Matlab: FFT and FRF gives peaks at different frequencies? - matlab

I'm trying to make a fft from a transient time measurement but it seems that peaks are located at different locations than the measured FRF? The program (PULSE) I'm using have given me an averaged FRF and the transient signal is the last measurement of this series.
The fft of the transient acceleration signal is made by the following code:
% loading data:
[DataST, InfoST, errmsgST]=readuff('.\steel_tight_bolt_acc_center.uff');
dt=1.52588e-05; % sampling time
Fs=1/dt/2.56; % sampling frequency
NFFT = 2^nextpow2(length(DataST{1,5}.x)); % Next power of 2 from length signal
f = Fs*linspace(0,1,NFFT/2+1); % frequency
figure
subplot(2,1,1)
plot(DataST{1,7}.x,abs(DataST{1,7}.measData)) % FRF data from PULSE
title(DataST{1,7}.d1)
subplot(2,1,2)
L=length(DataST{1,5}.x); % length of signal
a=DataST{1,5}.measData; % Transient data measured [m/s^2]
A=2*abs(fft(a/L)); % calculating the fft
plot(f,A(1:(length(A))/2+1))
ylabel('2*|fft(Y)/N|')
title('FFT')
But by the resulting plot it seems that the peaks are located at different locations?
Can anyone explain what I'm doing wrong? Thanks!

Related

Matlab fftshift not working correctly

I am trying to plot the frequency spectrum of a sinewave with frequency 77.5 kHz and amplitude 2. Only the zero-point is not correct, it is shifted to the left.
My code:
f1=77.5e3; % frequency of the sinewave
a1=2; % amplitude of the sinewave
Fs = 1.55e6; % sampling frequency
dt=1/Fs; % step size
maxtime = 5*(1/f1);
t=0:dt:maxtime; % time interval in which we want to plot
x=a1*sin(2*pi*f1*t); % the values for the sinewave
N=length(t); % this is how many samples we have in the time-domain
X=fft(x)/N;
X=fftshift(X);
f=[-N/2:1:N/2-1]*Fs/N; % creates a frequency axis
figure(1)
plot(f,abs(X))
title('Magnitude Spectrum of x(t)')
xlabel('Frequency [Hz]')
ylabel('|X(f)|')
When I run this code I get an incorrect frequency spectrum. Can anyone help me out?
Edit: the figure I get when running this code:
Besides the incorrect zero-point I also get an incorrect frequency when I count it out myself from the plot. I'm just not sure how I should plot such a sinewave with frequency 77.5kHz, amplitude 2 and sampling frequency 1.55 MHz
Your code is correct as it is. But your signal, once made periodic, is not just a sine wave (there is a discontinuity, because the 1st and last samples of x are the same).
You can try removing 1 sample at the end:
t=0:dt:maxtime; % time interval in which we want to plot
t = t(1:end-1);
Now the peak is at f1.

Mean amplitude value in EMG signal

I have an EMG-signal and would like to get the mean value of the amplitude in a defined frequency space. I tried making FFT, but i don't get a vector with amplitudes and frequencies. I am new to Matlab - please help.
Here is how you would get power (i.e., amplitude) and frequency from the fft function in Matlab:
fs = 1024; % sampling rate of signal
time = 1; % time in sec of simulated signal
xn = randn (fs*time,1); % creating random signal
nfft = time*fs; % size of window on which to perform FFT
Y = fft (xn, nfft);
% Convert value to obtain the power of the signal at
% each frequency
Pyy = Y .* conj(Y) / nfft;
% Create a frequency axis for ploting
fy = fs/nfft * (0:(nfft/2) -1);
plot (fy, Pyy(1:nfft/2))
ylabel ('power (AU)^2') % arbitrary units
xlabel ('frequency (Hz)')
xlim ([0 512])
However, keep in mind that EMG is not a stationary signal. When doing spectral analysis on EMG signals we are trying to approximate the true spectrum. This is why EMG is usually seperated into windows of data. FFT is performed on each of these windows and the averaged.
Rather than using the fft function, you might want to consider using the pwelch function in the Matlab Signal Processing Toolbox. It allows you to set the window size, amount of overlap of the windows, etc.
Alternatively you could use the very popular Neurospec Matlab toolbox writen by David Halliday. It has a PDF that describes all the functions and examples you can use. It has additional functionality (e.g., coherence), but you can ignore it if you like and simply extract the spectral data.

MATLAB script to determine the frequency that has the greatest power

I am doing the linear motion measurement with a moving audio source and a stationary observer. Described here: http://www.animations.physics.unsw.edu.au/labs/Doppler/doppler_lab.html
How to write a MATLAB script to do get the sample number of the frequency that has the greatest power in the audio file?
What you need is the Time-Frequency localization information. This can be obtained using Short-time Fourier transform. There are many other Time-Frequency analysis techniques, STFT being the simplest and hence a good starting point. Here is a simple code to help you understand the concept:
% Parameters
Fs = 44100; % Sample rate (44100 Hz)
t = 0:1/Fs:5; % Time instances
t1 = 5; % End time of signal, 5 secs
f0 = 440; % frequency swiped from 440 Hz
f1 = 880; % to 880 Hz
% Signal generation
audio = chirp(t,f0,t1,f1);
% wavplay(audio,Fs) % to play the audio
% Signal analysis
window = 2050; % Should be minimum twice the maximum frequency we want to analyze
noverlap = 1025; % 50% overlap
nfft = 44100;
[S,F,T,P] = spectrogram(audio,window,noverlap,nfft,Fs); % Spectrogram takes the STFT of the signal
% P matrix contains the power spectral density of each segment of the STFT
% Plotting results
imagesc(real(S)) % frequency-time Plot of the signal
ylim([0 1000])
xlabel('Time (secs)')
ylabel('Frequency (Hz)')
title('Time-Frequency plot of a Audio signal')
To get the sample number, you just need to find the time instance at which the frequency of your interest appears, and use sampling frequency to compute the sample number.
P is the power spectral density matrix. Along y-axis is the frequency, x-axis is time, and power contributed by each frequency at every instant is stored in this matrix. You need the element which has the highest value in the entire matrix. A code like below should work:
[maxElement, maxElementTimeIndex] = max(max(P, [], 1)); % max(P, [], 1) finds maximum power for each time instance, max(max(P,[],1)) finds maximum for the entire 2D matrix.
maxPoweredSampleInAudioSignal = (maxElementTimeIndex-1) * Fs; % This calculation is made within the limitations of STFT, so approximately here the maximum power for any frequency is present

