14

Personally, I feel the design of FourierSeries/FourierSinSeries/FourierCosSeries/FourierTrigSeries not convenient enough because:

  1. They can't give general formula of series as output, one must set a specific integer as the order of series.

  2. One cannot define the domain to be expanded in a convenient way. What if I want to expand a function $f(x)$ in e.g. $x\in(2,10)$?

Can we make them more handy?

xzczd
  • 65,995
  • 9
  • 163
  • 468

2 Answers2

18

For the reasons mentioned above, I wrote the following "shell" for these functions:

(* Weak test for singularity *)
findSingular[coe_, k_, assump___] := 
 Piecewise[{{{}, # === k}}, #] &[
  k /. Union@Solve[{assump, Denominator@Together@coe == 0, k ∈ Integers}, k]]

generalTerm[expr_, {t_, a_, b_}, n_: C][coefunc_, termfunc_, assump___] := 
 With[{generalCoe = coefunc[expr, {t, a, b}, \[FormalK]]}, 
  With[{singularity = findSingular[generalCoe, \[FormalK], assump]}, 
   Piecewise[{{generalCoe, And @@ (\[FormalK] != # & /@ singularity)}, 
      Sequence @@ ({coefunc[expr, {t, a, b}, #], \[FormalK] == #} & /@ 
         singularity)}] termfunc[{t, a, b}, \[FormalK]]]]

summation[lowerbound_, upperbound_] := 
 HoldForm@Sum[#, {\[FormalK], lowerbound, upperbound}] &

trans[old_, new_, var_] := First@RescalingTransform[{new}, {old}][{var}]

easyFourierSinCoefficient[expr_, {t_, a_, b_}, k_] := 
 FourierSinCoefficient[expr /. t -> trans[{a, b}, {0, Pi}, t], t, k] /. 
  t -> trans[{0, Pi}, {a, b}, t]

Block[{t, a, b, k},
  easySinTerm[{t_, a_, b_}, k_] = Sin[k t] /. t -> trans[{0, Pi}, {a, b}, t] // Simplify];

easyFourierSinSeries[expr_, {t_, a_, b_}, n_: C] := 
 summation[1, n]@
  generalTerm[expr, {t, a, b}][easyFourierSinCoefficient, easySinTerm, \[FormalK] > 0]

easyFourierCoefficient[expr_, {t_, a_, b_}, k_] := 
 FourierCoefficient[expr /. t -> trans[{a, b}, {-Pi, Pi}, t], t, k] /. 
  t -> trans[{-Pi, Pi}, {a, b}, t]

Block[{t, a, b, k},
  easyTerm[{t_, a_, b_}, k_] = 
   Exp[I k t] /. t -> trans[{-Pi, Pi}, {a, b}, t] // Simplify];

easyFourierSeries[expr_, {t_, a_, b_}, n_: C] := 
 summation[-n, n]@
  PiecewiseExpand@
   Piecewise[{{generalTerm[expr, {t, a, b}][easyFourierCoefficient, 
       easyTerm], \[FormalK] != 0}}, 
    easyFourierCoefficient[expr, {t, a, b}, 0] easyTerm[{t, a, b}, 0]]

easyFourierCosCoefficient[expr_, {t_, a_, b_}, k_] := 
 FourierCosCoefficient[expr /. t -> trans[{a, b}, {0, Pi}, t], t, k] /. 
  t -> trans[{0, Pi}, {a, b}, t]

Block[{t, a, b, k},
  easyCosTerm[{t_, a_, b_}, k_] = Cos[k t] /. t -> trans[{0, Pi}, {a, b}, t] // Simplify];

easyFourierCosSeries[expr_, {t_, a_, b_}, n_: C] := 
 easyFourierCosCoefficient[expr, {t, a, b}, 0]/2 + 
  summation[1, n]@
   generalTerm[expr, {t, a, b}][easyFourierCosCoefficient, easyCosTerm, \[FormalK] > 0]

Block[{t, a, b, k},
  easyTrigTerm[{t_, a_, b_}, 
    k_] = {Cos[k t], Sin[k t]} /. t -> trans[{-Pi, Pi}, {a, b}, t] // Simplify];

easyFourierTrigSeries[expr_, {t_, a_, b_}, n_: C] := 
 easyFourierCoefficient[expr, {t, a, b}, 0] + 
  summation[1, n]@
   Collect[Simplify[
     generalTerm[expr, {t, a, b}][easyFourierCoefficient, 
        ExpToTrig@easyTerm@## &, \[FormalK] != 
         0] /. {{\[FormalK] -> \[FormalK]}, {\[FormalK] -> -\[FormalK]}} // 
      Total, \[FormalK] > 0 && \[FormalK] ∈ Integers], (Cos | Sin)[_]]

I'm still in v9 so choose HoldForm rather than Inactivate to hold Sum.

The usage of these functions are simple and straightforward. For example, suppose I want to expand

$$ f(x)=\left\{ \begin{array}{ll} x & -\frac{1}{2}\leq x<0 \\ 1 & 0\leq x<\frac{1}{2} \\ -1 & \frac{1}{2}\leq x<\frac{3}{2} \\ \end{array}\right.$$

in $-\frac{1}{2}<x<\frac{3}{2}$ with Fourier sine series, then I just need to write

expr = Piecewise[{{x, -1/2 <= x < 0}, {1, 0 <= x < 1/2}, {-1, 1/2 <= x < 3/2}}]
series = easyFourierSinSeries[expr, {x, -1/2, 3/2}]

Mathematica graphics

If you want to plot or do numeric calculation with the result, just replace C with a specific integer and ReleaseHold:

Plot[{expr, series /. C -> 24 // ReleaseHold} // Evaluate, {x, -1/2, 3/2}, 
 PlotRange -> All]

Mathematica graphics

xzczd
  • 65,995
  • 9
  • 163
  • 468
  • Thanks, the built-in functions are indeed kind of hard to remember so I usually rescale arguments by hand before using them... – Jens Jul 01 '17 at 16:05
  • These procedures are really very helpful. Thanks for this work. (+1) –  Jul 02 '17 at 13:22
  • Please be careful in handling these procedures! For example: f = Piecewise[{{x Sin[x], 0 <= x <= 2 Pi}}] , series = easyFourierSinSeries[f, {x, 0, 2 Pi}] /. C -> 5 // ReleaseHold –  Jul 02 '17 at 17:51
  • @rewi OK, the problem is harder than I expected… The core issue is that we don't have a general function for obtaining singularity (see discussion here for more information). Anyway, I've modified the code to make the shell more general, have a look. – xzczd Jul 02 '17 at 20:21
  • Fantastic! The above example is now properly calculated, furthermore, I have also given difficult examples, e.g. Phase control; it works. –  Jul 02 '17 at 21:15
  • @xzczd He who seeks finds! Unfortunately the worm is still somewhere. Please try the function f [x _] = Exp [Sin [x]] with easyFourierTrigSeries or easyFourierCosSeries (it takes a few minutes). FourierCoefficient or FourierCosCoefficient is not calculated. Mathematica's FourierTrigSeries finds the solution. –  Jul 04 '17 at 11:37
  • @rewi This time it's somewhat beyond my reach… The root of evil is that, FourierCoefficient and FourierCosCoefficient is unable to find the general formula for the coefficient. Try e.g. FourierCoefficient[E^Cos[x/2], x, k] or FourierCosCoefficient[E^Sin[x], x, k]. (Corresponding range of $x$ is $(0,\pi)$. ) My easy…s are built on these functions so limited by their symbolic solving ability. Maybe we can start another (hard) question like "can we enhance the solving ability of FourierCoefficient"? – xzczd Jul 04 '17 at 14:11
  • @rewi Funny, Integrate maanges to find the former coefficient: Integrate[E^Cos[t/2] Exp[-I k t], {t, -Pi, Pi}] // AbsoluteTiming. Well, should I rebuild my easy… on Integrate? – xzczd Jul 04 '17 at 14:57
  • @xzczd Mm..The current version is good, only some functions can not be formed in a Fourier series. By the way, Mathematica can not form FourierSin and FourierCosSeries with f[x_] = E^Sin[x]. FourierTrigSeries but works. Try it with Integrate, the better version then stock. –  Jul 04 '17 at 15:48
7

Regarding the above Piecewise[ ] function:

Piecewise[{{x, -1/2 <= x < 0}, {1, 0 <= x < 1/2}, {-1, 1/2 <= x < 3/2}}]

There is another package (FS.m) that can compute the Fourier series of this type of function. It is located at https://arxiv.org/src/0806.0150v3/anc/FS.m (Most of the package was written long before FourierCoefficient[ ], etc. came along).

You can read in the package with something like << "C:\someDir\FS.m"

If all you want is a nicely-formatted expression for the Fourier series, then use formatSeries:

formatSeries[x, {x, 1, -1}, {-1/2, 0, 1/2, 3/2}, n]

If you don't care about the formatting, but instead just want expressions for the coefficients in terms of n, along with a graph of the function and 10 terms of its Fourier series, then use fSeries:

coeffs = fSeries[x, {x, 1, -1}, {-1/2, 0, 1/2, 3/2}, n, 10]

fSeries returns a list of three items:

coeffs = { aZeroOver2 , an , bn }

aZeroOver2 is the constant term; an and bn are the expressions for the nth cosine and sine terms.

I often find it easier to specify piecewise-continuous functions with a list of (x, y) pairs at endpoints, corners, and jumps:

xyPairs = { {-1/2, -1/2}, {0, 0}, {0, 1}, {1/2, 1}, {1/2, -1}, {3/2, -1} }

formatSeries and fSeries can also work with these (x, y) pairs:

formatSeries[x, xyPairs, n]

fSeries[x, xyPairs, n, 10]

In the above example, the period is $p = 3/2 - (-1/2) = 2$, so $2\pi/p = \pi$, so the Fourier series is

a0/2 + Sum[an * Cos[n Pi x] + bn * Sin[n Pi x], {n, 1, Infinity}]

The following plots the sum of 10 terms of the series over a larger interval that includes three periods:

Plot[coeffs[[1]] + Sum[(coeffs[[2]])*Cos[n Pi x] + (coeffs[[3]])*Sin[n Pi x], {n, 1, 10}], {x, -1/2 - 2, 3/2 + 2}]
xzczd
  • 65,995
  • 9
  • 163
  • 468
  • Happy to see another answer! Then, I think it's worth pointing out that 1. formatSeries can actually handle Piecewise directly, one just needs to make the second argument a List: formatSeries[x, List@Piecewise[{{x, -1/2 <= x < 0}, {1, 0 <= x < 1/2}, {-1, 1/2 <= x < 3/2}}] , {-1/2, 3/2}, n] (Well, I think this design isn't that convenient and can be improved.) 2. This package currently has trouble in handling some edge cases e.g. formatSeries[x, {x Sin[x]}, {0, 2 Pi}, n] – xzczd Jul 19 '17 at 04:19