MATLAB - Plot time-frequency graph of .wav file - matlab

I'm working on a project that involves looking at the changes in pitch/frequency over time with a wave file (I'm new to MATLAB, but not to programming). I'm able to see the time-amplitude graph and frequency-amplitude (after an FFT) graph, but how would I be able to isolate the frequency and show it at each point in time?
Code:
filename = '/Users/Username/Sample_1.wav'
[y, fs] = wavread(filename);
y = y(:,1);
dt = 1/fs;
t = 0:dt:(length(y)*dt)-dt;
plot(t,y); xlabel('Seconds'); ylabel('Amplitude');
transformed = fft(y);
mag = abs(transformed);
plot(mag);

If you have the Signal Processing Toolbox, then you may find the spectrogram function useful.
If you don't, then you can achieve the same effect manually by calculating FFTs of consecutive (possibly overlapped) windowed segments of your time-domain data, and then plotting the amplitudes.
This is essentially the short-time Fourier transform (STFT).

If you have the Signal Processing Toolbox, spectrogram is the way to go (as Oli Charlesworth mentioned).
If you don't have it, the MATLAB Central File exchange is always a good place to look for something that general.
http://www.mathworks.com/matlabcentral/fileexchange/1553-spectrogram-short-time-ft-log-magnitude
This seems to be a sensible and well working implementation of the spectrogram functionality.

Related

How to remove the noisy part of a heartbeat?

