# Fitting discrete curve to cosinus

I have a curve which the asymptotic behavior is the one of a cosinus. I look at this curve on all integers.

I know that the asymptotic curve has this behavior : $$cos(a*x+b)$$

My question is : how can I determine $a$ and $b$ ?

Indeed I only have samples of the curve, and the samples that I have are not exactly of the form of the cosinus as the cosinus is the asymptotic behavior of my curve.

I did the following : I took samples between $[N; N+P]$ with $N$ large enough to be sure that I'm ""in"" the asymptotic zone.

I did a FFT on this zone and noted the frequencies where a Dirac seemed to appear. I . (I chose P large enough to have enough sample to have a good frequency resolution).

Then I made a function which fft is just 2 pure dirac.

But when I plot my curve and the supposed asymptote, I have this (in blue the initial curve that I evaluate only on integers and in red the function I made with the two diracs).

We can see that we have a slow drift between the two curves (I'm almost sure that if I look to samples far away the two curves will be in opposite of phase at a moment).

My question is : is it possible to determine an asymptotic behavior of samples in my case ? And how to do it ?

• This question and its answer are probably relevant. Mar 2, 2017 at 22:17
• I don't think it's the best answer so will just comment that you are nearly there; simply compute the angle vs time between your two waveforms and adjust the frequency of your solution such that the error over your dataset is minimized. The reason for the offset is the small difference between the actual frequency and the closest FFT bin which is an integer submultiple of your sampling clock. Alternatively you could zero pad your time signal in order to interpolate further between your FFT bins to make a closer estimate of your signal assuming it is a single tone. Mar 2, 2017 at 23:06
• Also of my favorite methods of making a frequency discriminator due to its simplicity if you want to do an iterative approach (test, adjust, test, adjust) is the "cross product discriminator" assuming you have a complex signal: take two consecutive samples I1,Q1 and i2,Q2 and the frequency is proportional to i1Q2-I2Q1. You change the slope (sensitivity) of the discriminator by the time distance between the two samples - for your case I would average over the whole data set taking groups of consecutive samples for the best estimate. Mar 2, 2017 at 23:11

As pointed out by Dan Boschen, your signal appears to have a frequency, which does not lie exactly on an FFT bin. Given that the signal contains only a single cosine, you can get a better estimate of its frequency by zero-padding the signal. Have a look at the code below, which reproduces your problem:

Fs = 450
f = 75.5

T = 1

t = np.arange(0, T, 1/Fs)

x = np.cos(2*np.pi*f*t)

plt.figure(figsize=(10,10))

plt.subplot(221)
plt.plot(t, x)
plt.xlim((0, 0.1))

f1 = np.linspace(0, Fs, len(x), endpoint=False)
plt.subplot(222)
X1 = abs(np.fft.fft(x))
plt.plot(f1, X1, '-x')
plt.xlim((60, 90))
plt.axvline(f)

f2 = np.linspace(0, Fs, 32*len(x), endpoint=False)
plt.subplot(223)
X2 = abs(np.fft.fft(x, len(f2)))
plt.plot(f2, X2, '-x')
plt.xlim((60,90))
plt.axvline(f)

plt.subplot(224)
plt.plot(f2, X2, '-x')
plt.xlim((72,79))
plt.axvline(f)

iMax1 = np.argmax(X1)
iMax2 = np.argmax(X2)
print ("Estimated frequency of the Cosine without Zero-padding: f=%f" % (Fs-f1[iMax1]))
print ("Estimated frequency of the Cosine with Zero-padding: f=%f" % f2[iMax2])


The top-left figure shows a part of the sine wave. The top right shows its fft (zoomed into the interesting frequency). As you can see, the FFT shows a significant values at two different frequency bins. This indicates that the actual frequency is between both bins. To find the correct frequency, we can apply zero-padding. Bottom left shows the zero-padded FFT, showing more samples in the frequency domain. The bottom-right shows a zoomed-in version and we see, that the peak of the FFT is exactly at the correct frequency f=75.5Hz. For more information about zero-padding, you can refer to an article I wrote about when you can apply zero-padding, when it wont help etc.

The textual output of the code above is

Estimated frequency of the Cosine without Zero-padding: f=76.000000
Estimated frequency of the Cosine with Zero-padding: f=75.500000


As we see, if we take the maximum of the frequency bin of the non-zeropadded FFT the frequency is estimated to be at 76Hz. However, if we consider the zeropadded FFT, we get the correct frequency estimate.