1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
| import numpy as np import matplotlib.pyplot as plt from matplotlib import animation from IPython.display import HTML
def square_wave(x): return np.where(x > 0, 1, -1)
def fourier_approximation(x, num_terms): result = np.zeros_like(x, dtype=float) for n in range(1, num_terms + 1, 2): result += (4 / (np.pi * n)) * np.sin(n * x) return result
x = np.linspace(-np.pi, np.pi, 1000) true_function = square_wave(x)
approximations = {} term_counts = [1, 3, 5, 11, 21, 51, 101] for terms in term_counts: approximations[terms] = fourier_approximation(x, terms)
l2_errors = {} for terms, approx in approximations.items(): l2_errors[terms] = np.sqrt(np.mean((approx - true_function)**2))
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1) plt.plot(x, true_function, 'k-', label='Square Wave') plt.title('Original Square Wave Function') plt.grid(True) plt.legend() plt.xlim(-np.pi, np.pi) plt.ylim(-1.5, 1.5)
plt.subplot(2, 2, 2) plt.plot(x, true_function, 'k-', label='Square Wave') for terms in [1, 5, 21, 101]: plt.plot(x, approximations[terms], label=f'{terms} terms') plt.title('Fourier Series Approximations') plt.grid(True) plt.legend() plt.xlim(-np.pi, np.pi) plt.ylim(-1.5, 1.5)
plt.subplot(2, 2, 3) plt.plot(list(l2_errors.keys()), list(l2_errors.values()), 'bo-') plt.xscale('log') plt.yscale('log') plt.title('L2 Error vs Number of Terms') plt.xlabel('Number of terms (log scale)') plt.ylabel('L2 Error (log scale)') plt.grid(True)
plt.subplot(2, 2, 4) term_dense = np.arange(1, 102, 2) x_sample = np.linspace(-np.pi, np.pi, 100) approximation_matrix = np.zeros((len(term_dense), len(x_sample)))
for i, terms in enumerate(term_dense): approximation_matrix[i, :] = fourier_approximation(x_sample, terms)
plt.imshow(approximation_matrix, aspect='auto', extent=[-np.pi, np.pi, term_dense[-1], term_dense[0]], cmap='viridis') plt.colorbar(label='Function Value') plt.title('Function Approximation Space') plt.xlabel('x') plt.ylabel('Number of terms')
plt.tight_layout() plt.savefig('fourier_approximation.png', dpi=300) plt.show()
fig, ax = plt.subplots(figsize=(10, 6)) line_true, = ax.plot(x, true_function, 'k-', label='Square Wave') line_approx, = ax.plot([], [], 'r-', label='Approximation') ax.set_xlim(-np.pi, np.pi) ax.set_ylim(-1.5, 1.5) ax.grid(True) ax.legend()
title_text = ax.set_title('Fourier Approximation: 0 terms')
def init(): line_approx.set_data([], []) title_text.set_text('Fourier Approximation: 0 terms') return line_approx, title_text
def animate(i): terms = 2*i - 1 if i > 0 else 0 if terms <= 0: y = np.zeros_like(x) else: y = fourier_approximation(x, terms) line_approx.set_data(x, y) title_text.set_text(f'Fourier Approximation: {terms} terms') return line_approx, title_text
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=52, interval=200, blit=True)
plt.close() HTML(anim.to_jshtml())
terms_for_convergence = np.arange(1, 202, 2) errors = []
for terms in terms_for_convergence: approx = fourier_approximation(x, terms) error = np.sqrt(np.mean((approx - true_function)**2)) errors.append(error)
plt.figure(figsize=(10, 6)) plt.loglog(terms_for_convergence, errors, 'bo-') plt.xlabel('Number of Terms') plt.ylabel('L2 Error') plt.title('Convergence Rate of Fourier Series Approximation') plt.grid(True)
from scipy.optimize import curve_fit
def power_law(x, a, b): return a * x**b
params, _ = curve_fit(power_law, terms_for_convergence, errors) a, b = params
x_fit = np.logspace(np.log10(terms_for_convergence[0]), np.log10(terms_for_convergence[-1]), 100) plt.loglog(x_fit, power_law(x_fit, a, b), 'r-', label=f'Fitted power law: {a:.2e} × n^({b:.3f})') plt.legend() plt.show()
print(f"Convergence rate: O(n^{b:.3f})")
|