I have a large pulse oxymetery signal. Some part of that is noisy and will corrupt my data if I use it. Do you have any strategy to automatically remove the noisy part? (Since the data is very long and there are many channels, I can't really do it manually).
Please find the picture attached to have a feeling of the signal.
You can filter it but you need to know the spectral characteristics of the signal so you can extract it or the spectral characteristics of the noise so you can suppress it. Do you have a signal that doesn't have noise or do you know where in the spectrum your signal of interest lies?
This might be the problem identical to removing outliers from time series.
This problem can be solved by fitting the time series with a given model as shown in the this link. For example, try the following simulation codes.
xdata = (0:0.1:2*pi)';
y0 = sin(xdata); % pure data
gnoise = y0.*randn(size(y0)); % noise component
ydata = y0 + gnoise;
f = fittype('a*sin(b*x)');
fit1 = fit(xdata,ydata,f,'StartPoint',[1 1]);
plot(fit1,'r-',xdata,ydata,'k.',outliers,'m*')
xlim([0 2*pi])

Matlab not plotting the exact fourier signal

I'm trying to plot a simple signal in fourier domain using Matlab. It's not plotting the correct signal. Here is my code:
clc;
clear all;
close all;
x=1:0.001:10;
f1=sin(2*pi*10*x);
f2=sin(2*pi*15*x);
f3=sin(2*pi*30*x);
f=f1+f2+f3;
plot(2*pi*x,fft(f1));
figure
plot(x,fft(f1));
I've expected a peak at 10 since the frequency is 10. But it is giving a peak at some other point
Here are the two plot images:
This is the image for plot(x,fft(f1))
This is the image for plot(2*pi*x,fft(f1))
It is not showing the peak at 10.I even tried using abs(fft(f1)). No luck :/
Isn't it the correct way to plot signal in fourier domain?
The fft function assumes unit time step. In order to correct for non unit time step you need to define the frequency component based on the nyquist rate. The following code plots the magnitude of the fft with the correct frequency axis.
clc;
clear all;
close all;
x=1:0.001:10;
% ^ this is your sampling time step
f1=sin(2*pi*10*x);
f2=sin(2*pi*15*x);
f3=sin(2*pi*30*x);
% bounds of fourier transform based on sampling rate
Fs = 1/0.001;
ff = linspace(-Fs/2,Fs/2,numel(x));
F1 = fftshift(fft(f1)/numel(x));
F2 = fftshift(fft(f2)/numel(x));
F3 = fftshift(fft(f3)/numel(x));
figure();
plot(ff,abs(F1),'-r'); hold on;
plot(ff,abs(F2),'-b');
plot(ff,abs(F3),'-k');
Edit: To answer OPs question in the comment.
Speaking in normalized frequency units (assuming sampling rate of 1). The fft function returns the frequency response from 0 to 2*pi radians, but due to some signal processing properties and the way that discrete signals are interpreted when performing an FFT, the signal is actually periodic so the pi to 2*pi section is identical to the -pi to 0 section. To display the plot with the DC component (0 frequency) in the center we use fftshift which does a circular shift equal to 1/2 the length of the signal on the data returned by fft. Before you take the ifft make sure you use ifftshift to put it back in the right place.
Edit2: The normalization term (/numel(x)) is necessary to estimate the continuous time fourier transform using the discrete fourier transform. I don't remember the precise mathematical reason off the top of my head but the examples in the MATLAB documentation also imply the necessity of this normalization.
Edit 3: The original link that I had is down. I may come back to add a more detailed answer but in the mean time I definitely recommend that anyone interested in understanding the relationship between the fundamentals of the FS, FT, DTFT, and DFT watch Professor Oppenheim's hilariously old, but amazingly informative and straightforward lectures on MIT OpenCourseWare.

How to produce a log scale FFT with MatLab

It's my first time performing an FFT within MatLab by experimenting with some example code from the MathWorks website. I was wondering if it was possible to take the code I have and transform the x axis to a log-scale representation rather than linear. I understand most of the code, but it is the x axis line of code that I'm still not 100% sure exactly what it is doing apart from the +1 at the end of the line, which is that fact that MatLab's indexing structure doesn't start on 0.
My code so far is:
[y,fs] = wavread('Wav/800Hz_2sec.wav');
NFFT = 4096;
Y = fft(y,NFFT)/length(y);
f = fs/2*linspace(0,1,NFFT/2+1);
plot(f,2*abs(Y(1:NFFT/2+1))
frequency usually comes out in linear scale from Discrete Fourier Transform. if you want, you can make a new frequency vector in log scale and interpolate the results you already have
fnew=fs/2.*logspace(log10(fs/length(y)),0,npts);
Ynew= interp1(f,Y(1:NFFT/2+1),fnew);
where npts is the length of your new frequency vector. for just plotting
loglog(f,2*abs(Y(1:NFFT/2+1));
honestly IMO, the interpolation thing doesn't work very well because FFT of real signals produces strong peaks and troughs in spectra, so unless you smooth your spectrum first, the interpolated spectrum won't look as nice

Matlab: Finding dominant frequencies in a frame of audio data

I am pretty new to Matlab and I am trying to write a simple frequency based speech detection algorithm. The end goal is to run the script on a wav file, and have it output start/end times for each speech segment. If use the code:
fr = 128;
[ audio, fs, nbits ] = wavread(audioPath);
spectrogram(audio,fr,120,fr,fs,'yaxis')
I get a useful frequency intensity vs. time graph like this:
By looking at it, it is very easy to see when speech occurs. I could write an algorithm to automate the detection process by looking at each x-axis frame, figuring out which frequencies are dominant (have the highest intensity), testing the dominant frequencies to see if enough of them are above a certain intensity threshold (the difference between yellow and red on the graph), and then labeling that frame as either speech or non-speech. Once the frames are labeled, it would be simple to get start/end times for each speech segment.
My problem is that I don't know how to access that data. I can use the code:
[S,F,T,P] = spectrogram(audio,fr,120,fr,fs);
to get all the features of the spectrogram, but the results of that code don't make any sense to me. The bounds of the S,F,T,P arrays and matrices don't correlate to anything I see on the graph. I've looked through the help files and the API, but I get confused when they start throwing around algorithm names and acronyms - my DSP background is pretty limited.
How could I get an array of the frequency intensity values for each frame of this spectrogram analysis? I can figure the rest out from there, I just need to know how to get the appropriate data.
What you are trying to do is called speech activity detection. There are many approaches to this, the simplest might be a simple band pass filter, that passes frequencies where speech is strongest, this is between 1kHz and 8kHz. You could then compare total signal energy with bandpass limited and if majority of energy is in the speech band, classify frame as speech. That's one option, but there are others too.
To get frequencies at peaks you could use FFT to get spectrum and then use peakdetect.m. But this is a very naïve approach, as you will get a lot of peaks, belonging to harmonic frequencies of a base sine.
Theoretically you should use some sort of cepstrum (also known as spectrum of spectrum), which reduces harmonics' periodicity in spectrum to base frequency and then use that with peakdetect. Or, you could use existing tools, that do that, such as praat.
Be aware, that speech analysis is usually done on a frames of around 30ms, stepping in 10ms. You could further filter out false detection by ensuring formant is detected in N sequential frames.
Why don't you use fft with `fftshift:
%% Time specifications:
Fs = 100; % samples per second
dt = 1/Fs; % seconds per sample
StopTime = 1; % seconds
t = (0:dt:StopTime-dt)';
N = size(t,1);
%% Sine wave:
Fc = 12; % hertz
x = cos(2*pi*Fc*t);
%% Fourier Transform:
X = fftshift(fft(x));
%% Frequency specifications:
dF = Fs/N; % hertz
f = -Fs/2:dF:Fs/2-dF; % hertz
%% Plot the spectrum:
figure;
plot(f,abs(X)/N);
xlabel('Frequency (in hertz)');
title('Magnitude Response');
Why do you want to use complex stuff?
a nice and full solution may found in https://dsp.stackexchange.com/questions/1522/simplest-way-of-detecting-where-audio-envelopes-start-and-stop
Have a look at the STFT (short-time fourier transform) or (even better) the DWT (discrete wavelet transform) which both will estimate the frequency content in blocks (windows) of data, which is what you need if you want to detect sudden changes in amplitude of certain ("speech") frequencies.
Don't use a FFT since it calculates the relative frequency content over the entire duration of the signal, making it impossible to determine when a certain frequency occured in the signal.
If you still use inbuilt STFT function, then to plot the maximum you can use following command
plot(T,(floor(abs(max(S,[],1)))))

Using Matlab FFT to extract frequencies from EEG signal

I am new to BCI. I have a Mindset EEG device from Neurosky and I record the Raw data values coming from the device in a csv file. I can read and extract the data from the csv into Matlab and I apply FFT. I now need to extract certain frequencies (Alpha, Beta, Theta, Gamma) from the FFT.
Where Delta = 1-3 Hz
Theta= 4-7 Hz
Alpha = 8-12 Hz
Beta = 13-30 Hz
Gamma = 31-40 Hz
This is what I did so far:
f = (0:N-1)*(Fs/N);
plot(rawDouble);
title ('Raw Signal');
p = abs(fft(rawDouble));
figure,plot (f,p);
title('Magnitude of FFT of Raw Signal');
Can anyone tell me how to extract those particular frequency ranges from the signal?? Thank you very much!
For convenient analysis of EEG data with MatLab you might consider to use the EEGLAB toolbox (http://sccn.ucsd.edu/eeglab/) or the fieldtrip toolbox (http://fieldtrip.fcdonders.nl/start).
Both toolboxes come with good tutorials:
http://sccn.ucsd.edu/eeglab/eeglabtut.html
http://fieldtrip.fcdonders.nl/tutorial
You may find it easier to start off with MATLAB's periodogram function, rather than trying to use the FFT directly. This takes care of windowing the data for you and various other implementation details.
I think the easiest way is to filter your signal in those ranges after you load your data.
E.g.
band=[30 100] eeglocal.lowpass(band(2)).highpass(band(1));
then you can use select the time you want to process.
That should be all you need.