correct amplitude of pwelch fft - matlab

I have a simple sinus signal with some noise.
If I try a simple FFT algorithm I get the amplitude of the signal(23) and the freq(2).
If I try the pwelch from Matlab with hanning window I am getting the right freq but the amplitude is wrong. How can I obtain the real amplitude?
This is the code I am using for the pwelch:
time = 0:0.01:50;
frequency = 2;
amplitude = 23;
y = amplitude * sin (2 * pi * frequency * time);
y= y + 6 * randn(size(time));
y = y - mean(y);
N = length(y);
Fs = 100;
NFFT = 2^nextpow2(N);
M = 4396;
w = hanning(M);
[Pyy,Fy] = pwelch(y, w,[],M,Fs);
plot(Fy,Pyy);

IMHO, you cannot due to the spectral leakage. If you see the Hanning window that you are using, it is a low pass filter (when centred and normalised). It will reduce the power at the main frequencies and it will introduce power at other frequencies, i.e. smoothing. But, it is an aperiodic signal with infinite duration in the frequency domain, which cannot be computed.
figure;
plot(w);
title(['Hanning window with ', num2str(M), 'points']);
You can read more here.

Related

on the use and understanding of pwelch in matlab

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.

Find value of frequency form Sin wav

i have a this following equation of sine wav
Fs = 8000; % Sampling rate of signal
Fc = 3000; % Carrier frequency
t = [0:Fs-1]'/Fs; % Sampling times
dev = 50; % Frequency deviation in modulated signal
s1 = sin(2*pi*200*t)+2*sin(2*pi*f*t);
now i want to value of f for s1 equation how can we get this? thanks
You may want to look around SO for similar questions.
The FFT is the simplest route to a solution:
spec = abs(fft(s1));
Then search for the maxima in the spectrum using a detection threshold.
Example (here f=10):
f= 10;
s1 = sin(2*pi*200*t)+2*sin(2*pi*f*t);
thresh = 0.2;
f1=abs(fft(s1))/sum(abs(s1));
f= [0:length(f1)-1]/length(f1)*Fs;
f(f1(1:end/2)>0.2)
This is the result (the frequencies in the spectrum for peaks with amplitude greater than the threshold value):
ans =
10 200

Matlab Finding Damped Sine wave decay factor for a given frequency

how to find decay constant value of a damped sine wave for a given frequency in matlab?
t=0:1e-6:0.1;
f= 500000;
y=sin(2*pi*f*t).*exp(-d*t);
i want to solve above equation for "d"
You first need to find the envelope of your oscillating function (the function that amplitude-modulates your sine). This can be done e.g. by rectifying the signal and then low-pass-filtering, but I choose to do a quick and dirty running maximum. After you found the envelope, there are various ways to fit an exponential function. I again chose a quick&dirty trick to do a first order polyfit to the log of the envelope. The code below works for the simple example you gave, but is might not work if you have an offset, if you choose n wrong, etc. It also won't give the best possible result in case of a noisy measurement.
fsamp = 1e5;
tmax = 0.1;
t=0:1/fsamp:tmax;
f = 12e3; %should be smaller than fsamp/2!
tau = 0.0765;
y=sin(2 * pi * f * t) .* exp(-t / tau);
%calculate running maximum
n = 20; %number of points to take max over
nblocks = floor(length(t) / n);
trun = mean(reshape(t(1:n*nblocks), n, nblocks), 1); %n-point mean
envelope = max(reshape(y(1:n*nblocks), n, nblocks), [], 1); %n-point max
%quick and dirty exponential fit, not the proper way in case of noise
p = polyfit(trun, log(envelope), 1);
tau_fit = -1/p(1);
k_fit = exp(p(2));
plot(t, y, trun, envelope, 'or', t, k_fit * exp(-t / tau_fit), '-k')
title(sprintf('tau = %g', tau))
Note that with exponential decay, it is more common to define the time-constant tau = 1 / d.

How to fit a curve to a damped sine wave in matlab

I have some measurements done and It should be a damped sine wave but I can't find any information on how to make (if possible) a good damped sine wave with Matlab's curve fitting tool.
Here's what I get using a "Smoothing spline":
Image http://s21.postimg.org/yznumla1h/damped.png.
Edit 1:
Here's what I got using the "custom equation" option:
Edit 2:
I've uploaded the data to pastebin in csv format where the first column is the amplitude and the second is the time.
The damped sin function can be created using the following code:
f=f*2*pi;
t=0:.001:1;
y=A*sin(f*t + phi).*exp(-a*t);
plot(t,y);
axis([0 1 -2.2 2.2]);
Now you can use "cftool" from matlab and load your data then set the equation type to custom and enter the formula of the damped sin function. Here you can see what I found so far...
I think the distribution of the data makes it hard for the fitting tool to do a good fit. It may need more data or more distributed data. In addition, there are other tools and methods as well, for instance check this for now: docstoc.com/docs/74524947/Mathcad-Damped-sine-fit-mcd
For all these methods that actually trying to search and find a local optimum (for each fitting parameters), the most important thing is the initial condition. I believe if you choose a good initial condition (initial guess), the fitting tool works well.
Good Luck
I wouldn't use the curve fitting toolbox for this, I'd use a curve-fitting function, e.g. lsqcurvefit. Here is an example taken from something I did a while back:
% Define curve model functions
expsin = #(a, f, phi, tau, t)a * sin(omega * t + phi) .* exp(-tau * t);
lsqexpsin = #(p, t)expsin(p(1), p(2), p(3), p(4), t);
% Setup data params
a = 1; % gain
f = 10; % frequency
phi = pi/2; % phase angle
tau = 0.9252523;% time constant
fs = 100; % sample rate
N = fs; % length
SNR = 10; % signal to noise ratio
% Generate time vector
dt = 1/fs;
t = (0:N-1)*dt;
omega = 2 * pi * f; % angular freq
noiseGain = 10^(-SNR/20); % gain for given SNR
% Generate dummy data: decaying sinusoid plus noise
x = expsin(a, omega, phi, tau, t);
noise = noiseGain * rand(size(x));
noise = noise - mean(noise);
x = x + noise;
close all; figure; hold on;
plot(t, x, 'k-', 'LineWidth', 2);
% Count zero crossings to find frequency
zCross = find(x(1:end-1) .* x(2:end) < 0);
T = mean(diff(zCross) * dt) * 2;
fEstimate = 1 / T;
omegaEstimate = 2 * pi * fEstimate;
% Fit model to data
init = [0.5, omegaEstimate, 0, 0.5];
[newparams, err] = lsqcurvefit(lsqexpsin, init, t, x);
plot(t, lsqexpsin(newparams, t))
Here some data with known parameters is generated, and some random noise added; the data is plotted. The parameters [a, phi, tau] are estimated from the data and a curve with the estimated parameters plotted on top.

