0
$\begingroup$

I need to get the frequency and amplitude for a wave that consists of multiple function. for example, if I have a sine curve (created from two sine waves), How can I extract the parameters for this complex wave.

I used the curve fitting code provided in this answer, as illustrated below. A simple sinusoidal function is used in the provided code. so I obtain a fitted curve with a single amplitude and frequency.

Data example:

import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

x = np.arange(0, 50, 0.01)
x2 = np.arange(0, 100, 0.02)
x3 = np.arange(0, 150, 0.03)
sin1 = np.sin(x)
sin2 = np.sin(x2)
sin3= np.sin(x3/2)

sin4 = sin1 + sin2+sin3
plt.plot(x, sin4)
plt.show()

![enter image description here

import numpy, scipy.optimize

def fit_sin(tt, yy):
    '''Fit sin to the input time sequence, and return fitting parameters "amp", "omega", "phase", "offset", "freq", "period" and "fitfunc"'''
    tt = numpy.array(tt)
    yy = numpy.array(yy)
    ff = numpy.fft.fftfreq(len(tt), (tt[1]-tt[0]))   # assume uniform spacing
    Fyy = abs(numpy.fft.fft(yy))
    guess_freq = abs(ff[numpy.argmax(Fyy[1:])+1])   # excluding the zero frequency "peak", which is related to offset
    guess_amp = numpy.std(yy) * 2.**0.5
    guess_offset = numpy.mean(yy)
    guess = numpy.array([guess_amp, 2.*numpy.pi*guess_freq, 0., guess_offset])

    def sinfunc(t, A, w, p, c):  return A * numpy.sin(w*t + p) + c
    popt, pcov = scipy.optimize.curve_fit(sinfunc, tt, yy, p0=guess)
    A, w, p, c = popt
    f = w/(2.*numpy.pi)
    fitfunc = lambda t: A * numpy.sin(w*t + p) + c
    return {"amp": A, "omega": w, "phase": p, "offset": c, "freq": f, "period": 1./f, "fitfunc": fitfunc, "maxcov": numpy.max(pcov), "rawres": (guess,popt,pcov)}

yy = sin4
tt = x
res = fit_sin(tt, yy)
print(str(i), "Amplitude=%(amp)s, Angular freq.=%(omega)s, phase=%(phase)s, offset=%(offset)s, Max. Cov.=%(maxcov)s" % res )
fit_values=res["fitfunc"](tt)
Frequenc_fit= res['freq']
print(i, Frequenc_fit)
Frequenc_fit=Frequenc_fit
Amp_fit=res['amp']
Omega_fit=res['omega']
Phase_fit=res['phase']
Offset_fit=res['offset']
maxcov_fit=res['maxcov']
plt.plot(tt, yy, "-k", label="y", linewidth=2)
plt.plot(tt,fit_values, "r-", label="y fit curve", linewidth=2)
plt.legend(loc="best")
plt.show()

I got a fitted sine curve with a single frequency and amplitude as follows: ![enter image description here

Is there a method to obtain fitted curve matches with the original one? or open software can be used to get the parameters for the best-fitted wave from the original one? PLEASE, my understanding of FFT is VERY limited! So PLEASE forgive me for my lack of knowledge.

$\endgroup$
3
  • 1
    $\begingroup$ you mention fourier-transform and fft: what the FFT does is really take an input signal, and find the coefficients for complex sinusoids that when summed up, give the original signal. So, your problem is solved: you just need to properly draw all the resulting sines. $\endgroup$ Mar 20 at 10:01
  • 2
    $\begingroup$ the FFT does that, as said above. It's literally what it does: it gives you the coefficients of all sines that when summed up give the original signal. You just need to pick the biggest two coefficient from one half of the result. $\endgroup$ Mar 20 at 10:16
  • $\begingroup$ great, I will search for it. Thank you for your comments. $\endgroup$ Mar 20 at 10:19
1
$\begingroup$

As a precautionary statement, the FFT will give you coefficients of the frequency components closest to the integer multiples of $1/T$ in Hz where $T$ is the length of the sequence in seconds being used for the FFT. If the components are not on these integer boundaries, then you will get several results (called spectral leakage) where the actual components (if information is known such as in the OP’s case of having just two tones) can be estimated as being in between two large adjacent results.

Further when combining the waveform you must pay attention to the phase as well as amplitude of the result in order for it to match the time domain waveform shown. The FFT will provide both a scaled magnitude and phase. The FFT results are the coefficients for complex frequencies (of the form $e^{j\omega t}$ but if it is known that the waveform is real then you can use the first half of the FFT as representing the coefficients of real frequencies in the form of $\cos(\omega t)$, scaled by $N/2$ where $N$ is the number of samples in the sequence used for the FFT.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.