FFT デモ — 高速フーリエ変換
calx の FFT モジュールは混合基数 (radix-2, 3, 5) + Bluestein で任意長に対応し、 SIMD (AVX2/SSE) による自動高速化を備える。 このページでは 4 つのデモを通じて基本操作を紹介する。 出力はすべて calx で実際に計算したものである。 ソースコードはページ末尾に掲載している。
Demo 1: 複素 FFT (順変換と逆変換)
4 点の複素データに対して FFT を実行し、逆変換で元に戻ることを確認する。
FFT<C>::fft は in-place で動作し、FFT<C>::ifft は $1/N$ 正規化を含む。
Demo 2: 実数 FFT とスペクトル解析
8 点の実数信号 $x = [1, 0, -1, 0, 1, 0, -1, 0]$ (周期 4 のコサイン波) を
RealFFT で変換し、振幅スペクトルを取得する。
出力は共役対称性を利用して $N/2+1 = 5$ ビンに圧縮される。
Demo 3: 畳み込み (FIR フィルタ)
2 つの実数配列の畳み込みを RealFFT::convolve で高速に計算する。
信号にインパルス応答を畳み込む FIR フィルタ適用と等価である。
出力サイズは $|a| + |b| - 1$。
検算: $(1 + 2x + 3x^2)(4 + 5x) = 4 + 13x + 22x^2 + 15x^3$。
畳み込みと多項式乗算は同じ演算であるが、
FFT::convolve は複素係数用、RealFFT::convolve は float / double の波形用に最適化されている。
Demo 4: 位相スペクトルとアンラップ
スペクトルの位相を phase_spectrum で取得し、
unwrap_phase で $2\pi$ のジャンプを除去して連続位相にする。
群遅延 $-d\phi/d\omega$ の計算や位相応答の可視化に必要な前処理である。
phase_spectrum は std::arg() の主値 $(-\pi, \pi]$ を返すため、
位相が $\pm\pi$ でジャンプする。unwrap_phase を適用すると
連続した位相応答が得られ、差分で群遅延を求められる。
ソースコードと実行方法
example_fft_demo.cpp (完全なソースコード)
// example_fft_demo.cpp — FFT demo
#include <math/fft/fft.hpp>
#include <math/fft/fft_utils.hpp>
#include <iostream>
#include <iomanip>
using namespace calx;
int main() {
using C = std::complex<double>;
// --- Demo 1: Complex FFT ---
std::cout << "--- Complex FFT ---\n";
std::vector<C> data = {1, 2, 3, 4};
auto orig = data;
FFT<C>::fft(data);
std::cout << "FFT: ";
for (auto& v : data) std::cout << v << " ";
std::cout << "\n";
FFT<C>::ifft(data);
std::cout << "IFFT: ";
for (auto& v : data) std::cout << v << " ";
std::cout << "\n";
// --- Demo 2: Real FFT ---
std::cout << "\n--- Real FFT ---\n";
std::vector<double> signal = {1, 0, -1, 0, 1, 0, -1, 0};
auto spec = RealFFT<double>::fft(signal);
auto amp = amplitude_spectrum<double>(spec);
for (size_t i = 0; i < spec.size(); ++i)
std::cout << "X[" << i << "] = " << spec[i]
<< " |X| = " << amp[i] << "\n";
// --- Demo 3: Convolution ---
std::cout << "\n--- Convolution ---\n";
std::vector<double> a = {1, 2, 3}, b = {4, 5};
auto c = RealFFT<double>::convolve(a, b);
std::cout << "convolve = ";
for (auto v : c) std::cout << v << " ";
std::cout << "\n";
// --- Demo 4: Phase unwrap ---
std::cout << "\n--- Phase unwrap ---\n";
std::vector<double> sig2 = {1, 0.5, 0, -0.5, -1};
auto spec2 = RealFFT<double>::fft(sig2);
auto phase = phase_spectrum<double>(spec2);
auto uphase = unwrap_phase<double>(phase);
for (size_t i = 0; i < phase.size(); ++i)
std::cout << std::fixed << std::setprecision(3)
<< " [" << i << "] " << phase[i]
<< " -> " << uphase[i] << "\n";
return 0;
}
API の詳細は FFT API リファレンス を参照のこと。
ビルドと実行
cd calx
mkdir build && cd build
cmake .. -G "Visual Studio 17 2022" -A x64
cmake --build . --config Release --target example-fft-demo
examples\Release\example-fft-demo.exe