🎓How I Study AIHISA
📖Read
📄Papers📰Blogs🎬Courses
💡Learn
🛤️Paths📚Topics💡Concepts🎴Shorts
🎯Practice
⏱️Coach🧩Problems🧠Thinking🎯Prompts🧠Review
SearchSettings
How I Study AI - Learn AI Papers & Lectures the Easy Way
∑MathIntermediate

Fourier Series

Key Points

  • •
    A Fourier series rewrites any reasonable periodic function as a weighted sum of sines and cosines (or complex exponentials).
  • •
    The weights (Fourier coefficients) capture amplitudes and phases of the function’s harmonics and can be computed by integrals or numerically from samples.
  • •
    Orthogonality of sine and cosine waves makes the decomposition unique and efficient for analysis and reconstruction.
  • •
    In practice, we approximate integrals by sums; with equally spaced samples this becomes the Discrete Fourier Transform (DFT), often computed via the FFT.
  • •
    Fourier series converge pointwise for piecewise smooth periodic functions and in mean-square for all square-integrable periodic functions.
  • •
    Discontinuities cause the Gibbs phenomenon: persistent overshoots near jumps that do not vanish but localize as more terms are added.
  • •
    C++ implementations can compute coefficients directly in O(NM) or use FFT for O(N log N) to accelerate from many samples.
  • •
    Correct scaling, sampling rate (Nyquist), and domain normalization (period 2π vs. 2L) are essential to avoid errors.

Prerequisites

  • →Trigonometry (sine, cosine, radians) — Fourier series combine and project onto sine and cosine waves with specific frequencies.
  • →Calculus: definite integrals — Fourier coefficients are defined by integrals over one period.
  • →Complex numbers and Euler’s formula — Complex exponential form c_n e^{inx} simplifies derivations and FFT connections.
  • →DFT and FFT basics — Efficient numerical computation of coefficients relies on understanding the DFT/FFT.
  • →Numerical integration (Riemann/trapezoid) — Approximating integrals from samples is the practical route when f is not integrable in closed form.
  • →Sampling theory and Nyquist rate — Prevents aliasing and ensures correct reconstruction from discrete samples.
  • →Inner products and orthogonality — Coefficient formulas come from projecting onto an orthogonal basis.

Detailed Explanation

Tap terms for definitions

01Overview

Hook → Think about music: a complex chord sounds like one thing, yet it’s really a blend of pure notes (pitches). Concept → A Fourier series says every periodic signal can be expressed as a sum of simple waves—sines and cosines—at integer multiples of a base frequency. Each term’s weight tells you “how much” of that harmonic is present. Mathematically, this is possible because these waves are mutually orthogonal, so they don’t interfere when we measure their contributions. Example → A square wave that flips between +1 and −1 doesn’t look sinusoidal, but its Fourier series is a sum of odd harmonics with decreasing amplitudes. Truncating the series gives a close approximation, and adding more terms refines it. In computing, we rarely compute exact integrals; instead, we sample the function over one period and use weighted sums. With uniform sampling, this is exactly what the Discrete Fourier Transform (DFT) does, and the Fast Fourier Transform (FFT) computes it quickly. Engineers and scientists use Fourier series to analyze signals, filter noise, compress data, and solve differential equations (like the heat equation), because moving to the “frequency domain” often simplifies problems dramatically.

02Intuition & Analogies

Imagine building any complex shape from simple LEGO bricks. For periodic functions, those bricks are pure sine and cosine waves. Each sine/cosine has a frequency (how fast it oscillates), amplitude (how tall it is), and phase (where its peaks land). Just as different combinations of LEGO bricks produce different models, different combinations of sine/cosine waves produce different periodic signals. A tuning app listens to a guitar string and identifies a base pitch (fundamental frequency) and its overtones (harmonics). That’s the Fourier series in action: decomposing a time signal into a stack of pure tones. Another picture is spinning arrows (phasors): imagine several arrows rotating at constant speeds (frequencies). At each time, add their tip positions: the sum traces your signal. Changing an arrow’s length or initial angle changes the contribution’s amplitude and phase. Orthogonality is like grading exams with non-overlapping questions: a score in one section doesn’t affect another. Sines and cosines at different frequencies don’t “leak” into each other when integrated over a full period, so we can measure each harmonic cleanly. Finally, discontinuities are like trying to draw a sharp corner with smooth curves—you can get very close but near the corner you will always see a small wiggle or overshoot (Gibbs phenomenon). As you add more harmonics, the wiggle narrows but doesn’t vanish in height; away from the corner, the approximation becomes excellent.

