Fourier Coefficients (C++)

Series

This page demonstrates C++ implementations for computing Fourier series coefficients using numerical integration. The trapezoidal rule is used, which converges exponentially for periodic functions.

Fourier Series

For a function periodic on , the Fourier series is:

The coefficients are computed as:

C++ Implementation

The following code implements Fourier coefficient calculation with a functor-based design:

#include <functional>
#include <vector>
#include <numbers>
#include <cmath>
#include <iostream>

// Helper function: linspace
std::vector<double> linspace(double start, double end, size_t num) {
    std::vector<double> result(num);
    double dx = (end - start) / (num - 1);
    for (size_t i = 0; i < num; ++i) {
        result[i] = start + i * dx;
    }
    return result;
}

// Fourier basis functions
namespace sp {
    struct fourierSine {
        int n;
        double P;
        fourierSine(int n_, double P_) : n(n_), P(P_) {}
        double operator()(double x) {
            double pi = std::numbers::pi_v<double>; 
            return std::sin(2.0*n * pi * x / P);
        }
    };

    struct fourierCosine {
        int n;
        double P;
        fourierCosine(int n_, double P_) : n(n_), P(P_) {}
        double operator()(double x) {
            double pi = std::numbers::pi_v<double>; 
            return std::cos(2.0*n * pi * x / P);
        }
    };
}

// Trapezoidal rule template
template<typename F>
double trap(F f, double a, double b, int N) {
    double h = (b - a) / N;
    double s = 0.5 * (f(a) + f(b));
    for (int i = 1; i < N; ++i)
        s += f(a + i*h);
    return s * h;
}

// Inner product of two functions
double innerProduct(std::function<double(double)> f, 
                    std::function<double(double)> g, 
                    double a, double b, int N) {
    auto integrand = [&f, &g](double x) {
        return f(x) * g(x);
    };
    return trap(integrand, a, b, N);
}

// Fourier coefficient calculations
double a0Fourier(std::function<double(double)> f, double P, int n, int N) {
    return 2.0/P * trap(f, 0.0, P, N);
}

double aFourier(std::function<double(double)> f, double P, int n, int N) {
    auto cos_wrapper = sp::fourierCosine(n, P);
    return 2.0/P * innerProduct(f, cos_wrapper, 0.0, P, N);
}

double bFourier(std::function<double(double)> f, double P, int n, int N) {
    auto sin_wrapper = sp::fourierSine(n, P);
    return 2.0/P * innerProduct(f, sin_wrapper, 0.0, P, N);
}

// Fourier interpolant class
struct fourierInterp {
    std::vector<double> an;
    std::vector<double> bn;
    double a0;
    double L;
    
    fourierInterp(std::vector<double> an_, 
                  std::vector<double> bn_, 
                  double a0_, 
                  double L_)
        : an(an_), bn(bn_), a0(a0_), L(L_) {}

    double operator()(double x) {
        double result = a0 / 2.0;
        double pi = std::numbers::pi_v<double>; 
        
        for (int i = 0; i < an.size(); i++) {
            int n = i + 1;
            result += an[i]*std::cos(2.0*n * pi * x / L) 
                    + bn[i]*std::sin(2.0*n * pi * x / L);
        }
        return result;
    }
};

// Example usage
int main() {
    // Define function to approximate: f(x) = x^2
    auto f = [](double x){ return x*x; };
    
    double L = 6.28;  // Period
    int num_coeffs = 20;
    int integration_points = 20000;
    
    // Compute coefficients
    double a0 = a0Fourier(f, L, 1, integration_points);
    std::vector<double> a(num_coeffs);
    std::vector<double> b(num_coeffs);
    
    for(int n = 0; n < num_coeffs; n++) {
        a[n] = aFourier(f, L, n+1, integration_points);
        b[n] = bFourier(f, L, n+1, integration_points);
    }
    
    // Create interpolant
    fourierInterp finterp(a, b, a0, L);
    
    // Evaluate on grid
    std::vector<double> xs = linspace(0, L, 1000);
    std::vector<double> ys(xs.size());
    for(int i = 0; i < xs.size(); i++) {
        ys[i] = finterp(xs[i]);
    }
    
    // Print some results
    std::cout << "a0 = " << a0 << std::endl;
    std::cout << "First few coefficients:" << std::endl;
    for(int i = 0; i < 5; i++) {
        std::cout << "a[" << i+1 << "] = " << a[i] 
                  << ", b[" << i+1 << "] = " << b[i] << std::endl;
    }
    
    return 0;
}

Key Features

Convergence

The trapezoidal rule converges exponentially for periodic functions, making it ideal for Fourier coefficient calculation. The error decreases as for some constant , where is the number of integration points.