Sampling at exactly Nyquist rate in Matlab - matlab

Today I have stumbled upon a strange outcome in matlab. Lets say I have a sine wave such that
f = 1;
Fs = 2*f;
t = linspace(0,1,Fs);
x = sin(2*pi*f*t);
plot(x)
and the outcome is in the figure.
when I set,
f = 100
outcome is in the figure below,
What is the exact reason of this? It is the Nyquist sampling theorem, thus it should have generated the sine properly. Of course when I take Fs >> f I get better results and a very good sine shape. My explenation to myself is that Matlab was having hardtime with floating numbers but I am not so sure if this is true at all. Anyone have any suggestions?

In the first case you only generate 2 samples (the third input of linspace is number of samples), so it's hard to see anything.
In the second case you generate 200 samples from time 0 to 1 (including those two values). So the sampling period is 1/199, and the sampling frequency is 199, which is slightly below the Nyquist rate. So there is aliasing: you see the original signal of frequency 100 plus its alias at frequency 99.
In other words: the following code reproduces your second figure:
t = linspace(0,1,200);
x = .5*sin(2*pi*99*t) -.5*sin(2*pi*100*t);
plot(x)
The .5 and -.5 above stem from the fact that a sine wave can be decomposed as the sum of two spectral deltas at positive and negative frequencies, and the coefficients of those deltas have opposite signs.
The sum of those two sinusoids is equivalent to amplitude modulation, namely a sine of frequency 99.5 modulated by a sine of frequency 1/2. Since time spans from 0 to 1, the modulator signal (whose frequency is 1/2) only completes half a period. That's what you see in your second figure.
To avoid aliasing you need to increase sample rate above the Nyquist rate. Then, to recover the original signal from its samples you can use an ideal low pass filter with cutoff frequency Fs/2. In your case, however, since you are sampling below the Nyquist rate, you would not recover the signal at frequency 100, but rather its alias at frequency 99.
Had you sampled above the Nyquist rate, for example Fs = 201, the orignal signal could ideally be recovered from the samples.† But that would require an almost ideal low pass filter, with a very sharp transition between passband and stopband. Namely, the alias would now be at frequency 101 and should be rejected, whereas the desired signal would be at frequency 100 and should be passed.
To relax the filter requirements you need can sample well above the Nyquist rate. That way the aliases are further appart from the signal and the filter has an easier job separating signal from aliases.
† That doesn't mean the graph looks like your original signal (see SergV's answer); it only means that after ideal lowpass filtering it will.

Your problem is not related to the Nyquist theorem and aliasing. It is simple problem of graphic representation. You can change your code that frequency of sine will be lower Nyquist limit, but graph will be as strange as before:
t = linspace(0,1,Fs+2);
plot(sin(2*pi*f*t));
Result:
To explain problem I modify your code:
Fs=100;
f=12; %f << Fs
t=0:1/Fs:0.5; % step =1/Fs
t1=0:1/(10*Fs):0.5; % step=1/(10*Fs) for precise graphic representation
subplot (2, 1, 1);
plot(t,sin(2*pi*f*t),"-b",t,sin(2*pi*f*t),"*r");
subplot (2, 1, 2);
plot(t1,sin(2*pi*f*t1),"g",t,sin(2*pi*f*t),"r*");
See result:
Red star - values of sin(2*pi*f) with sampling rate of Fs.
Blue line - lines which connect red stars. It is usual data representation of function plot() - line interpolation between data points
Green curve - sin(2*pi*f)
Your eyes and brain can easily understand that these graphs represent the sine
Change frequency to more high:
f=48; % 2*f < Fs !!!
See on blue lines and red stars. Your eyes and brain do not understand now that these graphs represent the same sine. But your "red stars" are actually valid value of sine. See on bottom graph.
Finally, there is the same graphics for sine with frequency f=50 (2*f = Fs):
P.S.
Nyquist-Shannon sampling theorem states for your case that if:
f < 2*Fs
You have infinite number of samples (red stars on our plots)
then you can reproduce values of function in any time (green curve on our plots). You must use sinc interpolation to do it.