03Formal Definition

Let f be a 2L-periodic, piecewise smooth function. Its real Fourier series on [-L, L] is f(x) ∼ 2a0​​ + ∑n=1∞​ \big( an​ cos(Lnπx​) + bn​ sin(Lnπx​) \big), where the coefficients are an​ = L1​ ∫−LL​ f(x) cos(Lnπx​)\,dx and bn​ = L1​ ∫−LL​ f(x) sin(Lnπx​)\,dx, and a0​ = L1​ ∫−LL​ f(x)\,dx. In complex form, write f(x) ∼ ∑n=−∞∞​ cn​ einπx/L, with cn​ = 2L1​ ∫−LL​ f(x) e−inπx/L\,dx. The two forms are related by an​=cn​+c−n​ and bn​=i(c−n​−cn​). Convergence: if f is piecewise C1 with finitely many discontinuities (Dirichlet conditions), the series converges to f(x) at points of continuity and to the midpoint of the jump at discontinuities. In L2([-L,L]) (square-integrable), the Fourier series converges to f in mean-square, and Parseval’s identity equates the average energy of f to the sum of squared coefficients. Truncating to N harmonics gives a partial sum SN​(x) that is often used in numerical approximation, filtering, and PDE solutions.

04When to Use

  • Signal analysis and filtering: To identify or modify frequency content (e.g., remove 60 Hz hum), compute Fourier coefficients and zero-out undesired bands.
  • Solving PDEs on bounded intervals with periodic or homogeneous boundary conditions: Fourier series diagonalize linear operators like derivatives, turning differential equations into algebraic ones.
  • Compression and synthesis: Periodic textures, audio synthesis, and procedural animation benefit from storing just a few significant harmonics.
  • Numerical approximation of periodic functions: Spectral methods use truncated Fourier series to achieve very high accuracy for smooth functions.
  • Fast convolution/correlation on periodic domains: Work in frequency space (coefficients) where convolution becomes multiplication. Use the integral formulas when you have analytic expressions and can integrate. Use uniform sampling plus DFT/FFT when you have data or a black-box function. Prefer FFT when you have many samples (N large) or need repeated transforms; direct O(NM) quadrature is fine for small N and M. Always ensure the sampling rate satisfies Nyquist and the period is normalized consistently (2\pi vs. 2L).

⚠️Common Mistakes

  • Wrong scaling and domain: Mixing 2\pi-periodic formulas with [-L,L] formulas leads to missing factors of \pi or L. Always normalize x and double-check the 1/L, 1/\pi factors in coefficients.
  • Insufficient sampling (aliasing): Sampling too slowly folds high frequencies into low ones, corrupting coefficients. Ensure sampling frequency f_s satisfies f_s \ge 2 f_{\max}.
  • Ignoring periodicity alignment: Sampling over a non-integer number of periods causes spectral leakage. Sample exactly one (or an integer number of) full periods or apply a window if not possible.
  • Expecting Gibbs to vanish: The overshoot near discontinuities persists (~9%) though it localizes. Increasing terms narrows the region but doesn’t remove the peak height.
  • Endpoint duplication: In discrete sums on [0,2\pi], avoid double-counting the endpoint 2\pi which equals 0 for periodic functions.
  • Numerical instability or drift: Forgetting normalization by N in DFT/FFT, or mixing forward/inverse sign conventions, yields wrong amplitudes/phases.
  • Overfitting noise: Keeping too many high-frequency coefficients can amplify noise; use smoothing or low-pass filtering when appropriate.

Key Formulas

Real Fourier Series (period 2L)

f(x)∼2a0​​+n=1∑∞​(an​cos(Lnπx​)+bn​sin(Lnπx​))

Explanation: Any sufficiently nice 2L-periodic function can be written as a sum of cosines and sines. The coefficients an​ and bn​ determine how much of each harmonic is present.

Coefficient Formulas (real)

an​=L1​∫−LL​f(x)cos(Lnπx​)dx,bn​=L1​∫−LL​f(x)sin(Lnπx​)dx,a0​=L1​∫−LL​f(x)dx

Explanation: These integrals measure the projection of f onto each cosine/sine basis function. They come from orthogonality over one full period.

Complex Fourier Series

f(x)∼n=−∞∑∞​cn​einπx/L,cn​=2L1​∫−LL​f(x)e−inπx/Ldx

Explanation: The complex form packs amplitude and phase into a single complex number cn​ per harmonic. It is algebraically convenient and maps directly to the DFT.

Real–Complex Relation

an​=cn​+c−n​,bn​=i(c−n​−cn​),a0​=2c0​

