「どんな複雑な波形も、サイン波の足し算で作れる」
そう言われて、信じられますか? しかもそのサイン波は、ただの「くるくる回る矢印」の集まりで表現できるんです。
今回紹介するのは、そんな魔法を目で見て、手を動かして、コードまで書いて理解できるツール。しかも、あの有名な「ギブス現象」までリアルタイムで観察できます。
▶ 今回のシミュレーター: フーリエ級数可視化ツール (ブラウザで動作・登録不要)
「サイン波の足し算」って、本当にできるの?
まずは直感を養いましょう。
あなたが今見ているこの画面。実は、たった1つのサイン波から始まります。
- N=1:ただの正弦波。単純な「山と谷」
- N=3:3倍の速さで振動する波を足すと、角が立ち始める
- N=5:さらに5倍速の波を追加…矩形波に近づく
- N=奇数を増やすごとに、矩形波がくっきり
これがフーリエ級数の本質です。
「どんな周期的な波形も、基本波とその整数倍の高調波の重ね合わせで表現できる」
ざっくり本質──「回る矢印」が波形を作る
ここで、ツールの画面を見てください。左側にくるくる回る矢印(フェーザー) がいくつも描かれていますよね。
あれ、何を表しているか分かりますか?
各矢印=1つのサイン波です。
- 矢印の長さ → そのサイン波の振幅
- 回る速さ → 周波数(基本波の何倍か)
- 矢印を先端から次へつなげる → すべてのサイン波の和
そして、最後の矢印の先端の高さ(y座標) が、今この瞬間の合成波形の値になるんです。
つまり、円をくるくる回して、その先端を時間方向に並べる。それだけで、矩形波も鋸波も三角波も作れてしまう。
直感的に理解できましたか? では、数式で正確に表現してみましょう。
数式で理解する──4つの波形のフーリエ級数
矩形波(Square Wave)
最も有名なケース。奇数次の正弦波だけで構成されます。
x_{\text{square}}(t) = \frac{4}{\pi}\sum_{n=1,3,5,...}^{N}\frac{\sin(n\omega t)}{n}
- $n=1,3,5,...$:奇数のみ登場
- 係数が $1/n$:高調波ほど振幅が小さくなる
- 不連続点($t=0, T/2, T,...$)でギブス現象が起きる
鋸波(Sawtooth Wave)
全次数の正弦波が登場。係数の減衰は $1/n$ と同じ。
x_{\text{saw}}(t) = \frac{2}{\pi}\sum_{n=1}^{N}\frac{(-1)^{n+1}\sin(n\omega t)}{n}
- $n=1,2,3,...$:すべての整数が登場
- 符号が $(-1)^{n+1}$:偶数次で符号反転
- 矩形波と同様、不連続点でギブス現象が起きる
三角波(Triangle Wave)
奇数次のみだが、係数が $1/n^2$ と急速に減衰。
x_{\text{tri}}(t) = \frac{8}{\pi^2}\sum_{n=1,3,5,...}^{N}\frac{(-1)^{(n-1)/2}\sin(n\omega t)}{n^2}
- $n=1,3,5,...$:奇数だけ
- 係数 $1/n^2$:高調波の影響が非常に小さい
- 波形が連続なので、ギブス現象は起きない
パルス波(Pulse Wave)
デューティ比 $d$(0〜1)で波形が変化。$n=4,8,12,...$ で係数がゼロになる特徴が。
x_{\text{pulse}}(t) = \sum_{n=1}^{N}\frac{2}{n\pi}\bigl(1-\cos(2\pi n d)\bigr)\sin(n\omega t)
- $d$:デューティ比(パルスの幅)
- $n=4,8,12,...$ で $\cos(2\pi n d)=1$ となり、係数がゼロ
- 矩形波は $d=0.5$ の特殊ケース
コードで実装する ★最重要★
ここがこの記事の核心です。上の数式を実際に動くJavaScriptコードに落とし込みます。
このコードは、ツールの計算ロジックを再現したものです。ブラウザの開発者ツールで実行できます。
/**
* フーリエ級数 合成波形 計算機
* 4種類の波形(矩形波・鋸波・三角波・パルス波)をサポート
* @param {string} waveType - 'square' | 'sawtooth' | 'triangle' | 'pulse'
* @param {number} N - 高調波数(1以上の整数)
* @param {number} t - 時刻(秒)
* @param {number} omega - 基本角周波数(rad/s)
* @param {number} duty - パルス波のデューティ比(0〜1, パルス波のみ使用)
* @returns {number} 合成波形の値
*/
function fourierSeries(waveType, N, t, omega, duty = 0.25) {
let sum = 0;
const wt = omega * t; // 角周波数 × 時間
switch (waveType) {
case 'square': {
// 矩形波: 奇数次正弦波のみ
for (let n = 1; n <= N; n += 2) { // n = 1, 3, 5, ...
sum += Math.sin(n * wt) / n;
}
sum *= 4 / Math.PI;
break;
}
case 'sawtooth': {
// 鋸波: 全次数、符号反転あり
for (let n = 1; n <= N; n++) { // n = 1, 2, 3, ...
sum += Math.pow(-1, n + 1) * Math.sin(n * wt) / n;
}
sum *= 2 / Math.PI;
break;
}
case 'triangle': {
// 三角波: 奇数次、係数1/n^2で急速減衰
for (let n = 1; n <= N; n += 2) { // n = 1, 3, 5, ...
const sign = Math.pow(-1, (n - 1) / 2);
sum += sign * Math.sin(n * wt) / (n * n);
}
sum *= 8 / (Math.PI * Math.PI);
break;
}
case 'pulse': {
// パルス波: デューティ比dで係数変化
for (let n = 1; n <= N; n++) { // n = 1, 2, 3, ...
const coeff = (1 - Math.cos(2 * Math.PI * n * duty)) / n;
sum += coeff * Math.sin(n * wt);
}
sum *= 2 / Math.PI;
break;
}
default:
throw new Error(`Unknown wave type: ${waveType}`);
}
return sum;
}
// 使用例: 矩形波、N=9、t=0.01秒、基本周波数50Hz
const omega = 2 * Math.PI * 50; // 角周波数
const value = fourierSeries('square', 9, 0.01, omega);
console.log(`矩形波 N=9, t=0.01s: ${value.toFixed(4)}`);
// → 出力例: 0.9876(振幅1の矩形波に近い値)
コードのポイント:
- 各波形の数式をそのままループに変換している
- 矩形波と三角波は
n += 2で奇数のみ - 鋸波とパルス波は
n++で全次数 - パルス波のデューティ比は
dutyパラメータで指定
数値例で確かめる
実際に数値を代入して計算してみましょう。
条件: 矩形波、基本周波数 $f_1 = 50\text{Hz}$、$t = 0.005\text{s}$、高調波数 $N=5$
計算:
-
角周波数: $\omega = 2\pi f_1 = 2\pi \times 50 = 100\pi \text{ rad/s}$
-
$\omega t = 100\pi \times 0.005 = 0.5\pi \text{ rad}$
-
各項を計算:
- $n=1$: $\sin(0.5\pi)/1 = \sin(90^\circ) = 1$
- $n=3$: $\sin(3 \times 0.5\pi)/3 = \sin(1.5\pi)/3 = (-1)/3 = -0.3333$
- $n=5$: $\sin(5 \times 0.5\pi)/5 = \sin(2.5\pi)/5 = 1/5 = 0.2$
-
総和: $1 - 0.3333 + 0.2 = 0.8667$
-
係数 $\frac{4}{\pi}$ を乗算: $0.8667 \times \frac{4}{\pi} \approx 1.1037$
結果: $x(0.005) \approx 1.104$
これは振幅1の矩形波の値に近い(理想値は+1)。Nが小さいため、まだ少し誤差があります。
コードで確認:
const val = fourierSeries('square', 5, 0.005, 2*Math.PI*50);
console.log(val.toFixed(4)); // → 1.1037
一致しました!
シミュレーターで遊ぶ──実験3選
実験1: ギブス現象を「目で」確認する
- 波形を矩形波に設定
- N自動増加をON
- 画面右下のオーバーシュートの数値を見ながら、Nが増えていく様子を観察
何が起きるか:
- N=1→3→5…と増えるたびに、矩形波の角の部分にピョコンと飛び出す振動が現れる
- オーバーシュートの数値は約9% でほぼ一定
- N=100にしても、N=1000にしても約9%から下がらない
これがギブス現象です。不連続点をサイン波で近似すると、どうしても約9%の飛び出しが残る。数学的に消せないんです。
実験2: 三角波と矩形波の「収束の速さ」を比較
- 矩形波でN=1→3→5→…と増やし、波形の「ガタガタ」がどれだけ残るか観察
- 次に三角波で同じことをする
何が起きるか:
- 矩形波:N=9でもリンギングが目立つ。RMS誤差も大きい
- 三角波:N=3でもかなり滑らか。N=5でほぼ完全
理由は数式にあります。矩形波の係数は $1/n$ で減衰するのに対し、三角波は $1/n^2$。高調波の影響が圧倒的に小さいからです。
実験3: パルス波の「消える高調波」を探す
- 波形をパルス波、デューティ比を0.25に設定
- N=4, 8, 12…と増やしたときの変化を観察
何が起きるか:
- N=3までは波形が変化するが、N=4にしても変化しない
- N=7までは変化するが、N=8でも変化しない
パルス波の係数 $b_n = \frac{2}{n\pi}(1-\cos 2\pi n d)$ において、$d=0.25$ のとき $\cos(2\pi n \times 0.25) = \cos(\pi n/2)$。
$n=4,8,12,...$ で $\cos(\pi n/2) = 1$ となり、$b_n = 0$。つまり、特定の高調波が完全に消えるんです。
現場でハマるポイント
1. 「Nを増やせば完全になる」はウソ
これは多くの人が勘違いするポイント。
矩形波のように不連続点がある波形では、Nをいくら増やしてもギブス現象による約9%のオーバーシュートが残ります。
実務では「完全には再現できない」ことを前提に、許容誤差を決める必要があります。
2. 打ち切り誤差との付き合い方
無限級数を有限のNで打ち切ることで生じる誤差を打ち切り誤差と呼びます。
例えばN=9の矩形波は、理論式
x_{\text{square}}(t) = \frac{4}{\pi}\sum_{n=1,3,5,...}^{\infty}\frac{\sin(n\omega t)}{n}
の $n=11$ 以降を無視している状態。
この誤差は:
- 三角波:小さい(係数が $1/n^2$ で急速減衰)
- 矩形波:大きい(係数が $1/n$ でゆっくり減衰 + リンギング)
実務の信号処理では、必要な精度と計算コストのトレードオフを考えてNを決めましょう。
3. 「基本周波数」と「波形の周期」の混同
基本周波数 $f_1 = 50\text{Hz}$ なら、その周期 $T_1 = 1/50 = 0.02\text{s}$。
合成される矩形波の周期も同じ0.02秒です。基本波1周期分の時間で、合成波形も1周期を完了します。
フェーザーの回転速度と波形の繰り返し速度が連動していることを、ツールで確認してみてください。
まとめ──3つの要点
-
フーリエ級数は「円をくるくる回す」操作の延長:各高調波をフェーザー(回転ベクトル)で表現し、その先端をつなげると波形になる
-
ギブス現象は数学的に避けられない:不連続点では約9%のオーバーシュートが残る。Nを増やしても消えない
-
波形によって収束の速さが違う:三角波($1/n^2$)は少ない高調波で実用可能。矩形波($1/n$)は多くの高調波が必要
そして何より、実際に手を動かして確かめるのが一番の近道です。
▶ フーリエ級数可視化ツール — ブラウザで即動作、登録不要
スライダーを動かし、N自動増加を押し、フェーザーの回転を眺めてみてください。数式だけでは伝わらなかった「実感」が、きっと得られるはずです。
NovaSolverでは700以上の工学シミュレーターを無料公開中 👉 一覧はこちら