Matlab-frequency bin of the positive and negative frequency - matlab

I am using MATLAB tutorial Frequency-Domain Linear Regression. There is one part of code, where is necessary to determine "frequency bin of the positive and negative frequency", for fft and ifft, this part of code:
freqbin = 72/12;
freqbins = [freqbin 72-freqbin]+1;
tsfit = zeros(72,1);
tsfit(freqbins) = tsdft(freqbins);
tsfit = ifft(tsfit);
mu = mean(ts);
tsfit = mu+tsfit;
Length of time series is 72, and there is 12 months is one cycle. How there can be only one frequency bin for positive frequency, how do we know that is exactly 72/12+1 (+1 is because first bin is for zero frequency), is that some formula or what?

Let's start with some general notes. If the sample rate is Fs, and the number of samples in the FFT is N, then the frequency of the bin with MATLAB index k is:
f_k = (k-1) * Fs / N ;
Or, conversely,
k = f_k * N / Fs + 1;
Hence, the elements of the FFT vector correspond to frequencies 0, Fs/N, 2*Fs/N, ..., (N-1)*Fs/N.
Note that the frequencies are invariant to shifts by Fs. In other words, f and f+Fs and f-Fs are all equivalent. So, you could consider the first half of the FFT vector to correspond to positive frequencies (index: 1 to N/2; frequency: 0 to (N/2-1)/N*Fs), and the second half to correspond to negative frequencies (index: N/2+1 to N; frequency: -Fs/2 to -Fs/N). Here I include 0 in the set of positive frequencies for brevity.
Now, coming to your specific example:
N = 72
Fs = 12 ; % samples per year
So, the positive frequency range is from 0 to Fs/2 = 6 cycles per year, corresponding to indices 1 to 36, respectively.
You are interested in finding the FFT sample corresponding to the frequency 1 cycle per year. That corresponds to index 1 * 72 / 12 + 1 = 7.
Since the FFT is symmetric for real signals, you are also interested in finding the FFT sample corresponding to the frequency -1 cycle per year, which, using the shift-invariance property, is also equivalent to -1 + Fs = 11 cycles per year. The corresponding index is (12-1) * 72 / 12 + 1 = 67.
In summary,
There are 36 positive frequencies (including 0), not 1.
The algorithm is interested in only one positive frequency with the highest magnitude.
That frequency happens to be 1 cycle per year. The corresponding MATLAB index is 7.
The mirror image of the frequency is -1 cycle per year, which corresponds to MATLAB index 67.

Related

Inverse Fourier of a Discrete and Finite Sampling Window

I am trying to find the inverse Fourier of a discrete sampling window with N_f = 11 elements. I am expecting to see a periodic Sinc-like signal in the time-domain:
However, this is the output I get:
Why the number of observed oscillations in my output is more than the expected output?
N_f = 11; % Number of samples in the finite sampling window in Frequency domain
delta_f = 1;
f = [-N_f/2+1:delta_f:N_f/2];
wf = ones(1, N_f)/N_f; % W(f):finite sampling window in Frequency Domain
N_t =128;
wt = ifftshift(ifft(wf, N_t))*N_t; % w(t):Inverse Fourier of the window
I think one of the issues with your code is related to the location of the origin. You create an array wf with 11 ones (and normalized), then call ifft(wf,128). This pads the array with zeros to a size of 128, but the 11 ones are on the left side. You can see this by doing
fft(ifft(wf, N_t))
Thus, your window is shifted by 5 samples to the right, covering frequency bins 0 through 11, rather than -5 through 5 (or identically, 0 through 5 and 124 through 128).
The code below creates a signal with 128 samples, and fills the 11 frequency bins around the middle with 1/11. By calling ifftshift we rotate the signal such that the middle element is moved to the leftmost bin. Now bins 0 through 5 and 124 through 128 are non-zero. I then call ifft, and fftshift to move the 0 frequency back to the middle of the signal. Finally, I plot three repetitions of this signal.
N_f = 11; % Number of samples in the finite sampling window in Frequency domain
N_t = 128;
wf = zeros(1,N_t);
wf( N_t/2 - floor(N_f/2) + 1 : N_t/2 + floor(N_f/2) + 1 ) = 1 / N_f;
wt = fftshift(ifft(ifftshift(wf))) * N_t;
figure; plot(repmat(wt,1,3))
As you can see, the result is as you expected it. Note that the wt result of ifft is actually real-valued. The result of your inverse transform wasn't real-valued, you had to ignore the imaginary component to produce your plot. That's a sign that the input signal wasn't symmetric!
We can change N_f to be twice as large, yielding a result similar to yours, but with a purely real output:
N_f = 21;
N_t = 128;
wf = zeros(1,N_t);
wf( N_t/2 - floor(N_f/2) + 1 : N_t/2 + floor(N_f/2) + 1 ) = 1 / N_f;
wt = fftshift(ifft(ifftshift(wf))) * N_t;
figure; plot(repmat(wt,1,3))

define an interval for frequency of STFT outputs

