FFT when data set has varying vector lengths - matlab

I have data from a model I am running. However the data is collected at each time step and there are varying numbers of time steps. It works out that although there are varying time steps, it is compensated by the change in time step so that all runs are running for the same time.
However I would think that when I have a vector that is 200 in length and one that is 900 in length, taking the FFT will give me inherently different frequencies. I feel like I should take the FFT with respect to the same time axis of all the samples.
The way I have the data now is just as row vectors were each entry is not associated with a space in time.
Is there a way to take the fft of each vector with respect to their place in a time axis rather than their place in the vector array?
My goal is to write a for loop and take the fft of many data sets, and then plot them to compare of frequency signatures change.

If you collect 200 samples in 1 second (200 Hz), you can resolve input data from 1 Hz (1/(1 sec)) to 100 Hz. If you sample for 1 second collecting 900 samples, you can resolve input from 1 Hz to 450 Hz. So both your samples have the same spacing (sampling in the frequency axis is 1 Hz), but they go up to different maximum frequencies!
If your issue is just about plotting, you can either throw away the high frequencies which are not available in all your plots:
totaltime=1; %# common total time of all datasets, in seconds
minsamplenumber=200;
figure;
hold all;
cutofffreq=((minsamplenumber/2+1)/totaltime);
freqscale=0:(1/totaltime):cutofffreq;
datasetcount=42;
ffts=NaN(minsamplenumber,datasetcount);
for i=1:datasetcount
data{i}=... %# collect your data; to make life easier always collect an even number..
ffts(:,i)=fft(data{i},minsamplenumber);
plot(freqscale,ffts{i}(1:end/2+1));
end
... or live with reality, and plot all data you have:
totaltime=1; %# common total time of all datasets, in seconds
figure;
hold all;
for i=1:42
data{i}=... %# collect your data; to make life easier always collect an even number..
ffts{i}=fft(data{i});
maxfreq(i)=((numel(ffts{i})/2+1)/totaltime);
freqscale{i}=0:(1/totaltime):maxfreq(i);
plot(freqscale{i},ffts{i}(1:end/2+1));
end

You could resample your data (by filtered interpolation) into constant length vectors where the sample rate was the same constant rate in each frame. You may have to overlap your FFT frames as well to get constant frame or window offsets.

Related

Any good ways to obtain zero local means in audio signals?

I have asked this question on DSP.SE before, but my question has got no attention. Maybe it was not so related to signal processing.
I needed to divide a discrete audio signal into segments to have some statistical processing and analysis on them. Therefore, segments with fixed local mean would be very helpful for my case. Length of segments are predefined, e.g. 512 samples.
I have tried several things. I do use reshape() function to divide audio signal into segments, and then calculate means of every segment as:
L = 512; % Length of segment
N = floor(length(audio(:,1))/L); % Number of segments
seg = reshape(audio(1:N*L,1), L, N); % Reshape into LxN sized matrix
x = mean(seg); % Calculate mean of each column
Subtracting x(k) from each seg(:,k) would make each local mean zero, yet it would distort audio signal a lot when segments are joined back.
So, since mean of hanning window is almost 0.5, substracting 2*x(k)*hann(L) from each seg(:,k) was the first thing I tried. But this time multiplying by 2 (to make the mean of hanning window be almost equal to 1) distorted the neighborhood of midpoints in each segments itself.
Then, I have used convolution by a smaller hanning window instead of multiplying directly, and subtracting these (as shown in figure below) from each seg(:,k).
This last step gives better results, yet it is still not very useful when segments are smaller. I have seen many amazing approaches here on this site for different problems. So I just wonder if there is any clever ways or existing methods to obtain zero local means which distorts an audio signal less. I read that, this property is useful in some decompositions such as EMD. So maybe I need such decompositions?
You can try to use a moving average filter:
x = cumsum(rand(15*512, 1)-0.5); % generate a random input signal
mean_filter = 1/512 * ones(1, 512); % generate a mean filter
mean = filtfilt(mean_filter, 1, x); % filtfilt is used instead of filter to obtain a symmetric moving average.
% plot the result
figure
subplot(2,1,1)
plot(x);
hold on
plot(mean);
subplot(2,1,2)
plot(x - mean);
You can tune the filter by changing the interval of the mean filter. Using a smaller interval, results in lower means inside each interval, but filters also more low frequencies out of your signal.