Explanation: You can convert between real (an​, bn​) and complex (cn​) coefficients. For real-valued functions, c−n​ is the complex conjugate of cn​.

Orthogonality (cosines)

∫−LL​cos(Lmπx​)cos(Lnπx​)dx=⎩⎨⎧​0,L,2L,​m=nm=n=0m=n=0​

Explanation: Different harmonics are orthogonal over a full period. This property makes coefficient extraction by inner products straightforward.

Parseval’s Identity

L1​∫−LL​∣f(x)∣2dx=2a02​​+n=1∑∞​(an2​+bn2​)=2n=−∞∑∞​∣cn​∣2

Explanation: Average energy in the time domain equals the sum of squared Fourier coefficients. This justifies energy preservation under Fourier decomposition.

Mean-Square Truncation Error

EN2​=L1​∫−LL​​f(x)−SN​(x)​2dx=2∣n∣>N∑​∣cn​∣2

Explanation: The L2 error of truncating to N harmonics equals the leftover energy in the tail of coefficients. As coefficients decay, the error decreases.

Discrete Approximation (Riemann sum)

(2\pi-periodic)an​≈N2​k=0∑N−1​f(xk​)cos(nxk​),bn​≈N2​k=0∑N−1​f(xk​)sin(nxk​),xk​=N2πk​

Explanation: Approximating integrals by uniform sums over one period yields simple, practical formulas for coefficients. This is equivalent to using the DFT with proper scaling.

Discrete Complex Coefficients

cn​≈N1​k=0∑N−1​f(xk​)e−inxk​,xk​=N2πk​

Explanation: Sampling a 2π-periodic function at N points gives coefficients via the DFT normalized by 1/N. This maps directly to FFT-based computation.

Nyquist–Shannon Criterion

fs​≥2fmax​

Explanation: To avoid aliasing when sampling, the sampling frequency must be at least twice the highest frequency present in the signal.

Complexity Analysis

Computing Fourier series numerically involves two main tasks: estimating coefficients and reconstructing the function from them. If you evaluate integrals by uniform Riemann or trapezoidal sums over N samples and want M harmonics, the direct approach loops over all samples for each harmonic, costing O(NM) time and O(M) memory for storing coefficients (or O(N+M) if you also keep samples). This is fine when M and N are modest (e.g., hundreds), or when you only need a few specific harmonics. Reconstruction at a single point from M coefficients costs O(M), and evaluating on a grid of G points costs O(GM). For large N, the FFT reduces coefficient estimation from O(NM) to O(N log N), independent of M if you keep all frequencies. Specifically, a radix-2 Cooley–Tukey FFT transforms N complex samples in O(N log N) time and O(N) space. After the FFT, extracting the first M real coefficients uses simple O(M) formulas (an​=2 Re cn​, bn​ = −2 Im cn​), and you can select any subset of harmonics. Memory usage is O(N) for the sample and transform arrays. Accuracy considerations: for smooth functions, Fourier coefficients decay rapidly (often exponentially), so small M suffices. For piecewise smooth functions, decay is On1​, so more terms are needed and Gibbs oscillations appear near discontinuities. Numerical error sources include finite sampling (aliasing), rounding (especially if N is large), and edge misalignment causing spectral leakage. Using powers-of-two N improves FFT speed; ensuring exact periodicity over the sampled window and applying correct normalization avoids amplitude bias.

Code Examples

