Getting the Period in an audio file - matlab

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

Related

Unable to plot periodgram/pwelch/other PSD function for mock data in matlab

I am developing a 1v peak-to-peak sine wave with a 60hz frequency. I am doing this in order to ground truth certain methods of measuring sound. I am running into trouble in using and plotting various methods for developing a PSD. I have code below. Running this plots a fine sine wave and the RMS value of the data is .71 (good!). I expect to see a PSD plot with 1v energy at 60hz and no energy outside that band. I'm not getting that and am not sure why. For reference, I am a biologist - this is all Greek to me but I'm trying my best. Code:
Fs = 32000; % samples per second
dt = 1/Fs; % seconds per sample
StopTime = .5; % seconds
t = (0:dt:StopTime-dt)'; % seconds
%%Sine wave:
Fc = 60; % hertz
x = cos(2*pi*Fc*t);
% Plot the signal versus time:
figure;
plot(t,x);
xlabel('time (in seconds)');
title('Signal versus Time');
NFFT = 8192; %
NOVERLAP = round(0.75*NFFT);
w = hanning(NFFT);
[sensor_spectrum, freq] = pwelch(x,w,NOVERLAP,NFFT,fs);
figure;
plot (freq, sensor_spectrum );

Optical frequency comb time to frequency domain - MATLAB

I am trying to generate ultrashort pulses and then seeing the resulting frequency comb using a fourier transform, I have used the gaussian pulse and pulse train functions to try and do this but it is not coming out correctly - I am hoping to be able to change the variables at the top to see the changes quickly
If here is a solution or any good resources that could help me I would appreciate it alot... Thanks
Code is here:
fs = 1e17 ; % sample rate
frep = 7.5e9; % repition rate
f_sig = 1.93e15; %frequency of signal
tc = gauspuls('cutoff',f_sig,100,[],-80);
t = -tc*200:1/fs:tc*200;
[x1,x2,x3] = gauspuls(t,f_sig,0.5);
figure(1);
plot(t,x1,t,x3)
xlabel('Time (s)')
ylabel('Waveform')
ts = 0:1/fs/2:tc*50000000 ;
d = 0:1/frep:tc*50000000 ; %delay
y = pulstran(ts,d,x,fs);
figure(2);
plot(ts,y)
%Frequency Comb FFT
fsamp = fs;
L= length(t); %signal length
NFFT = 2^nextpow2(L);
FFT = abs(fftshift(fft(x3,NFFT))/NFFT); %FFT with FFTshift for both negative & positive frequencies
f = fsamp*(-NFFT/2:(NFFT/2-1))/NFFT; %Frequency Vector
figure(3)
plot(f/1e9,10*log10(FFT/1e-3));
title('Magnitude of FFT');
xlabel('Frequency (GHz)');
ylabel('Magnitude |X(f)|');
%xlim([-100 100])

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.

Fourier transform and LTI filter and frequency response in Matlab