Frequency from fft data set matlab [duplicate]

This question already has answers here:
How do I obtain the frequencies of each value in an FFT?
(5 answers)
Closed 6 years ago.
I have a data set in a matrix in matlab. It contains 25,000 values taken every 0.5 ns; so the total time of the dataset is 1.25E-5 seconds.
The data set contains very high frequency noise that I am not interested in so I create another matrix is every 50th data point from the first matrix So the size of the matrix is 1000*.
I plot the absolute values from matlab's fft this matrix (I also normalise the amplitude and only plot the first half) and get the attached (two plots, second is a close up of the low frequencies I am interested in). How do I convert the x-axis to frequency?
Another point, if I take every data point (so I create an fft of the entire 25,000 points) then the x-axis is exactly the same; in other words, the size of my matrix seems to have no bearing on the x-axis returned by matlab. I've attached two links to the frequency spectrum, one of which is a close-up of the low frequencies I am interested in. It's axis goes from 0-50, so it is these values I need to convert to Hz.
Thankyou in advance!
Close up of frequency spectrum
frequency spectrum
From what I read on http://www.mathworks.com/help/matlab/math/fast-fourier-transform-fft.html#bresqop-1, it appears that the units on the x-axis of the plotted FFT are Hz if the first vector, f, you put into the plot(f,power), is defined as a sequence of n elements (n being the number of data points put into the FFT) increasing from zero to the sample frequency.
Thus, for the first plot, which used every 50th of points that were taken at a frequency of 2 GHz, the sample frequency would be 40 MHz. Thus, f = (0:n-1)*4*10^7/(25000/50)
It goes on to show how to use the fftshift function to put the center of the output of the fft function at 0, but it's clear you already did that and chopped off the negative part.
So, once you have the right separation of fs/n, sampling frequency divided by number of data points used, in the vector that supplies the x-axis to the plot function, then the units of the x-axis will be Hz.
(I hope you still have the numbers to graph again? If not, this question might help: Confusion in figuring out the relation between actual frequency values and FFT plot indexes in MATLAB)

How to average values in plot, to make a plot with fewer values

I have a script that plots wind speed in m/s (measured every second) against time in minutes over a period of 24 hours. I want to make a new plot that instead of plotting wind speed each second, averages the wind speed over a period of 10 minutes and then plots this against the time.
Here is a sample image of my data:
Any ideas of how I can do this?
You can use a Moving Average filter using the smooth function as suggested by m.s. in a comment. This is fairly simple:
y = smooth(x,span);
This uses a symmetric smoothing filter, so the span (i.e. the number of samples it takes for smoothing) must be odd: take the current sample plus n before and n after the current sample. That way you still have one sample for every second, they are just smoothed to damp noise and measurement errors.
If you want to reduce the number of points, such that only one point every 10 minutes exists, you can do the following: You take the first 10min * 60s = 600 samples of the vector and put them in the first column of a new matrix. Then take the next 600 samples and put them in the second column, and so on. Now you can column-wise take the mean of the matrix. That way you have a new vector where every element is the mean of 600 samples.
In MATLAB this is easily possible:
X = reshape(x,600,[]); % create matrix with 600 elements per column
y = mean(X,1); % take column-wise mean

Position of high correlation using matlab