As you know the STFT has a matrix result, with the dimension given by:
number of frequency bins * number of time frames.
For example, suppose that I have a signal with characteristics and I want to apply STFT method with the following input parameters:
sampling rate : 250,000 Hz;
data length : 498900 samples;
window length : nftt=625 samples;
hop size : 125 samples
With those parameters my STFT will have an output with size: 313*3987 (the method to calculate these values exists in some websites)
Now, my question is how can I define a limit for frequency dimension of STFT output? I think I should calculate my threshold values as an index number in STFT output, if so, how can I do it?
I have the frequency resolution, but when I multiply it by nfft, it's half of the value of sampling rate.
You haven't provided how you calculated the frequency resolution, but here is what it should be:
frequency_resolution = sampling_rate / nfft;
In your particular case with a sampling rate of 250,000Hz and nfft=625, this should give you a frequency resolution of 400Hz. You can verify that 625*400 is indeed equal to 250000.
Then, if you want to include frequencies from 0Hz to frequencies no greater than max_frequency as part of your STFT output, the maximum size along the frequency axis should be given by:
size_frequency_axis = 1 + floor(max_frequency / frequency_resolution);
As a special case you can also verify that when max_frequency is set to the Nyquist frequency (250000/2 = 125000), the computed size is 1+floor(125000/400) = 313 (which matches your full spectrum STFT output size).
As a generalization, if you want to include a range of frequencies not starting at 0Hz, then you can compute in a similar fashion the index of the minimum and maximum frequencies, and obtain the corresponding size with:
min_frequency_index = 1 + floor(min_frequency / frequency_resolution);
max_frequency_index = 1 + floor(max_frequency / frequency_resolution);
size_frequency_axis = max_frequency_index - min_frequency_index + 1;

How can I create n sine waves from the elements of an n-by-m matrix?

I'm writing a program on MATLAB that generates 13 waveforms of varying amplitude, duration, and frequency. Each waveform is repeated 5 times, which means I have 65 'trials' in total.
The total length of each trial = 1.5 ms. The sampling frequency = 4 kHz. I would like the wave to begin at 0.5 ms. Prior to the onset of the wave, and following its offset, I would like the amplitude to be zero (i.e. a 'flatline' prior to and following the wave).
I have created a 65x3 matrix where the columns denote the frequency ('hz'), amplitude ('a'), and duration (ms) of the 65 sine waves. Each row denotes a single wave.
I would like to use the information contained in this 65x3 matrix to generate 65 sine waves of amplitude 'a', frequency 'hz', and duration 'ms'. To be specific: each wave should be created using the parameters (hz,a,ms) specified in the nth row of the matrix. E.g. if row 1 = 100, 1, 50... this means I would like to generate a 100 Hz sine wave (amplitude = 1) lasting 50 ms.
I have attempted to construct a for loop to solve this problem. However, the loop returns a number of errors, and I'm not sure how to resolve them. I have adapted the code to the point where no errors are returned; however, my latest attempt seems to generate 65 waves of equal duration, when in fact the duration of each wave should be that which is stated in vector 'ms'.
Here is my latest, albeit newbie and still unsuccessful, attempt: (note that 'trials' represents the 65x3 matrix discussed above; mA = amplitude).
hz=trials(:,1); mA=trials(:,2); ms=trials(:,3);
trials_waves=zeros(65,500); % the max duration (= 500ms); unsure of this part?
for n = 1:size(order,1)
trials_waves = mA*sin(2*pi*hz*0:ms);
end
Apologies if the information provided is scarce. This is the first time I have asked a question on this website. I can provide more information if needed.
Thank you for your help.
Best,
H
Looks like you've got a good start, I'll try to help you get further towards your solution.
Make a Sine Wave
For starters, let's make a sine wave with variable rate, amplitude, and length.
Fs = 4e3; % sample rate of 4 kHz
Sr = 100; % example rate
Sa = 1; % amplitude
St = 10e-3; % signal duration is 10 ms
% To create a sine wave in MATLAB, I'm going to first create a vector of time,
% `t`, and then create the vector of sine wave samples.
N = St * Fs; % number of samples = duration times sample rate;
t = (1:N) * 1/Fs; % time increment is one over sample rate
% Now I can build my sine wave:
Wave = Sa * sin( 2 * pi * Sr * t );
figure; plot(t, Wave);
Note! This is barely enough time for a full wavelength, so be careful with slow rates and short time lengths.
Make many Sine Waves
To turn this into a loop, I need to index into vectors of input variables. Using my previous example:
Fs = 4e3; % sample rate of 4 kHz
Sr = [100 200 300]; % rates
Sa = [1 .8 .5]; % amplitudes
St = [10e-3 20e-3 25e-3]; % signal durations
nWaves = length(Sr);
N = max(St) * Fs; % number of samples = duration times sample rate;
t = (1:N) /Fs; % time increment is one over sample rate
% initialize the array
waves = zeros(nWaves, N);
for iWaves = 1:nWaves
% index into each variable
thisT = (1:St(iWaves) * Fs) * 1/Fs;
myWave = Sa(iWaves) * sin( 2 * pi * Sr(iWaves) * thisT );
waves(iWaves,1:length(myWave)) = myWave;
end
figure; plot(t, waves);
You still have one more piece, zero padding the front end of your signals, there's lots of ways to do it, one way would be to build the signal the way I've described and then concatenate an appropriate number of zeros to the front of your signal array. Feel free to ask a new question if you get stuck. Good luck!