Need help re: FFT output scaling

I'm currently studying the following book: "Fourier Transform Spectroscopy Instrumentation Engineering", by Vidi Saptari. My question is related to the code below, based on the code from the book, Appendix C. The code below computes the interferogram of 3 waves with wavenumbers [cm-1] 5000, 10000 and 15000, respectively, and than performs an FFT to retrieve the information. The unscaled output has a magnitude of 1600, instead of 1.
clear;
% Sampling clock signal generation
samp_period_nm = 632.8 / 4; % sampling period in nm. 632.8 is the HeNe laser's wavelength
samp_period = 1 * samp_period_nm * 10^-7; % sampling period in cm.
scan_dist = 0.1; % mirror scan distance in cm.
no_elements = floor(scan_dist/samp_period);
x_samp = 0:samp_period:samp_period*no_elements; %Vector of clock signals in cm
xn_samp = x_samp .* (1 + rand(1, length(x_samp)));
v1 = 5000;
v2 = 10000;
v3 = 15000;
arg = 4 * pi * x_samp;
y = cos(arg*v1) + cos(arg*v2) + cos(arg*v3) ;
total_data = 2^18;
no_zero_fills=[total_data - length(y)];
zero_fills=zeros(1, no_zero_fills);
%triangular apodization
n_y = length(y);
points = 1:1:n_y;
tri = 1 - 1/(n_y) * points(1:n_y);
y = y.*tri; %dot product of interferogram with triangular apodization function
y = [y zero_fills]; %zero filling
% FFT operation
fft_y = fft(y);
% fft_y = fft_y / n_y;
% fft_y = fft_y * samp_period;
fft_y(1) = [];
n_fft=length(fft_y);
spec_y = abs(fft_y(1:n_fft/2)); %spectrum generation
nyquist = 1 / (samp_period * 4);
freq = (1:n_fft/2)/(n_fft/2)*nyquist; %frequency scale generation
figure();
plot(freq, spec_y); % plot of spectrum vs wave number
xlabel('Wavenumber [cm-1]');
ylabel('Intesity [V]');
By multiplying the result of the fft (fft_y) with dt = samp_period, as suggested here, the peak is as 0.025.
Following the same link's second solution, by dividing fft_y by n_y (the length of y), the magnitude is 0.25.
Clearly, I'm doing something wrong. Any help is appreciated.
Thanks,
The only thing you're doing wrong here is expecting the peaks in the spectrum to be 1. According to Parseval's theorem of DFT the energy of the time domain signal is equal to the energy of the frequency domain signal divided by the lenght of the sequence N. You can check this in your example:
td_energy = sum( abs(y).^2 )
fd_energy = sum( abs(fft_y).^2 )
td_energy - fd_energy / length(y) % won't be exactly zero because you deleted the zero frequency bin.
So the peaks in your spectrum don't represent the amplitudes of cosine waves in the time domain but their energy. Also note at this point that the energy is lower than you might expect as you padded a lot of zeros.
In practice, the average power of a certain frequency is often of greater interest. Consider the following code example
t = linspace(-4*pi, 4*pi, 2^16);
N = length(t); % DFT length
y = cos(t); % single cosine wave
y_pow = sum( abs(y).^2 ) / N; % is 0.5
fft_y = fft(y);
fft_y_pow = (sum( abs(fft_y).^2 ) / N) /N; % is 0.5
figure; plot(abs(fft_y)./N);
The power is obtained by averaging the energy by the length of the sequence N. If you divide the spectrum by N you obtain the average power per frequency. In the above example you recognize a single peak with height 0.5 that represents the single cos wave of amplitude 1 (and hence power 0.5).
Personally, I prefer scaling MATLAB's FFT output by 1/sqrt(N) and its IFFT output by sqrt(N). In this way, the energy of the time and frequency domain sequence are always equal.
if you want the same energy in the IFFT input and ouput you have to multiply
the IFFT output (time signal) by sqrt(N) where N is the size of the transform.
here's the code :
same thing for the FFT (divide output by sqrt(N));
hope it helps
Felix
N = 4096;
Freq = randn(N,1)+1j*randn(N,1);
Time = sqrt(N)*ifft(Freq,N);
FreqEn = sum(real(Freq).^2 + imag(Freq).^2);
TimeEn = sum(real(Time).^2 + imag(Time).^2);
TimeEn/Freq