I have a signal that more or less repeats itself (not exactly the same from one to the next, see plot to the left). If I use autocorrelation I get a number of maximums (right plot), but it doesn't tell me where (which sample number) the correlation is high. It gives me the lags but I lose information on the position, that is, the sample number in my original data where the signal occurs. For example in the auto-corr. plot, the second peak at sample 500 should correspond to the signal at about sample 750 in the data plot. I could do this by using a small window that moves over the data trace and find the maximums but it takes too much time. Is there a faster way of doing this in matlab? thanks.
I think you're misinterpreting autocorrelation. The correlation peak at 5000 is not due to a single location in the time series, but rather to the fact that the entire time series is similar to itself, when offset by 5000 samples. As much of that peak is due to the time series peak at 18000 as it is to the time series peak at 7500. Your autocorrelation will get very strange if, for example, you do not have a truly periodic time series (that is, if the interval between pulses is nonuniform).
If you can isolate one example of your pulse, and choose the location you want as your t=0, then a correlation of that one pulse with the time series will give you just what you want. Each pulse will light up clearly, at the time location at which it occurs. Then you just need a peak finder.
Yes, you could get the indices of the elements with the maximum amplitude using
treshold = max(a)/2
ind = find(a>=treshold)
where a is the matrix containing the correlation result.

Using FFT in MATLAB on multiple matrices of data to find differences within responses

I have 4 matrices of data F1,F2,O1,O2. All are neural signals collected at 1ms for a second. F1 and O1 were collected at the same time as with F2 and O2. I need to find how the data collected differes between the 2 trials and also compare the components of each trial (F1 and O1) to each other to notice and differences in respones. I'm new to MATLAB but I believe I need to use the fft function. I'm just not sure where to start, any help would be greatly appeciated.
Based on your sampling rate (1000 times per second), you will only be able to analyze signals which have frequency of up to 500 hz. Any neural signal components which have higher components will appear as signals of lower components (unless your device has highpass filter etc..)
The command for fft from Matlab Help is:
Y = fft(signal, n)
Signal is either F1 or O1 or F2 or O2 and should be a vector 1000 long. n determines how many samples your FFT have. This is essentially how finely you will split up the frequency values between 0 hz and 1000 hz (your sampling rate). For example, if you choose n =256, your Y will be a 256 long vector with a measure corresponding to the frequencies (0*1000/256 hz, 1*1000/256 hz, ... 255*1000/256 hz).
Y will be a vector of complex values. Often, you want to see the strength or power of the signal. You can use 'abs()' to find the magnitude. myPSD = abs(Y). Next because your signals are real signals, their fft's are symmetric about half the sampling rate (500hz). Thus, you should only look at the first half. Here is a code snippet to look at the first half.
Y = fft(signal, n); % choose your n
myPSD = abs(Y);
myHalfPSD = myPSD(1:ceil(n/2))
myFreqValues = [0:1000/n:500-1000/n] % both myHalfPSD and myFreqValues should be n/2 long
plot(myFreqValues, myHalfPSD)
Typically, PSD is displayed on a log scale or even decibal. So you might add a line.
Y = fft(signal, n); % choose your n
myPSD = abs(Y);
myHalfPSD = myPSD(1:ceil(n/2))
myHalfDBPSD = 20*log(myHalfPSD)
myFreqValues = [0:1000/n:500-1000/n] % both myHalfPSD and myFreqValues should be n/2 long
plot(myFreqValues, myHalfDBPSD)
If you want to plot all 4 graphs at once you might want to use something like
subplot(4,1,1), subplot(4,1,2) etc..
Hope that helps,
Chuan
If you're trying to compare the frequency spectrums of two separate acquisitions, then fft is the tool you want to use.
Mathworks has pretty good documentation on how to use the fft function, and you can probably cut and paste your data right into the example code they provide.
If you want to plot the data on the same axes, you can use the hold on command, plot different line colors (Ex: plot(x,y,'r') will plot a red line, 'b' a blue one, etc. - see lineseries properties) and include a legend to label the plots.