copied from Matlab Help:
linspace
Generate linearly spaced vectors
Syntax
y = linspace(a,b)
y = linspace(a,b,n)
Description
The linspace function generates linearly spaced vectors. It is similar to the colon operator ":", but gives direct control over the number of points.
y = linspace(a,b) generates a row vector y of 100 points linearly spaced between and including a and b.
y = linspace(a,b,n) generates a row vector y of n points linearly spaced between and including a and b. For n < 2, linspace returns b.
Examples
Create a vector of 100 linearly spaced numbers from 1 to 500:
A = linspace(1,500);
Create a vector of 12 linearly spaced numbers from 1 to 36:
A = linspace(1,36,12);

linspace is not apparent for Nyquist interval, so you can use the common form:
t = 0:Ts:1;
or
t = 0:1/Fs:1;
and change the Fs values.
The first Figure is due to the approximation of '0': sin(0) and sin(2*pi). We can notice the range is in 10^(-16) level.

I wrote the function reconstruct_FFT that can recover critically sampled data even for short observation intervals if the input sequence of samples is periodic. It performs lowpass filtering in the frequency domain.

Related

How to filter 1D vector data using a cut-off wavelength in matlab?

I am trying to apply a high-pass filter to a signal (column or row vector) consisting of 1-pixel-wide lines taken from a black-and-white image. I know the resolution of the image (res in the code below, given in mm/pixel). How can I filter these line data in MATLAB to discard certain low frequencies (waviness) or large wavelengths, say >10 mm, using a Butterworth filter or any other?
Line data are not centered at zero.
Fs = 1; % I do not know if this assumption is correct for the image.
Fn = Fs/2; % Nyquist frequency.
lambda = 10; % Cut-off wavelength in mm, given.
samples_in_lambda = lambda/res; % divide by resolution to get samples.
fc = 1/samples_in_lambda; % Cut-off frequency from lambda.
I tried : [z, p, k] = butter(9, fc/fn, 'high'); % I see the filter is high pass on plotting.
Can I filter the line data using the above given and assumed values? If not, is there a way that I can filter the data using a cut-off wavelength?
The highest linear spatial frequency you can represent without aliasing is 1 wave cycle per 2 pixels. This means a spatial Nyquist frequency of 1 wave cycle per 2*(res*1e-3) meters, or 1000/(res*2) reciprocal meters. (Confront this with temporal frequencies, which are measured in reciprocal seconds a.k.a. hertz).
In terms of wavelengths: the shortest wave you can represent without aliasing is 2 pixels long per wave cycle. This means a spatial "Nyquist wavelength" of res*2e-3 meters. (Confront this with temporal "wavelengths" a.k.a. periods, which are measured in seconds.)
If you want to set a cutoff wavelength of 10 mm, that corresponds to a spatial frequency of 100 reciprocal meters. Since the butter() function takes as its second input argument (Wn, the cutoff frequency) an arbitrary fraction of the (spatial) Nyquist frequency (the MATLAB documentation calls it "half the sampling rate"), you merely need to set Wn=100/(1000/(res*2)), i.e. Wn=res/5.
Even though your definition of the spatial sampling frequency is not quite correct (unless you are intentionally measuring it in reciprocal pixels), your final result ended up being equivalent to Wn=res/5, so you should be fine using the call to butter() that you indicated.

How can i use fft to find the maximum frequency of a periodic signal?