Getting the peak frequency of a note in MATLAB

I am trying to get the peak frequency of a musical note by using the FFT function that exists in MATLAB. I just copy-pasted the code for FFT of a mathematical function and replaced the function with the audio file.
Fs = 44100; % 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
y = wavread('c-note2.wav');
plot(Fs*t(1:50),y(1:50))
xlabel('time (milliseconds)')
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);
% Plot single-sided amplitude spectrum.
plot(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
Here, instead of y=wavread('c-note2.wav'), we had something like y=0.15sin(5x)+0.32cos(50t)+rand(I) (To add noise to the signal).
Is what we are trying to do correct? Can we put a wavread instead of a mathematical signal?
From the graph obtained I want to get the peak frequency of the c-note and check whether it is matching with the actual frequency of a c-note, but I am getting absurd results.
The pitch of a musical note is very often different from the peak frequency returned by an FFT. Musical notes usually contain a ton of overtones, many often stronger than the pitch frequency, some possibly even slightly inharmonic in frequency. Search for pitch detection or estimation algorithms instead of just looking at the FFT spectrum.
Also, when using an FFT to look at the audio spectrum, the length of the FFT has to be longer than several periods of the lowest frequency of interest. Your FFT length appears to be much too short to resolve 50 Hz (20 mS period).

Frequency response using FFT in MATLAB

Here is the scenario: using a spectrum analyzer i have the input values and the output values. the number of samples is 32000 and the sampling rate is 2000 samples/sec, and the input is a sine wave of 50 hz, the input is current and the output is pressure in psi.
How do i calculate the frequency response from this data using MATLAB,
using the FFT function in MATLAB.
i was able to generate a sine wave, that gives out the the magnitude and phase angles, here is the code that i used:
%FFT Analysis to calculate the frequency response for the raw data
%The FFT allows you to efficiently estimate component frequencies in data from a discrete set of values sampled at a fixed rate
% Sampling frequency(Hz)
Fs = 2000;
% Time vector of 16 second
t = 0:1/Fs:16-1;
% Create a sine wave of 50 Hz.
x = sin(2*pi*t*50);
% Use next highest power of 2 greater than or equal to length(x) to calculate FFT.
nfft = pow2(nextpow2(length(x)))
% Take fft, padding with zeros so that length(fftx) is equal to nfft
fftx = fft(x,nfft);
% Calculate the number of unique points
NumUniquePts = ceil((nfft+1)/2);
% FFT is symmetric, throw away second half
fftx = fftx(1:NumUniquePts);
% Take the magnitude of fft of x and scale the fft so that it is not a function of the length of x
mx = abs(fftx)/length(x);
% Take the square of the magnitude of fft of x.
mx = mx.^2;
% Since we dropped half the FFT, we multiply mx by 2 to keep the same energy.
% The DC component and Nyquist component, if it exists, are unique and should not be multiplied by 2.
if rem(nfft, 2) % odd nfft excludes Nyquist point
mx(2:end) = mx(2:end)*2;
else
mx(2:end -1) = mx(2:end -1)*2;
end
% This is an evenly spaced frequency vector with NumUniquePts points.
f = (0:NumUniquePts-1)*Fs/nfft;
% Generate the plot, title and labels.
subplot(211),plot(f,mx);
title('Power Spectrum of a 50Hz Sine Wave');
xlabel('Frequency (Hz)');
ylabel('Power');
% returns the phase angles, in radians, for each element of complex array fftx
phase = unwrap(angle(fftx));
PHA = phase*180/pi;
subplot(212),plot(f,PHA),title('frequency response');
xlabel('Frequency (Hz)')
ylabel('Phase (Degrees)')
grid on
i took the frequency response from the phase plot at 90 degree phase angle, is this the right way to calculate the frequency response?
how do i compare this response to the values that is obtained from the analyzer? this is a cross check to see if the analyzer logic makes sense or not.
Looks OK at first glance, but a couple of things you're missing:
you should apply a window function to the time domain data before the FFT, see e.g. http://en.wikipedia.org/wiki/Window_function for windowing in general and http://en.wikipedia.org/wiki/Hann_window for the most commonly used window function (Hann aka Hanning).
you probably want to plot log magnitude in dB rather than just raw magnitude
You should consider looking at the cpsd() function for calculating the Frequency response. The scaling and normalisation for various window functions is handled for you.
the Frequency reponse would then be
G = cpsd (output,input) / cpsd (input,input)
then take the angle() to obtain the phase difference between the input and the output.
Your code snippet does not mention what the input and output data sets are.