I'm using the pwelch method in matlab to compute the power spectra for some wind speed measurements. So, far I have written the following code as an example:
t = 10800; % number of seconds in 3 hours
t = 1:t; % generate time vector
fs = 1; % sampling frequency (seconds)
A = 2; % amplitude
P = 1000; % period (seconds), the time it takes for the signal to repeat itself
f1 = 1/P; % number of cycles per second (i.e. how often the signal repeats itself every second).
y = A*sin(2*pi*f1*t); % signal
fh = figure(1);
set(fh,'color','white','Units', 'Inches', 'Position', [0,0,6,6],...
'PaperUnits', 'Inches', 'PaperSize', [6,6]);
[pxx, f] = pwelch(y,[],[],[],fs);
loglog(f,10*(pxx),'k','linewidth',1.2);
xlabel('log10(cycles per s)');
ylabel('Spectral Density (dB Hz^{-1})');
I cannot include the plot as I do not have enough reputation points
Does this make sense? I'm struggling with the idea of having noise at the right side of the plot. The signal which was decomposed was a sine wave with no noise, where does this noise come from? Does the fact that the values on the yaxis are negative suggest that those frequencies are negligible? Also, what would be the best way to write the units on the y axis if the wind speed is measured in m/s, can this be converted to something more meaningful for environmental scientists?
Your results are fine. dB can be confusing.
A linear plot will get a good view,
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sample time
L = 1000; % Length of signal
t = (0:L-1)*T; % Time vector
y = sin(2 * pi * 50 * t); % 50Hz signal
An fft approach,
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(y,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
subplot(1,2,1);
plot(f,2*abs(Y(1:NFFT/2+1)))
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
pwelch approach,
subplot(1,2,2);
[pxx, freq] = pwelch(y,[],[],[],Fs);
plot(freq,10*(pxx),'k','linewidth',1.2);
xlabel('Frequency (Hz)');
ylabel('Spectral Density (Hz^{-1})');
As you can see they both have peak at 50Hz.
Using loglog for both,
So "noise" is of 1e-6 and exists in fft as well, and can be ignored.
For your second question, I don't think the axis will change it will be frequency again. For Fs you should use the sampling frequency of wind speed, like if you have 10 samples of speed in one second your Fs is 10. Higher frequencies in your graph means more changes in wind speed and lower frequencies represent less changes for the speed.
Related
I have a simple problem but since I have not used MATLAB Fourier Transform tools I need some help. I have a plot obtained from n excel file. The plot is in time domain. Time range for the plot is 0 to 50 ps. And I have data for the y component of the plot every 0.5 fs. Basically the plot contains 100000 data printed every 0.5fs. Now I want to get the Fourier transform of this plot. What should i do? The following is a simple format for my excel file that includes the data I needed to have the time-domain plot.
0 116.0080214
0.0005 116.051128
0.001 116.0939229
0.0015 116.1362197
0.002 116.1776665
0.0025 116.2178118
0.003 116.256182
.
.
.
.
50.0 123.000
The first column is time in ps. Thank you so much in advance for you helps. Best, HRJ
I have adapted this page for the solution.
Fs = 100000/50; % Sampling frequency (in 1/ps)
T = 1/Fs; % Sample time (in ps)
L = 100000; % Length of signal
t = (0:L-1)*T; % Time vector; your first column should replace this
% Sum of a 50 1/ps sinusoid and a 120 1/ps sinusoid
% Your second column would replace y
x = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);
y = x + 2*randn(size(t)); % Sinusoids plus noise
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(y,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
close all
subplot(2,1,1)
% Plot your original signal
plot(Fs*t(1:100),y(1:100))
title('Signal Corrupted with Noise')
xlabel('time (fs)')
% Plot single-sided amplitude spectrum.
subplot(2,1,2)
plot(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (1/ps)')
ylabel('|Y(f)|')
Here is the code I use to plot a function in frequency domain in Matlab:
dt = 1/10000; % sampling rate
et = 0.1; % end of the interval
t = 0:dt:et; % sampling range
y = 2+sin(2.*pi.*50.*t)+18.*sin(2.*pi.*90.*t)+6.*sin(2.*pi.*180.*t); % sample the signal
subplot(2,1,1); % first of two plots
plot(t,y); grid on % plot with grid
xlabel('Time (s)'); % time expressed in seconds
ylabel('Amplitude'); % amplitude as function of time
Y = fft(y); % compute Fourier transform
n = size(y,2)/2; % 2nd half are complex conjugates
amp_spec = abs(Y)/n; % absolute value and normalize
subplot(2,1,2); % second of two plots
freq = (0:100)/(2*n*dt); % abscissa viewing window
stem(freq,amp_spec(1:101)); grid on % plot amplitude spectrum
xlabel('Frequency (Hz)'); % 1 Herz = number of cycles/second
ylabel('Amplitude'); % amplitude as function of frequency
The problem is, when I zoom in my graph I don't see peaks exactly on 50Hz, 90Hz and 180Hz.
What did I do wrong in my code?
The problem is that in order to get perfect spectra (peaks on 50,90,180 and 0 otherwise), your interval should be a multiplier of all the frequencies.
Explanation: consider y=sin(2.*pi.*t). Use your code to plot it with:
1) et = 1-dt;
2) et = 1;
In the first case, if you zoom in, you will see that peak is perfectly on 1 Hz. In the second case it is not (also very close).
Why? Because you are working with the finite number of points, and, consequently, finite number of frequencies. If 1 Hz is among this set of frequencies (1st case), you will get perfect peak at 1 Hz at zeros at all others frequencies.
In case 2 there is no 1 Hz frequency in your set, so you will get peak on the nearest frequencies (and also it will have finite width).
Ultimately, in your original code, there are no 50, 90, 180 Hz frequencies in your full set of frequencies.
I have an audio file , which represent the sound of a motor running at 2500rpm my aim is to get the period of this signal, so I can automaticlly tell what is the motor speed is. To do that I take a part of the signal and run get it autocorrelation , hopping that this willl tell the period of the singal! but I just don't get it :
here is a part of my code :
clear;
clc;
[x0,Fs] = audioread('_2500.wav');
x= x0(1:2000,1);
xc = xcorr(x);
clf;
subplot(3,1,1);
plot(x);
subplot(3,1,2);
plot(xc);
[peaks,locs] = findpeaks(xc);
hold on
subplot(3,1,3)
plot(xc(locs),'ro');
and here are the plot :
and how should I consider the sampling frequency, which is : 44100 ?
You can use the autocorrelation or FFT of the signal to find where is the maximum:
% Parameters
Fc = 1e1;
Fs = 1e3;
% Signal
t = 0:1/Fs:1;
x = sin(2*pi*Fc*t);
% FFT
Y = abs(fft(x));
[~,I] = max(Y(1:floor(end/2)));
% Frequency and period
F = I-1;
T = 1/F;
% Plot
figure;
subplot(2,1,1); plot(t,x);
subplot(2,1,2); plot(Y);
disp(['The frequency is ',mat2str(F),'Hz, and the period is ',mat2str(T),'sec.']);
This and this post are related.
To go from your auto-correlation function xc to an estimate of the fundamental frequency, do:
fs = 44100; % Unit: Hz
xc = xc((length(xc) - 1) / 2 + 1: end); % Get the half on the positive time axis.
[~, pidx] = findpeaks(xc);
period = (pidx(1) - 1) / fs;
F0 = 1 / period; % Estimated fundamental frequency.
Note that there are other potentially more robust fundamental frequency / pitch estimation algorithms. Doing a google scholar search on "fundamental frequency estimation" or "pitch estimation" will lead you to some good reviews.
you find all peaks using "findpeaks" funciton, now compute the difference between each peak
P=diff(locs)
your period can be :
max(P)
The peiod of 250hz sine at 22050 sample rate, is about 88, the Frequency of your signal is equivalent at the Period if you do (Fs/Period) == Frequency
If you Know the frequency of your signal you can find the period just do Fs/Frequency
The following Matlab scrip (taken from MATLAB help for fft) runs perfectly fine
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sample time
L = 1000; % Length of signal
t = (0:L-1)*T; % Time vector
% Sum of a 50 Hz sinusoid and a 120 Hz sinusoid
x = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);
y = x + 2*randn(size(t)); % Sinusoids plus noise
plot(Fs*t(1:50),y(1:50))
title('Signal Corrupted with Zero-Mean Random Noise')
xlabel('time (milliseconds)')
But I am unable to understand why we needed Fs*t in plot(). Why I am making it dimension less?
Your vector t is defined in terms of samples, i.e. t(10) is the value taken as the 10th sample.
If you want to plot the signal vs. time, you will have to multiply the sampling instance with the sampling time, i.e. time = FS*t .
If you don't scale, you eventually plot the signal vs. the sampling instances. Then, however, the label "time(ms)" is not correct.
I had created a 3 three different frequency signal and filter out the signal i don't want. But when i using ifft in matlab, it shows a wrong graph.How to transform my frequency domain spectrum back into my 3 second time domain graph? Below my code is as below:
clc
clear all
Fs = 8192;
T = 1/Fs;
%create tones with different frequency
t=0:T:1;
t2=1:T:2;
t3=2:T:3;
y1 = sin(2*pi*220*t);
y2 = sin(2*pi*300*t2);
y3 = sin(2*pi*440*t3);
at=y1+y2+y3;
figure;
plot(t,y1,t2,y2,t3,y3),title('Tones with noise');
[b,a]=butter(2,[2*290/Fs,2*350/Fs],'stop');
e=filter(b,a,at);
et=(ifft(abs(e)));
figure,
plot(et)
As it is now, et is in the frequency domain, because of the fft. You don't need to fft. just plot(e) and you'll get the time domain filtered waveform. Yo can check the filter performance in the freq. domain by fft though, just
plot(abs(fftshift(fft(fftshift(e)))));
xlim([4000 5000])
Edit:
Your code as it is written on the question has the following bug: at has exactly 1 second of info in it (or 8192 elements). If you plot(at) you'll see the sum of frequencies alright, but they all happen in the same time. This is how to fix it:
clear all
Fs = 8192; % or multiply by 3 if needed
T = 1/Fs;
%create tones with different frequency
t=0:T:3;
y1 = sin(2*pi*220*t).*(t<1);
y2 = sin(2*pi*300*t).*(t<2 & t>=1);
y3 = sin(2*pi*440*t).*(t>=2);
at=y1+y2+y3;
[b,a]=butter(2,[2*290/Fs,2*350/Fs],'stop');
e=filter(b,a,at);
figure,
plot(t,e)
dt=t(2)-t(1);
N=length(at);
df=1/(N*dt); % the frequency resolution (df=1/max_T)
if mod(N,2)==0
f_vector= df*((1:N)-1-N/2); % frequency vector for EVEN length vectors: f =[-f_max,-f_max+df,...,0,...,f_max-df]
else
f_vector= df*((1:N)-0.5-N/2); % frequency vector for ODD length vectors f =[-f_max,-f_max+fw,...,0,...,f_max]
end
freq_vec=f_vector;
fft_vec=fftshift(fft(e));
plot(freq_vec,abs(fft_vec))
xlim([0 1000])