Calculating the Fourier series coefficients for raw data [duplicate]

I have an FFT result. These are stored in two double arrays: a real part array and an imaginary part array. How do I determine the frequencies that correspond to each element in these arrays?
In other words, I would like have create an array that stores the frequencies for each real and imaginary component of my FFT.
The first bin in the FFT is DC (0 Hz), the second bin is Fs / N, where Fs is the sample rate and N is the size of the FFT. The next bin is 2 * Fs / N. To express this in general terms, the nth bin is n * Fs / N.
So if your sample rate, Fs is say 44.1 kHz and your FFT size, N is 1024, then the FFT output bins are at:
0: 0 * 44100 / 1024 = 0.0 Hz
1: 1 * 44100 / 1024 = 43.1 Hz
2: 2 * 44100 / 1024 = 86.1 Hz
3: 3 * 44100 / 1024 = 129.2 Hz
4: ...
5: ...
...
511: 511 * 44100 / 1024 = 22006.9 Hz
Note that for a real input signal (imaginary parts all zero) the second half of the FFT (bins from N / 2 + 1 to N - 1) contain no useful additional information (they have complex conjugate symmetry with the first N / 2 - 1 bins). The last useful bin (for practical aplications) is at N / 2 - 1, which corresponds to 22006.9 Hz in the above example. The bin at N / 2 represents energy at the Nyquist frequency, i.e. Fs / 2 ( = 22050 Hz in this example), but this is in general not of any practical use, since anti-aliasing filters will typically attenuate any signals at and above Fs / 2.
Take a look at my answer here.
Answer to comment:
The FFT actually calculates the cross-correlation of the input signal with sine and cosine functions (basis functions) at a range of equally spaced frequencies. For a given FFT output, there is a corresponding frequency (F) as given by the answer I posted. The real part of the output sample is the cross-correlation of the input signal with cos(2*pi*F*t) and the imaginary part is the cross-correlation of the input signal with sin(2*pi*F*t). The reason the input signal is correlated with sin and cos functions is to account for phase differences between the input signal and basis functions.
By taking the magnitude of the complex FFT output, you get a measure of how well the input signal correlates with sinusoids at a set of frequencies regardless of the input signal phase. If you are just analyzing frequency content of a signal, you will almost always take the magnitude or magnitude squared of the complex output of the FFT.
I have used the following:
public static double Index2Freq(int i, double samples, int nFFT) {
return (double) i * (samples / nFFT / 2.);
}
public static int Freq2Index(double freq, double samples, int nFFT) {
return (int) (freq / (samples / nFFT / 2.0));
}
The inputs are:
i: Bin to access
samples: Sampling rate in Hertz (i.e. 8000 Hz, 44100Hz, etc.)
nFFT: Size of the FFT vector
The FFT output coefficients (for complex input of size N) are from 0 to N - 1 grouped as [LOW,MID,HI,HI,MID,LOW] frequency.
I would consider that the element at k has the same frequency as the element at N-k since for real data, FFT[N-k] = complex conjugate of FFT[k].
The order of scanning from LOW to HIGH frequency is
0,
1,
N-1,
2,
N-2
...
[N/2] - 1,
N - ([N/2] - 1) = [N/2]+1,
[N/2]
There are [N/2]+1 groups of frequency from index i = 0 to [N/2], each having the frequency = i * SamplingFrequency / N
So the frequency at bin FFT[k] is:
if k <= [N/2] then k * SamplingFrequency / N
if k >= [N/2] then (N-k) * SamplingFrequency / N
Your kth FFT result's frequency is 2*pi*k/N.

Matlab: Count values if signal changed for 0.1 in the last 2 seconds

I have a continuous signal rising and falling. I found peaks- maxima values and its locations.
I am wondering now how to write code to COUNT just in case my signal changed in this kind of rule: Its amplitude exceeded 0.1 and the peak occurred less than two seconds after the beginning of the increase.
Thanks a lot.
A general answer would be: loop through peak vector and check the appropriate part of the value vector for its smallest element:
for i = 1:len(peaks)
peak = peaks(i,:)
peak_value = peak[1]
peak_time = peak[2]
cut_values = values(max(1,(peak_time-2)*f):peak_time*f)
if min(cut_values) < peak_value - 0.1
peak_count += 1 % or something
edit - adding explanation:
peaks is the matrix (nx2) of peak values and times
values is your signal vector
f is the sampling frequency (Hz), considered uniform
Edited again to accomodate peaks before 2s.
Matlab's 1-indexing is a bit tricky here: sample 1 is at time 0, sample 2 at time f. So the really correct thing to do for a signal that starts at zero time is:
cut_values = values(max(0,(peak_time-2)*f)+1:peak_time*f+1)