Compute Fourier coefficients (2π-periodic) by uniform Riemann sums
1#include <iostream>
2#include <vector>
3#include <cmath>
4#include <iomanip>
5
6// This example computes a0, an, bn for a 2π-periodic function using uniform samples.
7// We use f(x) = square wave: +1 for sin(x) >= 0, else -1.
8// Coefficient formulas for 2π-periodic f:
9// a0 = (1/π) ∫_{-π}^{π} f(x) dx ≈ (2/N) Σ f(x_k)
10// an = (1/π) ∫ f(x) cos(nx) dx ≈ (2/N) Σ f(x_k) cos(n x_k)
11// bn = (1/π) ∫ f(x) sin(nx) dx ≈ (2/N) Σ f(x_k) sin(n x_k)
12
13static inline double PI() { return std::acos(-1.0); }
14
15double f(double x) {
16 return (std::sin(x) >= 0.0) ? 1.0 : -1.0; // 2π-periodic square wave
17}
18
19int main() {
20 const int N = 4096; // number of uniform samples over [0, 2π)
21 const int M = 15; // number of harmonics to compute
22
23 const double twoPI = 2.0 * PI();
24 const double h = twoPI / N; // step size
25
26 // Precompute samples
27 std::vector<double> samples(N);
28 for (int k = 0; k < N; ++k) {
29 double xk = (twoPI * k) / N; // x in [0, 2π)
30 samples[k] = f(xk);
31 }
32
33 // Compute coefficients
34 double a0 = 0.0;
35 for (int k = 0; k < N; ++k) a0 += samples[k];
36 a0 = (2.0 / N) * a0; // (1/π) * h * Σ = (1/π) * (2π/N) * Σ = 2/N * Σ
37
38 std::vector<double> an(M + 1, 0.0), bn(M + 1, 0.0);
39 for (int n = 1; n <= M; ++n) {
40 double sumC = 0.0, sumS = 0.0;
41 for (int k = 0; k < N; ++k) {
42 double xk = (twoPI * k) / N;
43 sumC += samples[k] * std::cos(n * xk);
44 sumS += samples[k] * std::sin(n * xk);
45 }
46 an[n] = (2.0 / N) * sumC;
47 bn[n] = (2.0 / N) * sumS;
48 }
49
50 // Print a0/2, then first few an, bn (expect only odd bn nonzero for a square wave)
51 std::cout << std::fixed << std::setprecision(6);
52 std::cout << "a0/2 = " << (a0 / 2.0) << "\n";
53 for (int n = 1; n <= M; ++n) {
54 std::cout << "n=" << n
55 << ": an=" << an[n]
56 << ", bn=" << bn[n] << "\n";
57 }
58 return 0;
59}
60

We uniformly sample a 2π-periodic function and approximate the defining integrals by Riemann sums. For the square wave, theory predicts a0=0, an≈0, and bn≈4/(π n) for odd n and 0 for even n; the output numerically confirms this. Uniform sampling over exactly one period avoids endpoint duplication and leakage.

Time: O(NM) for computing all an and bn up to M (plus O(N) for a0).Space: O(N + M) to store samples and coefficients.
Reconstruct and visualize partial sums (Gibbs near a jump)
1#include <iostream>
2#include <vector>
3#include <cmath>
4#include <iomanip>
5
6static inline double PI() { return std::acos(-1.0); }
7
8double f(double x) {
9 // 2π-periodic square wave
10 return (std::sin(x) >= 0.0) ? 1.0 : -1.0;
11}
12
13// Evaluate S_M(x) = a0/2 + sum_{n=1}^M (an cos(nx) + bn sin(nx))
14double partial_sum(double x, double a0,
15 const std::vector<double>& an,
16 const std::vector<double>& bn) {
17 double s = 0.5 * a0;
18 int M = (int)an.size() - 1;
19 for (int n = 1; n <= M; ++n) {
20 s += an[n] * std::cos(n * x) + bn[n] * std::sin(n * x);
21 }
22 return s;
23}
24
25int main() {
26 const int N = 4096; // samples for coefficient estimation
27 const int M = 25; // number of harmonics in reconstruction
28
29 const double twoPI = 2.0 * PI();
30
31 // 1) Estimate coefficients from uniform samples
32 std::vector<double> samples(N);
33 for (int k = 0; k < N; ++k) {
34 double xk = (twoPI * k) / N;
35 samples[k] = f(xk);
36 }
37
38 double a0 = 0.0;
39 for (double v : samples) a0 += v;
40 a0 = (2.0 / N) * a0;
41
42 std::vector<double> an(M + 1, 0.0), bn(M + 1, 0.0);
43 for (int n = 1; n <= M; ++n) {
44 double sumC = 0.0, sumS = 0.0;
45 for (int k = 0; k < N; ++k) {
46 double xk = (twoPI * k) / N;
47 sumC += samples[k] * std::cos(n * xk);
48 sumS += samples[k] * std::sin(n * xk);
49 }
50 an[n] = (2.0 / N) * sumC;
51 bn[n] = (2.0 / N) * sumS;
52 }
53
54 // 2) Evaluate the partial sum at grid points and print CSV: x, S_M(x), f(x)
55 std::cout << std::fixed << std::setprecision(6);
56 const int G = 200; // visualization grid
57 for (int i = 0; i < G; ++i) {
58 double x = (twoPI * i) / G; // [0, 2π)
59 double s = partial_sum(x, a0, an, bn);
60 std::cout << x << "," << s << "," << f(x) << "\n";
61 }
62 return 0;
63}
64

This program estimates coefficients for the square wave and then reconstructs the M-term partial sum on a grid, printing CSV lines (x, approximation, true value). Plotting the output (e.g., in Python or a spreadsheet) reveals oscillations near the jump that narrow but persist in height as M increases—the Gibbs phenomenon.

