Michele Ancis
Michele Ancis

Reputation: 1343

Sympy extract Fourier Series coefficients

I am using sympy to carry on some symbolic math manipulations.

Start by creating a Fourier series representation of a rectangular pulse train (duty cycle < 50%), then try to access the multiplying factors, i.e. a_n and b_n of the standard Fourier series.

In a nutshell:

import sympy as sy
from sympy import fourier_series, pi, cos, sin
from sympy.abc import t
from sympy.functions.special.delta_functions import Heaviside
T = sy.symbols('T')
s = fourier_series(Heaviside(t) - Heaviside(t-1/4), (t, 0, 1))
s.truncate(3)

1/π*sin(2πt)+1/π*sin(4πt)+1/π*cos(2πt)+0.25

I would then like to access the coefficients of the base functions. To this extent, I thought I should use as_coefficient(expr).

This produces the expected results in a simpler case:

g = 1/(pi*T)*sin(2*pi*t)
g.as_coefficient(sin(2*pi*t))

1/πT

However, with the object returned by fourier_series, this does not seem to work:

a = s.truncate(3)
a.as_coefficient(sin(2*pi*t))

returns nothing (not even a warning or message).

Other methods like s.as_Add() or s.as_Mul() return both a full expression where the a_n is tied to its sin(2*pi*n*t) term (or b_n to its dual).

Upvotes: 4

Views: 4984

Answers (2)

Victor Bettachini
Victor Bettachini

Reputation: 189

The class sympy.series.fourier.FourierSeries has methods to provide sympy.series.sequences.sequence objects with the cosine and sine terms of the series: a0, an and bn.

After computing the series by

import sympy as sym
from sympy import fourier_series
from sympy.abc import t
from sympy.functions.special.delta_functions import Heaviside
s = fourier_series(Heaviside(t) - Heaviside(t-1/4), (t, 0, 1))

The cosine coefficients can be obtained by

s.a0
0.25

and

s.an

a_n cosine coefficients.

For the sine coefficients

s.bn

b_n sine coefficients.

So in order to produce lists of the s series coefficients up to a given order, let say 4 that can be done with

def cosine_fourier_coeffs(fourierSeries, order):
    ### returns a list of fourier series cosine coefficients up to order
    out = []
    out.append(fourierSeries.a0)
    for i in range(1,order):
        out.append(fourierSeries.an.coeff(i).subs(t, 0 ) )
    return out

def sine_fourier_coeffs(fourierSeries, order):
    ### returns a list of fourier series sine coefficients up to order
    out = []
    for i in range(1,order):
        out.append(fourierSeries.bn.coeff(i).subs(t, 1/(4* i) ) )
    return out

cosine_fourier_coeffs(s, 4), sine_fourier_coeffs(s, 4)

that will return

([0.250000000000000, 1/pi, 0, -1/(3*pi)], [1/pi, 1/pi, 1/(3*pi)])

Upvotes: 4

user3717023
user3717023

Reputation:

The method as_coefficient can't handle a sum of terms like 2*sin(x)+3*cos(x): it picks the coefficient only if the given expression (like sin(x)) can be factored out. So, in order to use it you need to separate the series into chunks with one trig function each. This can be done, but it's easier to change the approach:

  1. Use s.truncate(None) to get a generator for the series.
  2. For each term produced by the generator, plug 0 to get cosine coefficient, and plug 1/(4*k) of the interval length to get sine coefficient (here k is the index)

The reason this works: at 0, sine is 0 and cosine is 1; at 1/4 of length, cosine is 0 and sine is 1.

trig


from sympy import fourier_series, pi, cos, sin
from sympy.abc import t
from sympy.functions.special.delta_functions import Heaviside
s = fourier_series(Heaviside(t) - Heaviside(t-1/4), (t, 0, 1))
iter = s.truncate(None)
cosine_coeffs = []
sine_coeffs = [0]       # there is no sine term for k = 0
for k in range(0, 4):
    term = next(iter)
    cosine_coeffs.append(term.subs(t, 0))
    if k > 0:
        sine_coeffs.append(term.subs(t, 1/(4*k)))

Result:

 cosine_coeffs = [0.250000000000000, 1/pi, 0, -1/(3*pi)]

 sine_coeffs = [0, 1/pi, 1/pi, 1/(3*pi)]

Upvotes: 2

Related Questions