Normalize the amplitude of a sinewave of varying amplitude and frequency

85 views (last 30 days)
I have a series of sine waves of varying amplitude and frequency, and I need to normalize them to -1 to +1 in amplitude, but maintain the frequency and not induce a phase shift. The idea being that I need to take the arcsine of this signal, and then the slope of that arcsine to get a 0 to 360deg output sawtooth wave. Such that I can compare them to each other to determine static phase offset, and dynamic phase offset (latency). I'm struggling to get a clean normalization, and pretty sure I'm just not fully understanding the "normalize" function. I feel like this might be a fairly normal function, but just don't know where/what to search for. In my mind I think I need to determine each "cycle" by detecting zero crossings and the peaks and valleys, then determining the peak and vally for that cycle, then normalizing to -1 to +1, but repeat it.

Answers (3)

Image Analyst
Image Analyst on 3 Mar 2023
Edited: Image Analyst on 3 Mar 2023
If you have any more questions, then attach your data and code to read it in with the paperclip icon after you read this:
In the meantime try rescale
normalizedSignal = rescale(signal, -1, 1); % Global rescaling
This assumes the peaks are all about the same height. If you have a "warbling" or "chirp" signal where the peaks of the sine waves vary over time, then look at the envelope function and divide by that envelope.

Star Strider
Star Strider on 3 Mar 2023
I need to determine each "cycle" by detecting zero crossings and the peaks and valleys, then determining the peak and vally for that cycle, then normalizing to -1 to +1, but repeat it.
If you just want to normalise the amplitudes in every cycle, try this —
Fs = 1000;
L = 10;
t = linspace(0, L*Fs, L*Fs+1)/Fs;
s = sin(2*pi*t*0.75) .* cos(2*pi*t*0.05) * 1.5;
figure
plot(t, s)
grid
xlabel('t')
ylabel('s(t)')
title('Original Signal')
zix = find(diff(sign(s))); % Approximate Zero-Crissing Indices
Ls = numel(s);
for k = 1:numel(zix)-1
idxrng = max(1,zix(k)-1) : min(Ls,zix(k)+1);
xv(k) = interp1(s(idxrng),t(idxrng),0); % 'Exact' Zero-Crossings
end
dt = t(2)-t(1); % Sampling Interval
for k = 1:numel(xv)-1
xrng{k,:} = xv(k) : dt : xv(k+1);
ys{k,:} = interp1(t, s, xrng{k}); % Extract Signal Segment By Interpolating Independent Variable
mx = max(ys{k});
mn = min(ys{k});
yv{k,:} = ys{k}/(mx-mn); % Normalise Signal Segment
end
figure
hold on
for k = 1:size(xrng,1)
plot(xrng{k}, yv{k})
end
hold off
grid
xlabel('t')
ylabel('s(t)')
title('Cycle-Normalised Signal')
This breaks the signal into half-cycles and normalises each half-cycle.
.
.

A Wen
A Wen on 15 Nov 2023
A cleaner way to do this is with the Hilbert Transform with extracts the amplitude and phase.
Example code below, which normalizes the amplitude out, but maintains the phase information.
% Create a sample signal with varying amplitude
t = linspace(0, 1, 1000);
signal = sin(2 * pi * 5 * t) .* (1 + 0.5 * sin(2 * pi * 2 * t));
% Apply the Hilbert transform
analytic_signal = hilbert(signal);
% Calculate the envelope (instantaneous amplitude)
envelope = abs(analytic_signal);
% Normalize the amplitude
normalized_signal = signal ./ envelope;
% Plot the original signal, envelope, and normalized signal
figure;
plot(t, signal, 'LineWidth', 1.5, 'DisplayName', 'Original Signal');
hold on;
plot(t, envelope, 'LineWidth', 1.5, 'DisplayName', 'Envelope');
plot(t, normalized_signal, 'LineWidth', 1.5, 'DisplayName', 'Normalized Signal');
hold off;
legend('Location', 'Best');
xlabel('Time');
ylabel('Amplitude');
title('Envelope Detection in MATLAB');
grid on;

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!