Summing Frequency Spectrums - matlab

I've a set of data from an EEG device from which I want to find the strength of different brain waves in Matlab. I tried to use EEGLAB but I wasn't really sure how, so at this point I'm simply using the dsp toolbox in Matlab.
For background: I've 15 epochs, 4 seconds in length. The device sampled at 256 Hz, and there are 264 sensors, so there are 1024 data points for each sensor for each epoch, i.e. my raw data is 264 x 1024 x 15. The baseline is removed. The data in each epoch is going to be used to train a classifier eventually, so I'm dealing with each epoch individually. I'll come up with more data samples later.
Anyways, what I've done so far is apply a Hann filter to the data and then run fft on the filtered data. So now I have the information in frequency domain. However, I'm not quite sure how to go from the power of the fft buckets to the power of certain frequency bands (e.g. alpha 8-13), to get the values I seek.
I know the answer should be straightforward but I can't seem to get find the answer I want online, and then there's further confusion by certain sources recommending using a wavelet transform? Here's the little bit of code I have so far, the input "data" is one epoch, i.e. 264 x 1024.
% apply a hann window
siz = size(data);
hann_window = hann(siz(2));
hann_window = repmat(hann_window.', siz(1), 1);
hann_data = data.' * hann_window;
% run fft
X = fft(hann_data, [], 2);
X_mag = abs(X);
X_mag = X_mag.';
Thanks for the assistance!

If I'm understanding your question correctly, you are wanting to scale the FFT output to get the correct power. To do this you need to divide by the number of samples used for the FFT.
X_mag = abs(X)/length(hann_data); % This gives the correct power.
See this question for more info.
Once the content is scaled correctly, you can find the power in a band (e.g. 8 - 13 Hz) by integrating the content from the start to the stop of the band. Since you are dealing with discrete values it is a discrete integration. For perspective, this is equivalent to changing the resolution bandwidth of a spectrum analyzer.

Related

Use FFT routine in Matlab to find BPM from given ECG

From the assignment:
Use the fft routine from MATLAB to find out the beats per minute (BPM) in the myecg.csv file. The sampling period for this signal is 0.00192 seconds and the signal was recorded with an attenuation of 10 on the digital scope (what do you have to do to put the signal with the proper amplitude)?
So basically I would have to get the BPM. I am able to successfully read the corresponding ECG and get the Fourier transform spectrum as well as the single sided amplitud spectrum of y(t), but I'm not sure how I can tie the info to get the BPM.
Here's an image of the signal:
That's my code so far:
There are many ways to get the BPM, depending on your DSP knowledge.
First, multiply the signal by 10 to get the "proper amplitude" as the question asks:
y_norm = y*10;
Time Domain: You can calculate the time between peaks:
mean_diff_peaks = mean( diff(find(y_norm>0.5)) );
bps = 1/(mean_diff_peaks * 0.00192);
bpm = bps * 60
(This option is less recommended, since you need some manipulation to samples around the peaks...)
Frequency Domain: You can use fft(),as you did, find the index of the peak and translate to frequency[Hz] (similar to above example)
Spectrum Estimations: Use pwelch() as spectrum estimation to get more accurate results.
Goodluck!

FFT on accelerometer data spike at 0

I have some accelerometer data in MATLAB and I was told to try FFT and try to use FFT features on classification. However, I am confused about the plot after FFT. It seems that there is a large spike only in the beginning of the plot and I am not sure what to make of it. I tried using some code from other posts such as this one: Accelerometer with FFT - strange output, and also some examples on the Mathworks website, but it did not help.
data = acc_data_x(1:300);
fs = 1/(1/12);
m = length(data);
nfft = 2^nextpow2(m);
y = fft(data,nfft)/m;
f = fs/2 * linspace(0,1,nfft/2+1);
power = abs(y);
plot(f,power(1:nfft/2+1))
t = (0 : m-1)/fs;
figure
plot(t,data);
I attached the plot of the accelerometer data in x and the result of the FFT. Is there some other step I am missing? I apologize for any ignorance since this is my first time trying FFT and working with this type of data.
Accelerometer Data in X plot:
After FFT:
Edit: I have tried Gareth's suggestion and used detrend function in MATLAB
After Detrend and FFT:
Also here is the full data with FFT (in the first example I only used up to 300 data points).
I'm now confused if this tells me any information?
You should first detrend your data. FFT inputs that have an uncorrected DC bias (ie, sits positive or negative) have a strong 0 Hz component.
Try data = detrend(data) after your first line. It'll skew some of the other things you do, but might help with showing the issue in the FFT. You can more carefully manage your data so that you can both clean it for FFT and also plot the original raw data once you feel happy with the issue being mostly fixed.
The amplitude of the first "zero-frequency" component in FFT is exactly the mean value of your data. If you fft(x-mean(x)), the first component will be zero. Other components nearby can be related with slow trend.

how to improve the resolution of the PSD using Matlab

I have and audio signal, which I read with Matlab, and use pwelch to get its PSD, here ist the code that I'm using
[x,Fs] = audioread('audioFile.wav');
x= x(:,1) % mono
[xPSD,f] = pwelch(x,hamming(512),16,1024,Fs);
plot(f,xPSD);
since the FS=96000 and I'm only interrested in Frequencies bellow 5khz, I would like to calculate the PSD only for the area, and also being able to adjust the resolution of the PSD ! any idea hwo to do that !
When calculating PSDs with pwelch, there is always a trade-off between spectral resolution, number of averages and the amount of data you need. My preferred way to use it is:
[psd_x, freq] = pwelch(x, hann(nfft), nfft/2, nfft, fsample);
A few differences with your code:
I prefer to use hann windows, since I have bad experiences with hamming windows, they are not very good if your signal contains for example a large DC component. See this comparison, which shows that the roll-off of hann is much better, at the only cost of a slightly higher first sidelobe.
I use windows that overlap 50% (by using noverlap = nfft/2), in this way you 'get the most out of your data'. In your case, there is only 16/512 = 3% overlap between windows, and since the window function is close to zero at its edges, the data points at the edges do not contribute as much as points in the middle of a window. With half-overlapping windows this effect is much smaller. Making the overlap bigger than 50% is useless, you will get more averages, but since you will use the same points many times, this does not add any extra information. Just stick to 50%.
I usually make the length of the fft (fourth argument to pwelch) the same as the window length. The only case you want to have this different is when you use zero-padding, which has limited use.
There are a few simple formulas, which you should memorize when working with pwelch and similar functions:
The spectral resolution is given by the window length only: df = 1 / t_window
The length of a single window is t_window = nfft / f_sample.
With half-overlapping windows, the total amount of needed data is t_total = t_window * (n_average + 1) / 2
For one-sided spectra, the number of spectral bins of the PSD is nfft / 2.
Nyquist: f_max = f_sample / 2
To get a reasonably smooth spectrum, I would typically use on the order of 20 averages. Combining the equations above and filling in the required spectral resolution then gives you the total length of data you need. Or the other way around, if you only have a limited amount of data available, you could calculate the frequency resolution you can obtain.

Time delay estimation using crosscorrelation

I have two sensors seperated by some distance which receive a signal from a source. The signal in its pure form is a sine wave at a frequency of 17kHz. I want to estimate the TDOA between the two sensors. I am using crosscorrelation and below is my code
x1; % signal as recieved by sensor1
x2; % signal as recieved by sensor2
len = length(x1);
nfft = 2^nextpow2(2*len-1);
X1 = fft(x1);
X2 = fft(x2);
X = X1.*conj(X2);
m = ifft(X);
r = [m(end-len+1) m(1:len)];
[a,i] = max(r);
td = i - length(r)/2;
I am filtering my signals x1 and x2 by removing all frequencies below 17kHz.
I am having two problems with the above code:
1. With the sensors and source at the same place, I am getting different values of 'td' at each time. I am not sure what is wrong. Is it because of the noise? If so can anyone please provide a solution? I have read many papers and went through other questions on stackoverflow so please answer with code along with theory instead of just stating the theory.
2. The value of 'td' is sometimes not matching with the delay as calculated using xcorr. What am i doing wrong? Below is my code for td using xcorr
[xc,lags] = xcorr(x1,x2);
[m,i] = max(xc);
td = lags(i);
One problem you might have is the fact that you only use a single frequency. At f = 17 kHz, and an estimated speed-of-sound v = 340 m/s (I assume you use ultra-sound), the wavelength is lambda = v / f = 2 cm. This means that your length measurement has an unambiguity range of 2 cm (sorry, cannot find a good link, google yourself). This means that you already need to know your distance to better than 2 cm, before you can use the result of your measurement to refine the distance.
Think of it in another way: when taking the cross-correlation between two perfect sines, the result should be a 'comb' of peaks with spacing equal to the wavelength. If they overlap perfectly, and you displace one signal by one wavelength, they still overlap perfectly. This means that you first have to know which of these peaks is the right one, otherwise a different peak can be the highest every time purely by random noise. Did you make a plot of the calculated cross-correlation before trying to blindly find the maximum?
This problem is the same as in interferometry, where it is easy to measure small distance variations with a resolution smaller than a wavelength by measuring phase differences, but you have no idea about the absolute distance, since you do not know the absolute phase.
The solution to this is actually easy: let your source generate more frequencies. Even using (band-limited) white-noise should work without problems when calculating cross-correlations, and it removes the ambiguity problem. You should see the white noise as a collection of sines. The cross-correlation of each of them will generate a comb, but with different spacing. When adding all those combs together, they will add up significantly only in a single point, at the delay you are looking for!
White Noise, Maximum Length Sequency or other non-periodic signals should be used as the test signal for time delay measurement using cross correleation. This is because non-periodic signals have only one cross correlation peak and there will be no ambiguity to determine the time delay. It is possible to use the burst type of periodic signals to do the job, but with degraded SNR. If you have to use a continuous periodic signal as the test signal, then you can only measure a time delay within one period of the periodic test signal. This should explain why, in your case, using lower frequency sine wave as the test signal works while using higher frequency sine wave does not. This is demonstrated in these videos: https://youtu.be/L6YJqhbsuFY, https://youtu.be/7u1nSD0RlwY .

matlab FFT. Stuck understanding relationship between frequency and result

We're trying to analyse flow around circular cylinder and we have a set of Cp values that we got from wind tunnel experiment. Initially, we started off with a sample frequency of 20 Hz and tried to find the frequency of vortex shedding using FFT in matlab. We got a frequency of around 7 Hz. Next, we did the same experiment, but the only thing we changed was the sampling frequency- from 20 Hz to 200 Hz. We got the frequency of the vortex shedding to be around 70 Hz (this is where the peak is located in the graph). The graph doesn't change regardless of the Cp data that we enter. The only time the peak differs is when we change the sample frequency. It seems like the increase in the frequency of vortex shedding is proportional to the sample frequency and this doesn't seem to make sense at all. Any help regarding establishing a relation between sample frequency and vortex shedding frequency would be greatly appreaciated.
The problem you are seeing is related to "data aliasing" due to limitations of the FFT being able to detect frequencies higher than the Nyquist Frequency (half-the sampling frequency).
With data aliasing, a peak in real frequency will be centered around (real frequency modulo Nyquist frequency). In your 20 Hz sampling (assuming 70 Hz is the true frequency, that results in zero frequency which means you're not seeing the real information. One thing that can help you with this is to use FFT "windowing".
Another problem that you may be experiencing is related to noisy data generation via single-FFT measurement. It's better to take lots of data, use windowing with overlap, and make sure you have at least 5 FFTs which you average to find your result. As Steven Lowe mentioned, you should also sample at faster rates if possible. I would recommend sampling at the fastest rate your instruments can sample.
Lastly, I would recommend that you read some excerpts from Numerical Recipes in C (<-- link):
Section 12.0 -- Introduction to FFT
Section 12.1 (Discusses data aliasing)
Section 13.4 (Discusses FFT windowing)
You don't need to read the C source code -- just the explanations. Numerical Recipes for C has excellent condensed information on the subject.
If you have any more questions, leave them in the comments. I'll try to do my best in answering them.
Good luck!
this is probably not a programming problem, it sounds like an experiment-measurement problem
i think the sampling frequency has to be at least twice the rate of the oscillation frequency, otherwise you get artifacts; this might explain the difference. Note that the ratio of the FFT frequency to the sampling frequency is 0.35 in both cases. Can you repeat the experiment with higher sampling rates? I'm thinking that if this is a narrow cylinder in a strong wind, it may be vibrating/oscillating faster than the sampling rate can detect..
i hope this helps - there's a 97.6% probability that i don't know what i'm talking about ;-)
If it's not an aliasing problem, it sounds like you could be plotting the frequency response on a normalised frequency scale, which will change with sample frequency. Here's an example of a reasonably good way to plot a frequency response of a signal in Matlab:
Fs = 100;
Tmax = 10;
time = 0:1/Fs:Tmax;
omega = 2*pi*10; % 10 Hz
signal = 10*sin(omega*time) + rand(1,Tmax*Fs+1);
Nfft = 2^8;
[Pxx,freq] = pwelch(signal,Nfft,[],[],Fs)
plot(freq,Pxx)
Note that the sample frequency must be explicitly passed to the pwelch command in order to output the “real” frequency data. Otherwise, when you change the sample frequency the bin where the resonance occurs will seem to shift, which is similar to the problem you describe.
Methinks you need to do some serious reading on digital signal processing before you can even begin to understand all the nuances of the DFT (FFT). If I was you, I'd get grounded in it first with this great book:
Discrete-Time Signal Processing
If you want more of a mathematical treatment that will really expand your abilities,
Fourier Analysis by Körner
Take a look at this related question. While it was originally asked about asked about VB the responses are generically about FFTs
I tried using the frequency response code as above but it seems that I dont have the appropriate toolbox in Matlab. Is there any way to do the same thing without using fft command? So far, this is what I have:
% FFT Algorithm
Fs = 200; % Sampling frequency
T = 1/Fs; % Sample time
L = 65536; % Length of signal
t = (0:L-1)*T; % Time vector
y = data1; % Your CP values go in this vector
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);
% Plot single-sided amplitude spectrum.
loglog(f,2*abs(Y(1:NFFT/2)))
title(' y(t)')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
I think there might be something wrong with the code I am using. I'm not sure what though.
A colleague of mine has written some nice GPL-licenced functions for spectral analysis:
http://www.mecheng.adelaide.edu.au/~pvl/octave/
(Update: this code is now part of one of the Octave modules:
http://octave.svn.sourceforge.net/viewvc/octave/trunk/octave-forge/main/signal/inst/.
But it might be tricky to extract just the pieces you need from there.)
They're written for both Matlab and Octave and serve mostly as a drop-in replacement for the analogous functions in the Signal Processing Toolbox. (So the code above should still work fine.)
It may help with your data analysis; better than rolling your own with fft and the like.