a multitone cosine wave with 4 freq. components shows only 3 peaks - matlab

I have four frequency components of non stationary signals defined as shown below in the code. When i tried to plot the frequency domain of these signals, i got a graph with only three frequency peaks as shown below in the image.?!
kindly let me know why ia m getting only three peaks while i have four freq. components.
COde:
% Time specifications:
Fs = 8000; % samples per second
dt = 1/Fs; % seconds per sample
StopTime = 2; % seconds
t = (0:dt:StopTime-dt); % seconds
t1 = (0:dt:.25);
t2 = (.25:dt:.50);
t3 = (.5:dt:.75);
t4 = (.75:dt:1);
x1 = (10)*sin(2*pi*10*t1);
x2 = (10)*sin(2*pi*20*t2) + x1;
x3 = (10)*sin(2*pi*50*t3) + x2;
x4 = (10)*sin(2*pi*70*t4) + x3;
NFFT = 2 ^ nextpow2(length(t)); % Next power of 2 from length of y
Y = fft(x4, NFFT);
f = Fs / 2 * linspace(0, 1, NFFT/2 + 1);
figure;
plot(f(1:200), 2 * abs( Y( 1:200) ) );
% Plot the signal versus time:
figure;
xlabel('time (in seconds)');
ylabel('Amplitude');
title('non-stationary Signal versus Time');
hold on
plot(t1,x1,'r');
plot(t2,x2,'g');
plot(t3,x3,'b');
plot(t4,x4,'black');
legend('x1 = (10)*sin(2*pi*15*t1) + (10)*sin(2*pi*8*t1)', 'x2 = (10)*sin(2*pi*25*t2)
+
x1', 'x3 = (10)*sin(2*pi*50*t3) + x2', 'x4 = (10)*sin(2*pi*75*t4) + x3', ...
'Location', 'SouthWest');
IMage::

You've plotted the fft for x3, which is the sum of the first three signals only. I think you meant to plot this for x4, which includes the fourth signal.

Related

Signal analysis

How to rotate the following signal around the x-axis using MATLAB.Let's say y is located in the plane xy. I want to move it to yz plane. Thank you
duration = 3; % seconds
samplingRate = 8192; % per second
samplingInterval = 1 / samplingRate;
t = 1:samplingInterval:duration;
y1 = cos(2*pi*300*t); % signal
y2 = cos(2*pi*5*t); % modulating signal (frequency = 5 Hz, adjust as desired)
y2 = rescale(y2,0.25,1); % modulation amplitude min/max factor
y = y1 .* y2; % create amplitude-modulated signal
% plot about 1 second of the signal (to show amplitude modulation)
plot(y(1:9000))
set(gca,'ylim', [-1.2, 1.2]);

implementing a filter from its frequency response in MATLAB