Time: O(NM + GM): estimating coefficients O(NM) and evaluating on G points O(GM).Space: O(N + M + G) for samples, coefficients, and optional output grid.
Use FFT to obtain Fourier coefficients fast (2π-periodic)
1#include <iostream>
2#include <vector>
3#include <complex>
4#include <cmath>
5#include <iomanip>
6#include <algorithm>
7
8// Radix-2 iterative FFT computing DFT with negative sign convention:
9// Forward transform (invert=false): F[k] = sum_{n=0}^{N-1} a[n] * exp(-i 2π k n / N)
10// Inverse (invert=true): a[n] = (1/N) sum_{k=0}^{N-1} F[k] * exp(+i 2π k n / N)
11
12void fft(std::vector<std::complex<double>>& a, bool invert) {
13 int n = (int)a.size();
14
15 // bit-reversal permutation
16 for (int i = 1, j = 0; i < n; ++i) {
17 int bit = n >> 1;
18 for (; j & bit; bit >>= 1) j ^= bit;
19 j ^= bit;
20 if (i < j) std::swap(a[i], a[j]);
21 }
22
23 for (int len = 2; len <= n; len <<= 1) {
24 double ang = 2 * M_PI / len * (invert ? 1 : -1);
25 std::complex<double> wlen(std::cos(ang), std::sin(ang));
26 for (int i = 0; i < n; i += len) {
27 std::complex<double> w(1.0, 0.0);
28 for (int j = 0; j < len / 2; ++j) {
29 std::complex<double> u = a[i + j];
30 std::complex<double> v = a[i + j + len / 2] * w;
31 a[i + j] = u + v;
32 a[i + j + len / 2] = u - v;
33 w *= wlen;
34 }
35 }
36 }
37
38 if (invert) {
39 for (int i = 0; i < n; ++i) a[i] /= n;
40 }
41}
42
43static inline double PI() { return std::acos(-1.0); }
44
45double f(double x) { // example: 2π-periodic square wave
46 return (std::sin(x) >= 0.0) ? 1.0 : -1.0;
47}
48
49int main() {
50 int N = 4096; // must be a power of two for this FFT
51 int M = 15; // number of harmonics to extract
52
53 // 1) Sample f at x_k = 2π k / N
54 std::vector<std::complex<double>> a(N);
55 for (int k = 0; k < N; ++k) {
56 double xk = (2.0 * PI() * k) / N;
57 a[k] = std::complex<double>(f(xk), 0.0);
58 }
59
60 // 2) Compute DFT via FFT (forward transform with negative sign)
61 fft(a, false);
62
63 // Now a[n] holds F[n] = sum f(x_k) e^{-i 2π n k / N}
64 // For a 2π-periodic function, complex Fourier coefficients are c_n ≈ F[n] / N.
65 // Convert to real form: a_n = 2 Re(c_n), b_n = -2 Im(c_n) for n ≥ 1; a_0 = 2 Re(c_0).
66
67 std::vector<double> an(M + 1, 0.0), bn(M + 1, 0.0);
68
69 std::complex<double> c0 = a[0] / (double)N; // n = 0
70 double a0 = 2.0 * c0.real();
71
72 for (int n = 1; n <= M; ++n) {
73 std::complex<double> cn = a[n] / (double)N; // uses forward DFT definition
74 an[n] = 2.0 * cn.real(); // cosine coefficient
75 bn[n] = -2.0 * cn.imag(); // sine coefficient
76 }
77
78 // Print coefficients
79 std::cout << std::fixed << std::setprecision(6);
80 std::cout << "a0/2 = " << (a0 / 2.0) << "\n";
81 for (int n = 1; n <= M; ++n) {
82 std::cout << "n=" << n << ": an=" << an[n] << ", bn=" << bn[n] << "\n";
83 }
84
85 return 0;
86}
87

We sample one period, perform a forward FFT using the negative-exponent convention, and then normalize by 1/N to obtain complex Fourier coefficients c_n. For a real-valued, 2π-periodic f, convert to real coefficients with a_n = 2 Re(c_n) and b_n = −2 Im(c_n). This reduces the cost from O(NM) to O(N log N) when many coefficients are needed.

Time: O(N log N) for the FFT; O(M) to convert the first M coefficients.Space: O(N) for the sample and transform arrays.
#fourier series#harmonics#fourier coefficients#orthogonality#parseval identity#gibbs phenomenon#dft#fft#sampling#nyquist#periodic function#spectral methods#signal processing#trigonometric series#complex exponentials