St · Statistics & Probability

How to Find a Sinusoidal Regression Equation

Published By the 9to5Science editorial team

At a glance

  1. 1. Choose the model

    Write the response as an intercept plus sine and cosine terms with an unknown angular frequency.

  2. 2. Search frequency

    Try candidate frequencies and select the one producing the smallest residual sum of squares.

  3. 3. Fit coefficients

    For each fixed frequency, use ordinary least squares to estimate the intercept, sine coefficient, and cosine coefficient.

  4. 4. Convert form

    Rewrite the fitted sine and cosine terms as amplitude times a shifted sine wave.

Sinusoidal regression is appropriate when a response variable rises and falls in a repeating pattern. The main difficulty is that the period, or equivalently the frequency, may be unknown. Once the frequency is fixed, the remaining regression is linear.

The standard model is

yi=c+asin⁡(ωxi)+bcos⁡(ωxi)+εi,y_i = c + a\sin(\omega x_i) + b\cos(\omega x_i) + \varepsilon_i,

where cc is the vertical offset, aa and bb determine the wave’s size and phase, and ω\omega is the angular frequency. The error terms εi\varepsilon_i represent deviations of the observations from the curve.

Why use both sine and cosine terms?

A model such as c+Rsin⁡(ωx)c + R\sin(\omega x) cannot represent every possible horizontal shift. Adding a cosine term allows the data to determine the phase automatically:

asin⁡(ωx)+bcos⁡(ωx)=Rsin⁡(ωx+ϕ),a\sin(\omega x)+b\cos(\omega x)=R\sin(\omega x+\phi),

where

R=a2+b2,ϕ=atan2⁡(b,a).R=\sqrt{a^2+b^2},\qquad \phi=\operatorname{atan2}(b,a).

Here, RR is the amplitude and ϕ\phi is the phase shift in radians. The period is

T=2πω.T=\frac{2\pi}{\omega}.

The two-argument function atan2⁡(b,a)\operatorname{atan2}(b,a) is preferable to arctan⁡(b/a)\arctan(b/a) because it gives the correct quadrant for the phase.

The fitting procedure

Suppose you have observations (xi,yi)(x_i,y_i).

1. Specify plausible frequencies

Use subject knowledge, a graph, or a periodogram to estimate a range of possible periods. If the period is expected to lie between Tmin⁡T_{\min} and Tmax⁡T_{\max}, then search over

2πTmax⁡≤ω≤2πTmin⁡.\frac{2\pi}{T_{\max}}\leq \omega\leq\frac{2\pi}{T_{\min}}.

Do not search over completely unrestricted frequencies without a reason. Very short periods can fit random fluctuations, especially when the data are sparse.

2. Fit a linear regression for each frequency

For a chosen value of ω\omega, create three predictor columns:

1,sin⁡(ωxi),cos⁡(ωxi).1,\qquad \sin(\omega x_i),\qquad \cos(\omega x_i).

Then fit the ordinary least-squares regression

yi=c+asin⁡(ωxi)+bcos⁡(ωxi)+εi.y_i=c+a\sin(\omega x_i)+b\cos(\omega x_i)+\varepsilon_i.

Calculate the residual sum of squares,

SSE⁡(ω)=∑i[yi−c−asin⁡(ωxi)−bcos⁡(ωxi)]2.\operatorname{SSE}(\omega)=\sum_i\left[y_i-c-a\sin(\omega x_i)-b\cos(\omega x_i)\right]^2.

3. Select the best frequency

Choose the frequency that minimizes SSE⁡(ω)\operatorname{SSE}(\omega). Finally, calculate RR, ϕ\phi, and TT from the fitted values of aa, bb, and ω\omega.

This is often called variable projection: the nonlinear search is needed only for ω\omega, while cc, aa, and bb are estimated linearly at every trial frequency.

Worked example

Consider the following data:

xxyy
02.1
14.8
22.2
3-0.9
41.7
55.2
61.8
7-1.2

The pattern suggests a period of about 44, so try

ω=2π4=π2.\omega=\frac{2\pi}{4}=\frac{\pi}{2}.

At this frequency, the sine and cosine columns are:

sin⁡(πx2)=0,1,0,−1,0,1,0,−1,\sin\left(\frac{\pi x}{2}\right)=0,1,0,-1,0,1,0,-1,

and

cos⁡(πx2)=1,0,−1,0,1,0,−1,0.\cos\left(\frac{\pi x}{2}\right)=1,0,-1,0,1,0,-1,0.

