The $N$th order approximation of a continuous periodic function $f(t)$ in a trigonometric basis with complex coefficients is
$$f_N(t)=\sum_{n=-N}^{N} c_n e^{i n \omega_0 t}$$where the Fourier coefficients
$$c_n = \frac{1}{T} \int_{t_0}^{t_0+T} f(t) e^{-i n \omega_0 t}$$are determined from quadratures over the period $T$. In the formula $\omega_0$ denotes principal frequency ($\omega_0 = \frac{2 \pi}{T}$).
These can be defined in terms of the SymPy Python symbolic algebra library functions:
import sympy
sympy.init_printing()
%matplotlib inline
i2pi = sympy.I*2*sympy.pi
exp = sympy.exp
def fN(N):
return sum(c(n)*exp(i2pi*n*t/T) for n in range(-N, N+1)).expand(complex=True).simplify()
def c(n):
return (sympy.integrate(
f(t)*exp((-i2pi * n * t)/T),
(t, t0, t0 + T))/T)
For example let us determine 1D Fourier series of the 'sawtooth' function.
Define function f(t)
and its period.
def f(t):
return t
T = 20
t0 = 0
t = sympy.Symbol('t', real=True)
Let us write its Fourier series up to $N=6$
N = 6
analytic_approx = fN(N).expand()
analytic_approx
The function was defined only as $y=t$ since Fourier series are always used for the analysis of periodic functions. If we plot this for an interval $t$ that is larger than the period $T$ we can see how it approximates the given function.
interval = (t, t0-T, t0+2*T)
p1 = sympy.plot(f(t), interval, show=False)
p2 = sympy.plot(analytic_approx, interval, show=False)
p2[0].line_color = 'red'
p1.extend(p2)
p1.show()
Insted of a symbolic solution a numerically equivalent approximation may also be given with SymPy's mpmath
module.
import mpmath
cs = mpmath.fourier(f, [t0, t0+T], N)
def numeric_approx(t):
return mpmath.fourierval(cs, [t0, t0+T], t)
mpmath.plot([f, numeric_approx], [t0, t0+T])
The coefficients calculated with mpmath.fourier are the cosine and sine coefficients of the function $f_N$.
$$f_N(t) = \sum_{n=0}^N \left(a_n \cos\left(\frac{2\pi nt}{T}\right) + b_n \sin\left(\frac{2\pi nt}{T}\right)\right)$$We can see the connection by evaluating the symbolic expression obtained above and by comparing the two results:
sympy.N(analytic_approx)
cs
([mpf('10.0'), mpf('0.0'), mpf('0.0'), mpf('0.0'), mpf('0.0'), mpf('0.0'), mpf('0.0')], [mpf('0.0'), mpf('-6.366197723675814'), mpf('-3.183098861837907'), mpf('-2.1220659078919377'), mpf('-1.5915494309189535'), mpf('-1.2732395447351628'), mpf('-1.0610329539459689')])
There are only sine coefficients since our function is odd.