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.
Related
I'm having problems plotting the FFT of a wav file. I managed to plot the magnitude and phase spectrums of the signal, however I need to repeat this in range -fs/2:fs/2.
%read sound files
%'y' is the vector holding the original samples & 'fs' refers to the sampling frequency
[y,fs] = wavread('handel.wav');
ydft = fft(y); %fft to transform the original signal into frequency domain
n = length (y); %length of the original signal
% y has even length
ydft = ydft(1:length(y)/2+1);
% create a frequency vector
freq = 0:fs/length(y):fs/2;
shiftfreq = fftshift(freq);
%plot original signal in time domain;
figure;
plot ((1:n)/fs, y);
title('handel.wav in time domain');
xlabel ('second');
grid on;
% plot magnitude in frequency domain
figure;
plot(freq,abs(ydft));
title('handel.wav in frequency domain');
xlabel ('Hz');
ylabel('Magnitude');
grid on;
% plot phase in frequency domain
figure;
plot(freq,unwrap(angle(ydft)));
title ('handel.wav in frequency domain');
xlabel ('Hz');
ylabel ('Phase');
grid on;
What you are currently doing now is plotting the half spectrum, so from 0 <= f < fs/2 where fs is the sampling frequency of your signal, and so fs/2 is the Nyquist frequency. Take note that considering the half spectrum is only valid if the signal is real. This means that the negative spectra is symmetric to the positive spectra and so you don't really need to consider the negative spectra here.
However, you would like to plot the full spectrum of the magnitude and phase. Take note that when calculating the fft using MATLAB, it uses the Cooley-Tukey algorithm so when computing the N point FFT, half of result is for the frequencies from 0 Hz inclusive up to fs/2 Hz exclusive and the other half is for the frequencies from -fs/2 Hz inclusive up to 0 Hz exclusive.
As such, to plot the full spectrum, simply perform a fftshift on the full signal so that the right half and left half of the spectrum is swapped so that the 0 Hz frequency is located in the centre of the signal. Also, you must generate frequencies between -fs/2 to fs/2 to cover the full spectrum. Specifically, you need to generate N points linearly spaced between -fs/2 to fs/2. However, take note that the Nyquist frequency at fs/2 Hz is being excluded at the end, so you need to generate N+1 points between -fs/2 to fs/2 and remove the last point in order for the right step size between each frequency bin to be correct. The easiest way to generate this linear array of points is by using the linspace command where the start frequency is -fs/2, the ending frequency is fs/2 and you want N+1 points between this range and remove the last point:
freq = linspace(-fs/2, fs/2, n+1);
freq(end) = [];
As such, borrowing some parts of your code, this is what the modified code looks like to plot the full spectrum of the magnitude and phase:
%// Read in sound file
[y,fs] = wavread('handel.wav');
%// Take N-point FFT where N is the length of the signal
ydft = fft(y);
n = numel(y); %// Get N - length of signal
%// Create frequency vector - make sure you remove last point
freq = linspace(-fs/2, fs/2, n+1);
freq(end) = [];
%// Shift the spectrum
shiftSpectrum = fftshift(ydft);
%//plot original signal in time domain;
figure;
plot ((0:n-1)/fs, y); %// Note you should start from time = 0, not time = 1/fs
title('handel.wav in time domain');
xlabel ('second');
grid on;
%// plot magnitude in frequency domain
figure;
plot(freq,abs(shiftSpectrum));
title('handel.wav in frequency domain');
xlabel ('Hz');
ylabel('Magnitude');
grid on;
%// plot phase in frequency domain
figure;
plot(freq,unwrap(angle(shiftSpectrum)));
title('handel.wav in frequency domain');
xlabel('Hz');
ylabel('Phase');
grid on;
I don't have access to your handel.wav file, but I'll be using the one provided with MATLAB. You can load this in with load handel;. The sampling frequency is stored in a variable called Fs, so I had to do fs = Fs; before the code I wrote above could work. The sampling frequency for this particular file is 8192 Hz, and this is approximately a 9 second long file (numel(y) / fs = 8.9249 seconds). With that file, this is the magnitude and phase that I get:
For the discrete Fourier transform (DFT) as well as its fast implementations (FFTs), the frequencies are normalized with the sampling frequency fs, i.e., the original range -fs/2:fs/2 is changed to -pi:pi.
Besides, the DFT/FFT always starts with 0, and you can use fftshift() to shift the 0 frequency to the center. Therefore, after fftshift(), the range is -pi:pi, then, you can scale to -fs/2:fs/2.
look at the following Matlab function, it can calculate phase spectrum as well as amplitude spectrum with a perfect accuracy:
https://www.mathworks.com/matlabcentral/fileexchange/63965-amplitude-and-phase-spectra-of-a-signal--fourier-transform-
This program calculates amplitude and phase spectra of an input signal with acceptable accuracy especially in the calculation of phase spectrum.The code does three main jobs for calculation amplitude and phase spectra. First of all, it extends the input signal to infinity; because for calculation Fourier transform(FT) (fft function in Matlab), we consider our signal is periodic with an infinite wavelength, the code creates a super_signal by putting original signal next to itself until the length of super_signal is around 1000000 samples, why did I choose 1000000 samples? Actually, it is just based on try and error!! For most signals that I have tried, a supper signal with 1000000 samples has the best output.
Second, for calculating fft in Matlab you can choose different resolutions, the Mathwork document and help use NFFT=2^nextpow2(length(signal)), it definitely isn't enough for one that wants high accuracy output. Here, I choose the resolution of NFFT=100000 that works for most signals.
Third, the code filters result of FT by thresholding, it is very important step! For calculating phase spectrum, its result is very noisy because of floating rounding off error, it causes during calculation "arctan" even small rounding off error produces significant noise in the result of phase spectrum, for suppressing this kind of noise you can define a threshold value. It means if amplitude of specific frequency is less than predefined threshold value (you must define it) it put zero instead of it.
These three steps help to improve the result of amplitude and phase spectra significantly.
IF YOU USE THIS PROGRAM IN YOUR RESEARCH, PLEASE CITE THE FOLLOWING PAPER:
Afshin Aghayan, Priyank Jaiswal, and Hamid Reza Siahkoohi (2016). "Seismic denoising using the redundant lifting scheme." GEOPHYSICS, 81(3), V249-V260. https://doi.org/10.1190/geo2015-0601.1
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 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
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).