The least-squares estimates are

c=1.9625,a=3.025,b=−0.05.c=1.9625,\qquad a=3.025,\qquad b=-0.05.

Therefore, one fitted equation is

y^=1.9625+3.025sin⁡(πx2)−0.05cos⁡(πx2).\widehat y=1.9625+3.025\sin\left(\frac{\pi x}{2}\right)-0.05\cos\left(\frac{\pi x}{2}\right).

The amplitude is

R=3.0252+(−0.05)2≈3.0254,R=\sqrt{3.025^2+(-0.05)^2}\approx 3.0254,

and the phase is

ϕ=atan2⁡(−0.05,3.025)≈−0.0165.\phi=\operatorname{atan2}(-0.05,3.025)\approx -0.0165.

Thus the same model in amplitude-phase form is approximately

y^=1.9625+3.0254sin⁡(πx2−0.0165).\widehat y=1.9625+3.0254\sin\left(\frac{\pi x}{2}-0.0165\right).

Its period is 44 units. With real data, you would compare this frequency with other candidate frequencies rather than assuming it from the graph alone.

Computing the fit in Python

This code searches a frequency grid and then refines the best candidate. It requires NumPy and SciPy.

import numpy as np
from scipy.optimize import minimize_scalar

x = np.array([0, 1, 2, 3, 4, 5, 6, 7], dtype=float)
y = np.array([2.1, 4.8, 2.2, -0.9, 1.7, 5.2, 1.8, -1.2])

def fit_for_frequency(omega):
    X = np.column_stack([
        np.ones_like(x),
        np.sin(omega * x),
        np.cos(omega * x)
    ])
    coefficients, _, _, _ = np.linalg.lstsq(X, y, rcond=None)
    residuals = y - X @ coefficients
    return np.sum(residuals**2), coefficients

# Search periods between 2 and 10 units.
omegas = np.linspace(2 * np.pi / 10, 2 * np.pi / 2, 2000)
sse_values = np.array([fit_for_frequency(w)[0] for w in omegas])
index = np.argmin(sse_values)
omega0 = omegas[index]

# Refine locally around the best grid value.
step = omegas[1] - omegas[0]
result = minimize_scalar(
    lambda w: fit_for_frequency(w)[0],
    bounds=(max(omegas[0], omega0 - step),
            min(omegas[-1], omega0 + step)),
    method="bounded"
)

omega = result.x
sse, (c, a, b) = fit_for_frequency(omega)
amplitude = np.hypot(a, b)
phase = np.arctan2(b, a)
period = 2 * np.pi / omega

print(f"y = {c:.4f} + {a:.4f} sin({omega:.4f} x) "
      f"+ {b:.4f} cos({omega:.4f} x)")
print(f"amplitude = {amplitude:.4f}")
print(f"phase = {phase:.4f} radians")
print(f"period = {period:.4f}")
print(f"SSE = {sse:.4f}")

A frequency search can have several local minima. Searching a sufficiently fine grid first, restricting the plausible period range, and then refining the best candidates is safer than starting one local optimizer from an arbitrary value.

Common mistakes

Confusing frequency and period

The period is TT, while angular frequency is ω=2π/T\omega=2\pi/T. Using 1/T1/T in a sine function is correct only if the function is written using ordinary frequency and 2π2\pi is included:

sin⁡(2πxT).\sin\left(2\pi\frac{x}{T}\right).

Fitting only a sine term

A model c+Rsin⁡(ωx)c+R\sin(\omega x) forces the wave to have a particular phase. Use sine and cosine predictors unless the phase is known in advance.

Treating the frequency search as linear regression

The coefficients cc, aa, and bb are linear parameters, but ω\omega is not. It must be searched or estimated with a nonlinear optimization method.

Assuming the best visual period is the best statistical period

A graph provides a starting point, not a final estimate. Compare candidate frequencies using residual error and inspect the residuals afterward.

Ignoring uncertainty and extrapolation

A curve may fit observed cycles well but give unreliable predictions outside the observed range. Report uncertainty for the coefficients and frequency when inference matters, and check whether the residuals show remaining trends or changing variance.

References

  1. NIST/SEMATECH e-Handbook of Statistical Methods: Nonlinear Regression
  2. NIST/SEMATECH e-Handbook of Statistical Methods: Least Squares

Spotted an error? Send a correction. Read how we write and check articles in our editorial policy.