I have been trying to implement this filter on MATLAB and I only know its frequency response which is: HW= ( (3*c*1i*(J0))./(2*rfg*W) ) + (( (3*2*rfg*(W.*J1))-(3*3*c*1i*J1) ) ./ (2*alambdarfg*W.^2) ) where J0 and J1 are spherical Bessel functions of order 0 and 1 respectively.
How can I implement it in time domain using its frequency response?
a = 0.1; %radius of a spherical zone in m
%Data
c = 344; %speed of sound
rf = 3; %location of primary sound source
phi_f = degtorad(0); % "
rg = 1; %location of secondary sound source
phi_g = degtorad(45); % "
rfg = 1/((1/rg)-(1/rf));
lambda = - (2/c) * sin( (phi_f - phi_g)/2 );
F=0:.1:10000; %Frequency in Hertz
W = 2*pi*F; %Angular frequency vector (rad/sec)
%Bessel Functions
J0 = sphbes(0, a*lambda*W);
J1 = sphbes(1, a*lambda*W);
%Filter
HW= ( (3*c*1i*(J0))./(2*rfg*W) ) + (( (3*2*rfg*(W.*J1))-(3*3*c*1i*J1) ) ./ (2*a*lambda*rfg*W.^2) );
Thanks.
Is this what you are looking for?
a = 0.1; %radius of a spherical zone in m
%Data
c = 344; %speed of sound
rf = 3; %location of primary sound source
phi_f = degtorad(0); % "
rg = 1; %location of secondary sound source
phi_g = degtorad(45); % "
rfg = 1/((1/rg)-(1/rf));
lambda = - (2/c) * sin( (phi_f - phi_g)/2 );
Fs = 20000; % Sampling frequency (largest frequency in the frequency domain)
dt = 1/Fs; % Sampling time step (period)
N = 200000; % Number of points in the signal
t = (0:N-1)*dt; % Time vector
df = 1/(N*dt); % Frequency step
f = 0:df:(Fs/2); % Frequency vector in Hz
W = 2*pi*f; %Angular frequency vector (rad/sec)
%Bessel Functions
J0 = sphbes(0, a*lambda*W);
J1 = sphbes(1, a*lambda*W);
% Filter
HW = ( (3*c*1i*(J0))./(2*rfg*W) ) + (( (3*2*rfg*(W.*J1))-(3*3*c*1i*J1) ) ./ (2*a*lambda*rfg*W.^2) );
HW(1) = HW(2); % the value is NaN at f = 0
% visualising
figure(1);
cla(gca);
hold on;
plot(f, real(HW));
plot(f, imag(HW));
plot(f, abs(HW));
hold off;
xlabel('Frequency (Hz)');
ylabel('Amplitude');
legend({'Real', 'Imaginary', 'Absolute'});
box on;
% Convert from single sided to two sided
P1 = HW;
P1_flipped = fliplr(P1);
P2 = [P1(1:end-1) P1_flipped(1:end-1)];
P2 = P2/2;
% do the inverse fft
time_domain = ifft(P2);
% visualising
figure(2);
cla(gca);
hold on;
plot(t*1000, real(time_domain));
plot(t*1000, imag(time_domain));
plot(t*1000, abs(time_domain));
hold off;
xlabel('time (msec)');
ylabel('Amplitude');
legend({'Real', 'Imaginary', 'Absolute'});
box on;
xlim([0 10]);
ylim([-18*10^(-5) 18*10^(-5)]);

Finding the phase of each harmonics using fft