I'm new to Matlab for LTI signal processing and wondering if anyone can help with something that I'm sure is meant to be basic. I've spent hours and hours researching and obtaining background information and still cannot obtain a clear path to tackle these problems. So far, from scratch, I have generated a signal required and managed to use the fft function to produce the signal's DFT:
function x = fourier_rikki(A,t,O)
Fs = 1000;
t = 0:(1/Fs):1;
A = [0.5,0,0.5];
N = (length(A) - 1)/2;
x = zeros(size(t));
f1 = 85;
O1 = 2*pi*f1;
for k = 1:length(A)
x1 = x + A(k)*exp(1i*O1*t*(k-N-1));
end
f2 = 150;
O2 = 2*pi*f2;
for k = 1:length(A);
x2 = x + A(k)*exp(1i*O2*t*(k-N-1));
end
f3 = 330;
O3 = 2*pi*f3;
for k = 1:length(A);
x3 = x + A(k)*exp(1i*O3*t*(k-N-1));
end
signal = x1 + x2 + x3;
figure(1);
subplot(3,1,1);
plot(t, signal);
title('Signal x(t) in the Time Domain');
xlabel('Time (Seconds)');
ylabel('x(t)');
X = fft(signal); %DFT of the signal
subplot(3,1,2);
plot(t, X);
title('Power Spectrum of Discrete Fourier Transform of x(t)');
xlabel('Time (Seconds)');
ylabel('Power');
f = linspace(0, 1000, length(X)); %?
subplot(3,1,3);
plot(f, abs(X)); %Only want the positive values
title('Spectral Frequency');
xlabel('Frequency (Hz)'); ylabel('Power');
end
At this stage, I'm assuming this is correct for:
"Generate a signal with frequencies 85,150,330Hz using a sampling frequency of 1000Hz - plot 1seconds worth of the signal and its Discrete Fourier Transform."
The next step is to "Find the frequency response of an LTI system that filters out the higher and lower frequencies using the Fourier Transform". I'm stuck trying to create an LTI system that does that! I have to be left with the 150Hz signal, and I'm guessing I perform the filtering on the FFT, perhaps using conv.
My course is not a programming course - we are not assessed on our programming skills and I have minimal Matlab experience - basically we have been left to our own devices to struggle through, so any help would be greatly appreciated! I am sifting through tonnes of different examples and searching Matlab functions using 'help' etc, but since each one is different and does not have a break down of the variables used, explaining why certain parameters/values are chosen etc. it is just adding to the confusion.
Among many (many) others I have looked at:
http://www.ee.columbia.edu/~ronw/adst-spring2010/lectures/matlab/lecture1.html
http://gribblelab.org/scicomp/09_Signals_and_sampling.html section 10.4 especially.
As well as Matlab Geeks examples and Mathworks Matlab function explanations.
I guess the worst that can happen is that nobody answers and I continue burning my eyeballs out until I manage to come up with something :) Thanks in advance.
I found this bandpass filter code as a Mathworks example, which is exactly what needs to be applied to my fft signal, but I don't understand the attenuation values Ast or the amount of ripple Ap.
n = 0:159;
x = cos(pi/8*n)+cos(pi/2*n)+sin(3*pi/4*n);
d = fdesign.bandpass('Fst1,Fp1,Fp2,Fst2,Ast1,Ap,Ast2',1/4,3/8,5/8,6/8,60,1,60);
Hd = design(d,'equiripple');
y = filter(Hd,x);
freq = 0:(2*pi)/length(x):pi;
xdft = fft(x);
ydft = fft(y);
plot(freq,abs(xdft(1:length(x)/2+1)));
hold on;
plot(freq,abs(ydft(1:length(x)/2+1)),'r','linewidth',2);
legend('Original Signal','Bandpass Signal');
Here is something you can use as a reference. I think I got the gist of what you were trying to do. Let me know if you have any questions.
clear all
close all
Fs = 1000;
t = 0:(1/Fs):1;
N = length(t);
% 85, 150, and 330 Hz converted to radian frequency
w1 = 2*pi*85;
w2 = 2*pi*150;
w3 = 2*pi*330;
% amplitudes
a1 = 1;
a2 = 1.5;
a3 = .75;
% construct time-domain signals
x1 = a1*cos(w1*t);
x2 = a2*cos(w2*t);
x3 = a3*cos(w3*t);
% superposition of 85, 150, and 330 Hz component signals
x = x1 + x2 + x3;
figure
plot(t(1:100), x(1:100));
title('unfiltered time-domain signal, amplitude vs. time');
ylabel('amplitude');
xlabel('time (seconds)');
% compute discrete Fourier transform of time-domain signal
X = fft(x);
Xmag = 20*log10(abs(X)); % magnitude spectrum
Xphase = 180*unwrap(angle(X))./pi; % phase spectrum (degrees)
w = 2*pi*(0:N-1)./N; % normalized radian frequency
f = w./(2*pi)*Fs; % radian frequency to Hz
k = 1:N; % bin indices
% plot magnitude spectrum
figure
plot(f, Xmag)
title('frequency-domain signal, magnitude vs. frequency');
xlabel('frequency (Hz)');
ylabel('magnitude (dB)');
% frequency vector of the filter. attenuates undesired frequency components
% and keeps desired components.
H = 1e-3*ones(1, length(k));
H(97:223) = 1;
H((end-223):(end-97)) = 1;
% plot magnitude spectrum of signal and filter
figure
plot(k, Xmag)
hold on
plot(k, 20*log10(H), 'r')
title('frequency-domain signal (blue) and filter (red), magnitude vs. bin index');
xlabel('bin index');
ylabel('magnitude (dB)');
% filtering in frequency domain is just multiplication
Y = X.*H;
% plot magnitude spectrum of filtered signal
figure
plot(f, 20*log10(abs(Y)))
title('filtered frequency-domain signal, magnitude vs. frequency');
xlabel('frequency (Hz)');
ylabel('magnitude (dB)');
% use inverse discrete Fourier transform to obtain the filtered time-domain
% signal. This signal is complex due to imperfect symmetry in the
% frequency-domain, however the imaginary components are nearly zero.
y = ifft(Y);
% plot overlay of filtered signal and desired signal
figure
plot(t(1:100), x(1:100), 'r')
hold on
plot(t(1:100), x2(1:100), 'linewidth', 2)
plot(t(1:100), real(y(1:100)), 'g')
title('input signal (red), desired signal (blue), signal extracted via filtering (green)');
ylabel('amplitude');
xlabel('time (seconds)');
Here is the end result...