I'm trying to find the maximum frequency of a periodic signal in Matlab and as i know when you convert a periodic signal to the frequency spectrum you get only delta functions however i get a few curves between the produced delta functions. Here is the code :
t=[-0.02:10^-3:0.02];
s=5.*(1+cos(2*pi*10*t)).*cos(2*pi*100*t);
figure, subplot(211), plot(t,s);
y=fft(s);
subplot(212), plot(t,y);
Here is a code-snippet to help you understand how to get the frequency-spectrum using fft in matlab.
Things to remember are:
You need to decide on a sampling frequency, which should be high enough, as per the Nyquist Criterion (You need the number of samples, at least more than twice the highest frequency or else we will have aliasing). That means, fs in this example cannot be below 2 * 110. Better to have it even higher to see a have a better appearance of the signal.
For a real signal, what you want is the power-spectrum obtained as the square of the absolute of the output of the fft() function. The imaginary part, which contains the phase should contain nothing but noise. (I didn't plot the phase here, but you can do this to check for yourself.)
Finally, we need to use fftshift to shift the signal such that we get the mirrored spectrum around the zero-frequency.
The peaks would be at the correct frequencies. Now considering only the positive frequencies, as you can see, we have the largest peak at 100Hz and two further lobs around 100Hz +- 10Hz i.e. 90Hz and 110Hz.
Apparently, 110Hz is the highest frequency, in your example.
The code:
fs = 500; % sampling frequency - Should be high enough! Remember Nyquist!
t=[-.2:1/fs:.2];
s= 5.*(1+cos(2*pi*10*t)).*cos(2*pi*100*t);
figure, subplot(311), plot(t,s);
n = length(s);
y=fft(s);
f = (0:n-1)*(fs/n); % frequency range
power = abs(y).^2/n;
subplot(312), plot(f, power);
Y = fftshift(y);
fshift = (-n/2:n/2-1)*(fs/n); % zero-centered frequency range
powershift = abs(Y).^2/n;
subplot(313), plot(fshift, powershift);
The output plots:
The first plot is the signal in the time domain
The signal in the frequency domain
The shifted fft signal

Confusion on how the frequency axis when plotting the FFT magnitude is created

This code takes FFT of a signal and plots it on a new frequency axis.
f=600;
Fs=6000;
t=0:1/Fs:0.3;
n=0:1:length(t);
x=cos(2*pi*(400/Fs)*n)+2*sin(2*pi*(1100/Fs)*n);
y=fft(x,512);
freqaxis=Fs*(linspace(-0.5,0.5, length(y)));
subplot(211)
plot(freqaxis,fftshift(abs(y)));
I understand why we used fftshift because we wanted to see the signal centered at the 0 Hz (DC) value and it is better for observation.
However I seem to be confused about how the frequency axis is defined. Specifically, why did we especially multiply the range of [-0.5 0.5] with Fs and we obtain the [-3000 3000] range? It could be [-0.25 0.25].
The reason why the range is between [-Fs/2,Fs/2] is because Fs/2 is the Nyquist frequency. This is the largest possible frequency that has the ability of being visualized and what is ultimately present in your frequency decomposition. I also disagree with your comment where the range "could be between [-0.25,0.25]". This is contrary to the definition of the Nyquist frequency.
From signal processing theory, we know that we must sample by at least twice the bandwidth of the signal in order to properly reconstruct the signal. The bandwidth is defined as the largest possible frequency component that can be seen in your signal, which is also called the Nyquist Frequency. In other words:
Fs = 2*BW
The upper limit of where we can visualize the spectrum and ultimately the bandwidth / Nyquist frequency is defined as:
BW = Fs / 2;
Therefore because your sampling frequency is 6000 Hz, this means the Nyquist frequency is 3000 Hz, so the range of visualization is [-3000,3000] Hz which is correct in your magnitude graph.
BTW, your bin centres for each of the frequencies is incorrect. You specified the total number of bins in the FFT to be 512, yet the way you are specifying the bins is with respect to the total length of the signal. I'm surprised why you don't get a syntax error because the output of the fft function should give you 512 points yet your frequency axis variable will be an array that is larger than 512. In any case, that is not correct. The frequency at each bin i is supposed to be:
f = i * Fs / N, for i = 0, 1, 2, ..., N-1
N is the total number of points you have in your FFT, which is 512. You originally had it as length(y) and that is not correct... so this is probably why you have a source of confusion when examining the frequency axis. You can read up about why this is the case by referencing user Paul R's wonderful post here: How do I obtain the frequencies of each value in an FFT?
Note that we only specify bins from 0 up to N - 1. To account for this when you specify the bin centres of each frequency, you usually specify an additional point in your linspace command and remove the last point:
freqaxis=Fs*(linspace(-0.5,0.5, 513); %// Change
freqaxis(end) = []; %// Change
BTW, the way you've declared freqaxis is a bit obfuscated to me. This to me is more readable:
freqaxis = linspace(-Fs/2, Fs/2, 513);
freqaxis(end) = [];
I personally hate using length and I favour numel more.
In any case, when I run the corrected code to specify the bin centres, I now get this plot. Take note that I inserted multiple data cursors where the peaks of the spectrum are, which correspond to the frequencies for each of the cosines that you have declared (400 Hz and 1100 Hz):
You see that there are some slight inaccuracies, primarily due to the number of bins you have specified (i.e. 512). If you increased the total number of bins, you will see that the frequencies at each of the peaks will get more accurate.

DSP - Filtering in the frequency domain via FFT

I've been playing around a little with the Exocortex implementation of the FFT, but I'm having some problems.
Whenever I modify the amplitudes of the frequency bins before calling the iFFT the resulting signal contains some clicks and pops, especially when low frequencies are present in the signal (like drums or basses). However, this does not happen if I attenuate all the bins by the same factor.
Let me put an example of the output buffer of a 4-sample FFT:
// Bin 0 (DC)
FFTOut[0] = 0.0000610351563
FFTOut[1] = 0.0
// Bin 1
FFTOut[2] = 0.000331878662
FFTOut[3] = 0.000629425049
// Bin 2
FFTOut[4] = -0.0000381469727
FFTOut[5] = 0.0
// Bin 3, this is the first and only negative frequency bin.
FFTOut[6] = 0.000331878662
FFTOut[7] = -0.000629425049
The output is composed of pairs of floats, each representing the real and imaginay parts of a single bin. So, bin 0 (array indexes 0, 1) would represent the real and imaginary parts of the DC frequency. As you can see, bins 1 and 3 both have the same values, (except for the sign of the Im part), so I guess bin 3 is the first negative frequency, and finally indexes (4, 5) would be the last positive frequency bin.
Then to attenuate the frequency bin 1 this is what I do:
// Attenuate the 'positive' bin
FFTOut[2] *= 0.5;
FFTOut[3] *= 0.5;
// Attenuate its corresponding negative bin.
FFTOut[6] *= 0.5;
FFTOut[7] *= 0.5;
For the actual tests I'm using a 1024-length FFT and I always provide all the samples so no 0-padding is needed.
// Attenuate
var halfSize = fftWindowLength / 2;
float leftFreq = 0f;
float rightFreq = 22050f;
for( var c = 1; c < halfSize; c++ )
{
var freq = c * (44100d / halfSize);
// Calc. positive and negative frequency indexes.
var k = c * 2;
var nk = (fftWindowLength - c) * 2;
// This kind of attenuation corresponds to a high-pass filter.
// The attenuation at the transition band is linearly applied, could
// this be the cause of the distortion of low frequencies?
var attn = (freq < leftFreq) ?
0 :
(freq < rightFreq) ?
((freq - leftFreq) / (rightFreq - leftFreq)) :
1;
// Attenuate positive and negative bins.
mFFTOut[ k ] *= (float)attn;
mFFTOut[ k + 1 ] *= (float)attn;
mFFTOut[ nk ] *= (float)attn;
mFFTOut[ nk + 1 ] *= (float)attn;
}
Obviously I'm doing something wrong but can't figure out what.
I don't want to use the FFT output as a means to generate a set of FIR coefficients since I'm trying to implement a very basic dynamic equalizer.
What's the correct way to filter in the frequency domain? what I'm missing?
Also, is it really needed to attenuate negative frequencies as well? I've seen an FFT implementation where neg. frequency values are zeroed before synthesis.
Thanks in advance.
There are two issues: the way you use the FFT, and the particular filter.
Filtering is traditionally implemented as convolution in the time domain. You're right that multiplying the spectra of the input and filter signals is equivalent. However, when you use the Discrete Fourier Transform (DFT) (implemented with a Fast Fourier Transform algorithm for speed), you actually calculate a sampled version of the true spectrum. This has lots of implications, but the one most relevant to filtering is the implication that the time domain signal is periodic.
Here's an example. Consider a sinusoidal input signal x with 1.5 cycles in the period, and a simple low pass filter h. In Matlab/Octave syntax:
N = 1024;
n = (1:N)'-1; %'# define the time index
x = sin(2*pi*1.5*n/N); %# input with 1.5 cycles per 1024 points
h = hanning(129) .* sinc(0.25*(-64:1:64)'); %'# windowed sinc LPF, Fc = pi/4
h = [h./sum(h)]; %# normalize DC gain
y = ifft(fft(x) .* fft(h,N)); %# inverse FT of product of sampled spectra
y = real(y); %# due to numerical error, y has a tiny imaginary part
%# Depending on your FT/IFT implementation, might have to scale by N or 1/N here
plot(y);
And here's the graph:
The glitch at the beginning of the block is not what we expect at all. But if you consider fft(x), it makes sense. The Discrete Fourier Transform assumes the signal is periodic within the transform block. As far as the DFT knows, we asked for the transform of one period of this:
This leads to the first important consideration when filtering with DFTs: you are actually implementing circular convolution, not linear convolution. So the "glitch" in the first graph is not really a glitch when you consider the math. So then the question becomes: is there a way to work around the periodicity? The answer is yes: use overlap-save processing. Essentially, you calculate N-long products as above, but only keep N/2 points.
Nproc = 512;
xproc = zeros(2*Nproc,1); %# initialize temp buffer
idx = 1:Nproc; %# initialize half-buffer index
ycorrect = zeros(2*Nproc,1); %# initialize destination
for ctr = 1:(length(x)/Nproc) %# iterate over x 512 points at a time
xproc(1:Nproc) = xproc((Nproc+1):end); %# shift 2nd half of last iteration to 1st half of this iteration
xproc((Nproc+1):end) = x(idx); %# fill 2nd half of this iteration with new data
yproc = ifft(fft(xproc) .* fft(h,2*Nproc)); %# calculate new buffer
ycorrect(idx) = real(yproc((Nproc+1):end)); %# keep 2nd half of new buffer
idx = idx + Nproc; %# step half-buffer index
end
And here's the graph of ycorrect:
This picture makes sense - we expect a startup transient from the filter, then the result settles into the steady state sinusoidal response. Note that now x can be arbitrarily long. The limitation is Nproc > 2*min(length(x),length(h)).
Now onto the second issue: the particular filter. In your loop, you create a filter who's spectrum is essentially H = [0 (1:511)/512 1 (511:-1:1)/512]'; If you do hraw = real(ifft(H)); plot(hraw), you get:
It's hard to see, but there are a bunch of non-zero points at the far left edge of the graph, and then a bunch more at the far right edge. Using Octave's built-in freqz function to look at the frequency response we see (by doing freqz(hraw)):
The magnitude response has a lot of ripples from the high-pass envelope down to zero. Again, the periodicity inherent in the DFT is at work. As far as the DFT is concerned, hraw repeats over and over again. But if you take one period of hraw, as freqz does, its spectrum is quite different from the periodic version's.
So let's define a new signal: hrot = [hraw(513:end) ; hraw(1:512)]; We simply rotate the raw DFT output to make it continuous within the block. Now let's look at the frequency response using freqz(hrot):
Much better. The desired envelope is there, without all the ripples. Of course, the implementation isn't so simple now, you have to do a full complex multiply by fft(hrot) rather than just scaling each complex bin, but at least you'll get the right answer.
Note that for speed, you'd usually pre-calculate the DFT of the padded h, I left it alone in the loop to more easily compare with the original.
Your primary issue is that frequencies aren't well defined over short time intervals. This is particularly true for low frequencies, which is why you notice the problem most there.
Therefore, when you take really short segments out of the sound train, and then you filter these, the filtered segments wont filter in a way that produces a continuous waveform, and you hear the jumps between segments and this is what generates the clicks you here.
For example, taking some reasonable numbers: I start with a waveform at 27.5 Hz (A0 on a piano), digitized at 44100 Hz, it will look like this (where the red part is 1024 samples long):
So first we'll start with a low pass of 40Hz. So since the original frequency is less than 40Hz, a low-pass filter with a 40Hz cut-off shouldn't really have any effect, and we will get an output that almost exactly matches the input. Right? Wrong, wrong, wrong – and this is basically the core of your problem. The problem is that for the short sections the idea of 27.5 Hz isn't clearly defined, and can't be represented well in the DFT.
That 27.5 Hz isn't particularly meaningful in the short segment can be seen by looking at the DFT in the figure below. Note that although the longer segment's DFT (black dots) shows a peak at 27.5 Hz, the short one (red dots) doesn't.
Clearly, then filtering below 40Hz, will just capture the DC offset, and the result of the 40Hz low-pass filter is shown in green below.
The blue curve (taken with a 200 Hz cut-off) is starting to match up much better. But note that it's not the low frequencies that are making it match up well, but the inclusion of high frequencies. It's not until we include every frequency possible in the short segment, up to 22KHz that we finally get a good representation of the original sine wave.
The reason for all of this is that a small segment of a 27.5 Hz sine wave is not a 27.5 Hz sine wave, and it's DFT doesn't have much to do with 27.5 Hz.
Are you attenuating the value of the DC frequency sample to zero? It appears that you are not attenuating it at all in your example. Since you are implementing a high pass filter, you need to set the DC value to zero as well.
This would explain low frequency distortion. You would have a lot of ripple in the frequency response at low frequencies if that DC value is non-zero because of the large transition.
Here is an example in MATLAB/Octave to demonstrate what might be happening:
N = 32;
os = 4;
Fs = 1000;
X = [ones(1,4) linspace(1,0,8) zeros(1,3) 1 zeros(1,4) linspace(0,1,8) ones(1,4)];
x = ifftshift(ifft(X));
Xos = fft(x, N*os);
f1 = linspace(-Fs/2, Fs/2-Fs/N, N);
f2 = linspace(-Fs/2, Fs/2-Fs/(N*os), N*os);
hold off;
plot(f2, abs(Xos), '-o');
hold on;
grid on;
plot(f1, abs(X), '-ro');
hold off;
xlabel('Frequency (Hz)');
ylabel('Magnitude');
Notice that in my code, I am creating an example of the DC value being non-zero, followed by an abrupt change to zero, and then a ramp up. I then take the IFFT to transform into the time domain. Then I perform a zero-padded fft (which is done automatically by MATLAB when you pass in an fft size bigger than the input signal) on that time-domain signal. The zero-padding in the time-domain results in interpolation in the frequency domain. Using this, we can see how the filter will respond between filter samples.
One of the most important things to remember is that even though you are setting filter response values at given frequencies by attenuating the outputs of the DFT, this guarantees nothing for frequencies occurring between sample points. This means the more abrupt your changes, the more overshoot and oscillation between samples will occur.
Now to answer your question on how this filtering should be done. There are a number of ways, but one of the easiest to implement and understand is the window design method. The problem with your current design is that the transition width is huge. Most of the time, you will want as quick of transitions as possible, with as little ripple as possible.
In the next code, I will create an ideal filter and display the response:
N = 32;
os = 4;
Fs = 1000;
X = [ones(1,8) zeros(1,16) ones(1,8)];
x = ifftshift(ifft(X));
Xos = fft(x, N*os);
f1 = linspace(-Fs/2, Fs/2-Fs/N, N);
f2 = linspace(-Fs/2, Fs/2-Fs/(N*os), N*os);
hold off;
plot(f2, abs(Xos), '-o');
hold on;
grid on;
plot(f1, abs(X), '-ro');
hold off;
xlabel('Frequency (Hz)');
ylabel('Magnitude');
Notice that there is a lot of oscillation caused by the abrupt changes.
The FFT or Discrete Fourier Transform is a sampled version of the Fourier Transform. The Fourier Transform is applied to a signal over the continuous range -infinity to infinity while the DFT is applied over a finite number of samples. This in effect results in a square windowing (truncation) in the time domain when using the DFT since we are only dealing with a finite number of samples. Unfortunately, the DFT of a square wave is a sinc type function (sin(x)/x).
The problem with having sharp transitions in your filter (quick jump from 0 to 1 in one sample) is that this has a very long response in the time domain, which is being truncated by a square window. So to help minimize this problem, we can multiply the time-domain signal by a more gradual window. If we multiply a hanning window by adding the line:
x = x .* hanning(1,N).';
after taking the IFFT, we get this response:
So I would recommend trying to implement the window design method since it is fairly simple (there are better ways, but they get more complicated). Since you are implementing an equalizer, I assume you want to be able to change the attenuations on the fly, so I would suggest calculating and storing the filter in the frequency domain whenever there is a change in parameters, and then you can just apply it to each input audio buffer by taking the fft of the input buffer, multiplying by your frequency domain filter samples, and then performing the ifft to get back to the time domain. This will be a lot more efficient than all of the branching you are doing for each sample.
First, about the normalization: that is a known (non) issue. The DFT/IDFT would require a factor 1/sqrt(N) (apart from the standard cosine/sine factors) in each one (direct an inverse) to make them simmetric and truly invertible. Another possibility is to divide one of them (the direct or the inverse) by N, this is a matter of convenience and taste. Often the FFT routines do not perform this normalization, the user is expected to be aware of it and normalize as he prefers. See
Second: in a (say) 16 point DFT, what you call the bin 0 would correspond to the zero frequency (DC), bin 1 low freq... bin 4 medium freq, bin 8 to the highest frequency and bins 9...15 to the "negative frequencies". In you example, then, bin 1 is actually both the low frequency and medium frequency. Apart from this consideration, there is nothing conceptually wrong in your "equalization". I don't understand what you mean by "the signal gets distorted at low frequencies". How do you observe that ?

What's the fastest way to approximate the period of data using Octave?

I have a set of data that is periodic (but not sinusoidal). I have a set of time values in one vector and a set of amplitudes in a second vector. I'd like to quickly approximate the period of the function. Any suggestions?
Specifically, here's my current code. I'd like to approximate the period of the vector x(:,2) against the vector t. Ultimately, I'd like to do this for lots of initial conditions and calculate the period of each and plot the result.
function xdot = f (x,t)
xdot(1) =x(2);
xdot(2) =-sin(x(1));
endfunction
x0=[1;1.75]; #eventually, I'd like to try lots of values for x0(2)
t = linspace (0, 50, 200);
x = lsode ("f", x0, t)
plot(x(:,1),x(:,2));
Thank you!
John
Take a look at the auto correlation function.
From Wikipedia
Autocorrelation is the
cross-correlation of a signal with
itself. Informally, it is the
similarity between observations as a
function of the time separation
between them. It is a mathematical
tool for finding repeating patterns,
such as the presence of a periodic
signal which has been buried under
noise, or identifying the missing
fundamental frequency in a signal
implied by its harmonic frequencies.
It is often used in signal processing
for analyzing functions or series of
values, such as time domain signals.
Paul Bourke has a description of how to calculate the autocorrelation function effectively based on the fast fourier transform (link).
The Discrete Fourier Transform can give you the periodicity. A longer time window gives you more frequency resolution so I changed your t definition to t = linspace(0, 500, 2000).
time domain http://img402.imageshack.us/img402/8775/timedomain.png (here's a link to the plot, it looks better on the hosting site).
You could do:
h = hann(length(x), 'periodic'); %# use a Hann window to reduce leakage
y = fft(x .* [h h]); %# window each time signal and calculate FFT
df = 1/t(end); %# if t is in seconds, df is in Hz
ym = abs(y(1:(length(y)/2), :)); %# we just want amplitude of 0..pi frequency components
semilogy(((1:length(ym))-1)*df, ym);
frequency domain http://img406.imageshack.us/img406/2696/freqdomain.png Plot link.
Looking at the graph, the first peak is at around 0.06 Hz, corresponding to the 16 second period seen in plot(t,x).
This isn't computationally that fast though. The FFT is N*log(N) operations.