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
Related
Here is my code for generating a triangular waveform in the time domain and for generating its corresponding fourier series/transform (I don't know whether its series or transform because matlab only has fourier transform function but since the signal is periodic, references say that the fourier counterpart must be called fourier series).
x = 0;
s = 50; % number of sinusoidal components
fs = 330; % hertz
dt = 1/fs; % differential time
t = [0:dt:4]; % seconds
const = 2 / (pi^2);
for k = 1:2:s,
x = x + (((-1)^((k - 1) / 2)) / (k^2)) * sin(4*pi*k*t);
end
x = const * x;
% amplitude = max(x) = 0.2477
% period = 0.5 seconds
f = linspace(-fs/2,fs/2,length(x));
xk = fftshift(fft(x));
figure;
subplot(3,1,1);
plot(t,x);
grid on;
xlabel('time(seconds)');
title('Time Domain');
subplot(3,1,2);
plot(f,abs(xk));
grid on;
xlabel('frequency(hertz)');
title('Magnitude Spectrum');
subplot(3,1,3);
plot(f,angle(xk));
grid on;
xlabel('frequency(hertz)');
title('Phase Spectrum');
And here is the generated plots for the time domain signal, magnitude spectrum, and phase spectrum.
link:
fs = 330hz
My problem is when I changed the sampling frequency (fs which is currently equal to 330 hz) to another value, the plots of the magnitude and phase spectra change.
Here is the plots of the magnitude and phase spectra when the sampling frequency is equal to 400 hz:
link:
fs = 400 hz
Can you explain why does this happen? And what can I do in order to get a constant plots for the magnitude and phase spectra given any sampling frequency?
I can't get your pictures to load over my proxy, but the spectrum of a FFT will be have a bigger "gap" in the middle at a higher sampling rate. A fundamental property of sampling is that it introduces copies of your original spectrum; you may have learned this if you studied the discrete-time Fourier transform. At a higher sampling rate, these copies are farther apart.
Additionally, your sampling points will be in different places at different sampling rates, so you may get different lobing behavior.
Incidentally, you are getting the discrete Fourier transform in Matlab -- you are giving it a finite sequence of discrete points, not a continuous, inifintely long signal.
If you want the plots to look the same, just make their x-axes match.
It because that the spectra by DFT/FFT are indeed the sampled and normalized version of the original analog spectra, therefore, with the sampling step changes, the sampling step in frequency domain also changes, thus the spectra lines that you see also change since the original spectra are not constant. Another factor may be the aliasing effects, since the analog spectra of triangular waveform are infinite in theory.
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!
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.
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).
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.