Low pass filtering not working as expected

The following Matlab script is for filtering a signal consisting of a 50 Hz and 120 Hz sine. I am calculating the frequnecy in rad/s as Fp= (2*PI * 30)/1000=0.184.
I have kept fp=0.184 and fst=0.185, as I want to filter out both 50 hz and 120 Hz.
But when I am plotting the FFT of the output of the filter, what I am getting is a sine at 50 Hz. Why this 50Hz sine is coming even after filtering?
Ideally there should not be any peak in the plot.
Before filtering
after filtering
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sample time
L = 1000; % Length of signal
t =(0:L-1)*T; % Time vector
x = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t); % Sum of a 50 Hz sinusoid and a 120 Hz sinusoid %
y = x + 2*randn(size(t)); % Sinusoids plus noise
y = x ;
plot(Fs*t(1:50),y(1:50));title('Signal');xlabel('time (milliseconds)')
%pause;
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)|')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Now let us see Low Pass Filtering of this signal
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Fp= (2*pi * 30)/1000; %=0.184 %only frequncies less than 30Hz will be passed
d=fdesign.lowpass('Fp,Fst,Ap,Ast',0.184,0.185,2,60);
designmethods(d);
Hd = design(d,'equiripple'); fvtool(Hd);
Filterd_Output = filter(Hd,y);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Filtered_Freq = fft(Filterd_Output,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
% Plot single-sided amplitude spectrum.
plot(f,2*abs(Filtered_Freq(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of Low Pass Filtered_Output')
xlabel('Frequency (Hz)');ylabel('|Filtered_Freq_Amplitude|')
Update
As suggested I compared the original spectrum with the filterd one. This explains me a lot. But is there any way so that I can reduce this spike at 50 Hz further?
You incorrectly specify the normalized frequencies for the filter. Matlab assumes the frequency to be in [0, 1], not in [0, pi].
Replace
d=fdesign.lowpass('Fp,Fst,Ap,Ast',0.184,0.185,2,60);
with
d=fdesign.lowpass('Fp,Fst,Ap,Ast', 2*30/Fs, 2*35/Fs,2,60);
or alternatively
d=fdesign.lowpass('Fp,Fst,Ap,Ast', 30, 35,2,60, Fs);
and it should work as expected.