How to Find a Sinusoidal Regression Equation
At a glance
- 1. Choose the model
Write the response as an intercept plus sine and cosine terms with an unknown angular frequency.
- 2. Search frequency
Try candidate frequencies and select the one producing the smallest residual sum of squares.
- 3. Fit coefficients
For each fixed frequency, use ordinary least squares to estimate the intercept, sine coefficient, and cosine coefficient.
- 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
where is the vertical offset, and determine the wave’s size and phase, and is the angular frequency. The error terms represent deviations of the observations from the curve.
Why use both sine and cosine terms?
A model such as cannot represent every possible horizontal shift. Adding a cosine term allows the data to determine the phase automatically:
where
Here, is the amplitude and is the phase shift in radians. The period is
The two-argument function is preferable to because it gives the correct quadrant for the phase.
The fitting procedure
Suppose you have observations .
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 and , then search over
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 , create three predictor columns:
Then fit the ordinary least-squares regression
Calculate the residual sum of squares,
3. Select the best frequency
Choose the frequency that minimizes . Finally, calculate , , and from the fitted values of , , and .
This is often called variable projection: the nonlinear search is needed only for , while , , and are estimated linearly at every trial frequency.
Worked example
Consider the following data:
| 0 | 2.1 |
| 1 | 4.8 |
| 2 | 2.2 |
| 3 | -0.9 |
| 4 | 1.7 |
| 5 | 5.2 |
| 6 | 1.8 |
| 7 | -1.2 |
The pattern suggests a period of about , so try
At this frequency, the sine and cosine columns are:
and
The least-squares estimates are
Therefore, one fitted equation is
The amplitude is
and the phase is
Thus the same model in amplitude-phase form is approximately
Its period is 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 , while angular frequency is . Using in a sine function is correct only if the function is written using ordinary frequency and is included:
Fitting only a sine term
A model 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 , , and are linear parameters, but 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
Spotted an error? Send a correction. Read how we write and check articles in our editorial policy.