I use Matlab.
I have a sinusoidal signal :
X (amp:220/ Freq:50)
to which I add 3 harmonics :
x1 => (h2) amp:30 / Freq:100 / phase:30°
x2 => (h4) amp:10 / Freq:200 / phase:50°
x3 => (h6) amp:05 / Freq:300 / phase:90°
I sum all the signals together (like X containing 3 harmonics), the resulting signal is called : Xt
Here is the code :
%% Original signal
X = 220.*sin(2 .* pi .* 50 .* t);
%% Harmonics
x1 = 30.*sin(2 .* pi .* 100 .* t + 30);
x2 = 10.*sin(2 .* pi .* 200 .* t + 50);
x3 = 05.*sin(2 .* pi .* 300 .* t + 90);
%% adding the harmonics
Xt = X + x1 + x2 + x3;
What I want to do is : find the 3 harmonics signal (their amplitude, frequency and phase) starting for the summed signal Xt and knowing the fundamental signal X (amplitude and frequency) !
So far, I was able using fft, to retrieve the frequencies and the amplitudes of the harmonics, the problem now is finding the phases of the harmonics (in our case : 30°, 50° and 90°).
The FFT returns you an array consisting of complex numbers. To define phases of the frequency components you need to use angle() function for complex numbers. Don't forget: the phase of your harmonics has to be given in radians.
Here is the code:
Fs = 1000; % Sampling frequency
t=0 : 1/Fs : 1-1/Fs; %time
X = 220*sin(2 * pi * 50 * t);
x1 = 30*sin(2*pi*100*t + 30*(pi/180));
x2 = 10*sin(2*pi*200*t + 50*(pi/180));
x3 = 05*sin(2*pi*300*t + 90*(pi/180));
%% adding the harmonics
Xt = X + x1 + x2 + x3;
%Transformation
Y=fft(Xt); %FFT
df=Fs/length(Y); %frequency resolution
f=(0:1:length(Y)/2)*df; %frequency axis
subplot(2,1,1);
M=abs(Y)/length(Xt)*2; %amplitude spectrum
stem(f, M(1:length(f)), 'LineWidth', 0.5);
xlim([0 350]);
grid on;
xlabel('Frequency (Hz)')
ylabel('Magnitude');
subplot(2,1,2);
P=angle(Y)*180/pi; %phase spectrum (in deg.)
stem(f, P(1:length(f)), 'LineWidth', 0.5);
xlim([0 350]);
grid on;
xlabel('Frequency (Hz)');
ylabel('Phase (degree)');
It will result in such a mess (but you can see your amplitudes very well):
You can see a lot of phase components on the second plot. But if you eliminate all the frequencies which correspond to zero amplitudes, you will see your phases.
Here we are:
Y=fft(Xt); %FFT
df=Fs/length(Y); %frequency resolution
f=(0:1:length(Y)/2)*df; %frequency axis
subplot(2,1,1);
M=abs(Y)/length(Xt)*2; %amplitude spectrum
M_rounded = int16(M(1:size(f, 2))); %Limit the frequency range
ind = find(M_rounded ~= 0);
stem(f(ind), M(ind), 'LineWidth', 0.5);
xlim([0 350]);
grid on;
xlabel('Frequency (Hz)')
ylabel('Magnitude');
subplot(2,1,2);
P=angle(Y)*180/pi; %phase spectrum (in deg.)
stem(f(ind), P(ind), 'LineWidth', 0.5);
xlim([0 350]);
ylim([-100 100]);
grid on;
xlabel('Frequency (Hz)');
ylabel('Phase (degree)');
Now you can see the phases, but all of them are shifted to 90 degrees. Why? Because the FFT works with cos() instead of sin(), so:
X = 220*sin(2*pi*50*t + 0*(pi/180)) = 220*cos(2*pi*50*t - 90*(pi/180));
UPDATE
What if the parameters of some signal components are not integer numbers?
Let's add a new component x4:
x4 = 62.75*cos(2*pi*77.77*t + 57.62*(pi/180));
Using the provided code you will get the following plot:
This is not really what we expected to get, isn't it? The problem is in the resolution of the frequency samples. The code approximates the signal with harmonics, which frequencies are sampled with 1 Hz. It is obviously not enough to work with frequencies like 77.77 Hz.
The frequency resolution is equal to the inversed value of the signal's time. In our previous example the signal's length was 1 second, that's why the frequency sampling was 1/1s=1Hz. So in order to increase the resolution, you need to expand the time window of the processed signal. To do so just correct the definition of the vaiable t:
frq_res = 0.01; %desired frequency resolution
t=0 : 1/Fs : 1/frq_res-1/Fs; %time
It will result in the following spectra:
UPDATE 2
It does not matter, which frequency range has to be analyzed. The signal components can be from a very high range, what is shown in the next example. Suppose the signal looks like this:
f=20e4; % 200 KHz
Xt = sin(2*pi*(f-55)*t + pi/7) + sin(2*pi*(f-200)*t-pi/7);
Here is the resulting plot:
The phases are shifted to -90 degrees, what was explained earlier.
Here is the code:
Fs = 300e4; % Sampling frequency
frq_res = 0.1; %desired frequency resolution
t=0 : 1/Fs : 1/frq_res-1/Fs; %time
f=20e4;
Xt = sin(2*pi*(f-55)*t + pi/7) + sin(2*pi*(f-200)*t-pi/7);
Y=fft(Xt); %FFT
df=Fs/length(Y); %frequency resolution
f=(0:1:length(Y)/2)*df; %frequency axis
subplot(2,1,1);
M=abs(Y)/length(Xt)*2; %amplitude spectrum
M_rounded = int16(M(1:size(f, 2))); %Limit the frequency range
ind = find(M_rounded ~= 0);
stem(f(ind), M(ind), 'LineWidth', 0.5);
xlim([20e4-300 20e4]);
grid on;
xlabel('Frequency (Hz)')
ylabel('Magnitude');
subplot(2,1,2);
P=angle(Y)*180/pi; %phase spectrum (in deg.)
stem(f(ind), P(ind), 'LineWidth', 0.5);
xlim([20e4-300 20e4]);
ylim([-180 180]);
grid on;
xlabel('Frequency (Hz)');
ylabel('Phase (degree)');
To start off we should note (as you correctly found out in comments) that Matlab uses radians for angles, so the harmonics should be:
%% Harmonics
x1 = 30.*sin(2 .* pi .* 100 .* t + 30*pi/180);
x2 = 10.*sin(2 .* pi .* 200 .* t + 50*pi/180);
x3 = 05.*sin(2 .* pi .* 300 .* t + 90*pi/180);
The simple case
The process of estimating the amplitude, frequency and phase of the frequency components will usually start off with taking the Fast Fourier Transform (FFT), and selecting the strongest frequency components:
% Compute the frequency spectrum
N = length(Xt);
Xf = fft(Xt);
Nmax = N/2 + 1;
Xf = Xf(1:Nmax);
% Locate the peaks
largest_peak = max(20*log10(abs(Xf)));
peak_floor = largest_peak - 100; % to reject peaks from spectral leakage and noise
[pks,idx] = findpeaks((max(peak_floor, 20*log10(abs(Xf))) - peak_floor)')
Now if the fundamental frequency and the frequency of the harmonics happens to be exact multiples of fs/N where fs is the sampling rate and N is the number of samples (in this case length(Xt)) then the tones will fall exactly on a bin, and the frequencies, amplitudes and phases of each component can be estimated fairly easily with:
Amp = 2*abs(Xf(idx))/N;
freq = (idx-1)*fs/N;
phase = angle(Xf(idx));
phase = phase - phase(1); % set phase reference to that of the fundamental
The usual and more complicated reality
If on the other hand the frequency components are not exact multiples of fs/N, (or at least are not known to be exact multiples of fs/N, you are after all trying to estimate the frequency of those components) then things get more complicated. Note that this can have a particularly significant effect on the phase estimate.
We start off by recalling that a pure complex tone (exp(2*pi*j*n*f/fs)) of finite length N has a Discrete Fourier Transform (DFT) given by:
One estimation approach could be to start by estimating the frequency. The amplitude and phase can be factored out by looking at the ratio of the magnitudes of two successive bins of Xf around the peak, mainly at indices idx(i) and idx(i)+1. Under the assumption that those two bins suffer little interference, then the ratio can be expressed as:
ratio = abs(Xf(idx(i)+1)/Xf(idx))
= abs(sin(pi*frac/N)/sin(pi*(frac-1)/N))
Where the frequency to be estimated is f = (idx(i)-1 + frac)*fs/N. The parameter frac can then be obtained with the Newton-Raphson method:
% Solve for "f" for which ratio = sin(pi*frac/N)/sin(pi*(frac-1)/N)
function f = fractional_frequency(ratio, N)
niter = 20;
K = (pi/N) * sin(pi/N);
f = 0;
for i=1:niter
a = sin(pi*f/N);
b = sin(pi*(f-1)/N);
y = ratio - a/b;
yp = K / (b^2);
f = max(-0.5, min(f - y/yp, 0.5));
end
end
Which we use to estimate the frequency with:
freq = zeros(1,length(idx));
for i=1:length(idx)
ratio = abs(Xf(idx(i)+1))/abs(Xf(idx(i)));
if (abs(Xf(idx(i)+1)) > abs(Xf(idx(i)-1)))
ratio = -ratio;
end
frac = fractional_frequency(ratio, N)
freq(i) = (idx(i)-1+frac)*fs/N;
end
Now that we have the tone frequency, we can obtain the amplitude and phase by fitting the DFT equation given above (where we also add a factor of 2 for the amplitude by since we are dealing with a real tone):
Amp(i) = 2 * abs(Xf(idx(i))) * abs(sin(pi*frac/N)/sin(pi*frac));
phase(i) = angle( Xf(idx(i)) .* (1-exp(2*pi*frac*j/N)) ./ (1-exp(2*pi*frac*j)) );
And putting it all together:
Amp = zeros(1,length(idx));
freq = zeros(1,length(idx));
phase = zeros(1,length(idx));
for i=1:length(idx)
ratio = abs(Xf(idx(i)+1))/abs(Xf(idx(i)));
if (abs(Xf(idx(i)+1)) > abs(Xf(idx(i)-1)))
ratio = -ratio;
end
frac = fractional_frequency(ratio, N)
freq(i) = (idx(i)-1+frac)*fs/N;
Amp(i) = 2 * abs(Xf(idx(i))) * abs(sin(pi*frac/N)/sin(pi*frac));
phase(i) = angle( Xf(idx(i)) .* (1-exp(2*pi*frac*j/N)) ./ (1-exp(2*pi*frac*j)) );
end
phase = phase - phase(1); % set phase reference to that of the fundamental

how to alter the range of values of a plot generated by spectrogram function

In the below posted image, I am trying to get TFR using STFT. In the code posted, I specified the paramerter T = 0:.001:1; and when I modify it to be, for an example, T = 0:.001:2; the values range on the horizontal axis of the plot changes, despite it is labelled Frequency.
Now, I want to change the ranges of values of the horizontal and the vertical axes on the shown plot. How can I do that?
NOTE: the code used to generate the shown plot is:
T = 0:.001:1;
spectrogram(x4,128,50,NFFT);
CODE:
% Time specifications:
Fs = 8000; % samples per second
dt = 1/Fs; % seconds per sample
StopTime = 1; % seconds
t = (0:dt:StopTime-dt); % seconds
t1 = (0:dt:.25);
t2 = (.25:dt:.50);
t3 = (.5:dt:.75);
t4 = (.75:dt:1);
%two freqs. = abs(f1 - f2), that's why, x1 is plotted with 2 freqs.
x1 = (10)*sin(2*pi*30*t1);
x2 = (10)*sin(2*pi*60*t2) + x1;
x3 = (10)*sin(2*pi*90*t3) + x2;
x4 = (10)*sin(2*pi*120*t4) + x3;
%x5 = (10) * sin(2*pi*5*t5);
%x6 = x1 + x2 + x3 + x4 + x5;
NFFT = 2 ^ nextpow2(length(t)); % Next power of 2 from length of y
Y = fft(x3, NFFT);
f = Fs / 2 * linspace(0, 1, NFFT/2 + 1);
figure;
plot(f(1:200), 2 * abs( Y( 1:200) ) );
T = 0:.001:1;
spectrogram(x4,10,9,31);
axis(get(gcf,'children'), [0, 1,0,100]);
% Plot the signal versus time:
figure;
xlabel('time (in seconds)');
ylabel('Amplitude');
title('non-stationary Signal versus Time');
hold on
plot(t1,x1,'r');
plot(t2,x2,'g');
plot(t3,x3,'b');
plot(t4,x4,'black');
%plot(t5,x5,'y');
%plot(t, x6,'black');
legend('x1 = (10)*sin(2*pi*15*t1) + (10)*sin(2*pi*8*t1)', 'x2 = (10)*sin(2*pi*25*t2) + x1',
'x3 = (10)*sin(2*pi*50*t3) + x2', 'x4 = (10)*sin(2*pi*75*t4) + x3', ...
'Location', 'SouthWest');
image
new Result_1
Idea: get the axis the was used to plot the spectrogram and set its properties accordingly. For example, supposing you'd want to restrict the x range to [0, 0.5] and y to [100, 200], then:
%'old code here'
%' . . . '
spectrogram(x4,128,50,NFFT);
%'new code here'
axis(get(gcf,'children'), [0, 0.5, 100, 200]);
Explanation: The added one-liner gets the child handle from the current figure gcf (wich is assumed to be created by spectrogram), then sets it's range to [xmin, xmax, ymin, ymax] via axis call.
Nota Bene: I assume that you just need to re-scale the axis, not re-compute the spectrogram for different data.
Also I assume the spectrogram doesn't share its figure with other axes.
Also, extending the axis range rather than restricting it might not give you the expected results (in a word: is ugly).

how to get fourier transform of a signal

In the below code I am trying to get the fourier transform of a stationary signal (x3). But at run time the plot i get is absolutely something wrong and does not show any frequencies of the signals x3.
kindly please guide me and help me to get the fourier transform correctly.
Code:
%% Time specifications:
Fs = 8000; % samples per second
dt = 1/Fs; % seconds per sample
StopTime = 1; % seconds
t = (0:dt:StopTime-dt); % seconds
x1 = (10)*cos(2*pi*3*(t));
x2 = x1 + (10)*cos(2*pi*5*(t));
x3 = x2 + (10)*cos(2*pi*10*(t));
%% here i try to Plot fourier transform of the signal x3:
NFFT = 2^nextpow2(StopTime); % Next power of 2 from length of y
Y = fft(y,NFFT)/StopTime;
f = Fs/2*linspace(0,1,NFFT/2+1);
figure;
plot(f,2*abs(Y(1:NFFT/2+1)));
%% Plot the signal versus time:
figure;
hold on;
plot(t,x1,'r');
plot(t,x2,'g');
plot(t,x3,'b');
Update_1
You can not see what you expected because the value of NFFT is 1 means when you write NFFT/2+1 as an index of Y it will not be an integer value so MATLAB warns you. You can calculate NFFT like this:
NFFT = 2^nextpow2(length(t))
instead of writing
NFFT = 2^nextpow2(StopTime)
Well, try this:
Fs = 8000; % samples per second
dt = 1/Fs; % seconds per sample
StopTime = 1; % seconds
t = (0 : dt : StopTime-dt); % seconds
x1 = 10 * cos(2*pi*3*t);
x2 = x1 + 10 * cos(2*pi*5*t);
x3 = x2 + 10 * cos(2*pi*10*t);
%% here i try to Plot fourier transform of the signal x3:
NFFT = 2 ^ nextpow2(length(t)); % Next power of 2 from length of y
Y = fft(x3, NFFT) / StopTime;
f = Fs / 2 * linspace(0, 1, NFFT/2 + 1);
figure;
plot(f, 2 * abs( Y( 1:length(f) ) ) ); % // Also try this: plot(f(f <= 200), 2 * abs( Y( 1:length(f(f <= 200)) ) ) )
%% Plot the signal versus time:
figure;
hold on;
plot(t, x1, 'r');
plot(t, x2, 'g');
plot(t, x3, 'b');
Plots:
EDIT:
1- Actually you don' t have to use nextpow() function. If you use it, fft() function works faster. Because, due to time efficiency, fft() works like that recursively divide the signal by 2 for each time. Then calculates discrete fourier transform for each part and gather them. This means that the FFT is most efficient when the signal vector length is a power of 2.
2- Dividing fft result by StopTime part doesn' t make any sense to me either. Dividing fft result by NFFT may be more convenient theoretically.