JavaScript(React)傅里叶级数可视化

Contra
2019-08-31
JavaScript(React)傅里叶级数可视化

【编程德鲁伊】系列是我的横向编程练习笔记,每期围绕一个主题(数学物理电子图形声音...),用几种程序语言分别实现。战法牧贼同时修,能抗能打能奶能开溜。


编程德鲁伊 - 数学篇 - 傅里叶级数可视化 JavaScript (React) 实现

fs-js-5


上一章做了三角函数可视化,分别用 MaxMSP, JavaScript (React), Python, 以及 Unity:

sine-unity-croped

这一章准备重新体验下被傅里叶支配的恐惧,搞一搞傅里叶级数的可视化。 不禁想起那一年夕阳下的奔跑,高数考了7分。 所以本节决定先从最称手的 JavaScript (React) 开始,以防坑上加坑爬不出来。

谈到傅里叶变换、傅里叶分析,通常会分为两部分内容来讲,傅里叶级数和连续傅里叶变换。本章先试试傅里叶级数。


数学基础

在数学中,傅里叶级数可以看作一组正弦曲线组成的周期函数,由加权求和组合而成。 (wikipedia)

举个例子,假设有一个周期性方波,它可以分解成多个正弦波:

Fourier_series_and_transform

正弦波越多,合成后的曲线越接近方波:

474px-Fourier_Series.svg.png


下面正式开始傅里叶级数的推导(公式抄写)。

假设 f(x)f(x) 是一个区间为 x[π,π]x∈[−π,π] 的周期函数, 周期为 2π\pi

f(x)={1,πx<01,0x<πf(x)=\begin{cases} -1,\quad -\pi \leq x < 0 \\\\ 1,\quad 0 \leq x < \pi \end{cases}

它的傅里叶级数正弦函数式:

f(x)=a02+n=1(ancos(nx)+bnsin(nx))f(x) = \cfrac{a_0}{2} + \sum_{n=1}^\infin(a_ncos(nx) + b_nsin(nx))

傅里叶系数:

an=1πππf(x)cos(nx)dxa_n = \cfrac{1}\pi \int _{-\pi} ^\pi f(x) cos(nx)dx

=1ππ0(1)cos(nx)dx+1π0π(1)cos(nx)dx= \cfrac{1}\pi \int _{-\pi} ^0 (-1) cos(nx) dx + \cfrac{1}\pi \int _{0} ^\pi (1) cos(nx) dx

=0(n=0,1,2,...)=0\quad (n = 0, 1, 2, ...)


bn=1πππf(x)sin(nx)dxb_n = \cfrac{1}\pi \int_{-\pi} ^\pi f(x) sin(nx)dx

=1ππ0(1)sin(nx)dx+1π0π(1)sin(nx)dx= \cfrac{1}\pi \int_{-\pi} ^0 (-1) sin (nx) dx + \cfrac{1}\pi \int_{0}^\pi (1) sin(nx)dx

=1π1n[cos(nx)]π0+1π(1n)[cos(nx)]0π= \cfrac{1}\pi \cdot \cfrac{1}n [cos(nx)]_{-\pi}^0 + \cfrac{1}\pi \cdot ( - \cfrac{1}n) [cos(nx)]_{0}^\pi

=2nπ(1cos(nπ))= \cfrac{2}{n\pi} (1 - cos (n\pi))

=2nπ[1(1)n]= \cfrac{2}{n\pi} [1 - (-1)^n]

={4nπ,n=1,3,5,...0,n=2,3,4,...= \begin{cases} \cfrac{4}{n\pi}, \quad n = 1,3,5,... \\\\ 0, \quad n = 2,3,4,... \end{cases}


系数带入傅里叶级数,最终得到:

f(x)=4π122n1 xf(x) = \cfrac{4}\pi \sum_1^\infin \cfrac{2}{2n - 1} \ x

=4π(sinx+13sin3x+15sin5x+...)= \cfrac{4}\pi (sinx + \cfrac{1}3 sin3x+ \cfrac{1}5 sin5x + ...)

(<x<+,and x0,±1,±2,...)( - \infin < x < + \infin, and \ x \neq 0, \pm1, \pm2, ... )


上述公式参考了 "Advanced Mathematics - (Engineering Course) 高等数学-工科"

详细的傅里叶级数在维基百科里也有定义和解释:wikipedia


维基百科里有一张图,是以傅里叶级数正弦函数展开式取了前四项的和为例,展示了如何去近似接近一个方波:

f(x)=4π(sinx+13sin3x+15sin5x+17sin7x)f(x) = \cfrac{4}\pi (sinx + \cfrac{1}3 sin3x+ \cfrac{1}5 sin5x + \cfrac{1}7 sin7x)

Fourier_series_square_wave_circles_animation

本次练习就来实现这张图的曲线。


Visualization

上一章我重构实现了正弦曲线:

sine-visualization-reactjs

这次接着上回单位圆和正弦部分的代码,继续使用React Hooks来做傅里叶级数可视化。

React把js、html、css揉在一起,写起来还是逻辑很清晰(?)的:

fs-js-carbon-0


f(x)=4π(sinx+13sin3x+15sin5x+...)f(x) = \cfrac{4}\pi (sinx + \cfrac{1}3 sin3x+ \cfrac{1}5 sin5x + ...)

(x=1,3,5,7,9,...)( x = 1, 3, 5, 7, 9, ... )

fs-js-carbon-1


数据刷新部分,继续使用 React Hooks:

fs-js-carbon-2

完整源代码请见后文。


最终结果:

fs-js-5

随着n的增加,即正弦波的增加,合成后的波形越来越接近方波。

通过做这个例子,我感觉再考高数的话,傅里叶级数的题应该稳了,这次拿个八九分不成问题,100分在招手。


参考资源


Talk is cheap. Show me the code!

本例及【编程德鲁伊】系列大部分代码都开源在这里: https://github.com/avantcontra/coding-druid


公众号/B站/小红书/抖音/知乎:实验编程

实验编程社群资源、公开课: https://ghc.h5.xeknow.com/s/hzkMX

实验编程情报中心(会员): https://ghc.h5.xeknow.com/s/2BCFuJ

Cheers🍻

Contra