Q2557-10:ハードウェアFFTの速度はどれくらい出るのか?
今回のトピック
ロームのマイコン「ML63Q2500」シリーズはAI処理向けのペリフェラルが載っています。この中にFFTの機能があり、入力データ数は最大1024個、窓関数無しかハニング窓を選択できるようになっていて、しかもこれをハードウェアで実行します。
ペリフェラルでFFTを実行している間はCPUの手が空くので、ビジーフラグをポーリングするか割り込みを設定して他の処理に移ることができます。そうすると気になるのが、実際のFFT処理はどれくらいの時間で終わるのか? というところです。
今回は32kHzの水晶振動子を使って48MHzのクロックを生成し、入力データ数を変化させたときの処理時間を実測しました。AI処理の実行にもシステムクロックが使用されるので、MCUのクロックを下げるとFFTの実行速度も落ちてしまいます。
テストに使用したコード
サンプルソースコードの「FftSample」を手直しして1024個の入力データを用意、窓関数無しとハニング窓の時のFFTに関わる一連の処理を実行し、LEDが接続されたポートにパルスを出力します。時間を測り終えたらブレークをかけて入出力サイズ(size, ysize)を徐々に減らしていき、プログラムを再開して時間を測る、という作業を繰り返します。
#include "data/fft_input1024.h"
void FFT_Test(void) {
bfloat16 x[sizeof(fft_input64) / sizeof(fft_input64[0])];
uint16_t size = sizeof(x) / sizeof(x[0]); // 入力データ数
uint16_t ysize = size / 2 + 1; // 出力データ数
while(1) {
// 窓なし
smpl_offLED1();
ODL_ToBfloat16(x, fft_input64, 12U, size);
fft_Init(size, FFT_WINDOW_NONE);
fft_Start(x, size);
while (fft_IsBusy()) {
__NOP();
}
fft_GetResult(y, ysize);
wdt_clear();
// ハニング窓
smpl_onLED1();
ODL_ToBfloat16(x, fft_input64, 12U, size);
fft_Init(size, FFT_WINDOW_HANN);
fft_Start(x, size);
while (fft_IsBusy()) {
__NOP();
}
fft_GetResult(y, ysize);
wdt_clear();
}
}
測定結果
| 入力サイズ(size) | 出力サイズ(ysize) | 窓なし | ハニング窓 |
|---|---|---|---|
| 2 | 2 | 0.3ms | 0.36ms |
| 4 | 3 | 0.4ms | 0.45ms |
| 8 | 5 | 0.6ms | 0.65ms |
| 16 | 9 | 0.86ms | 0.92ms |
| 32 | 17 | 1.12ms | 1.19ms |
| 64 | 33 | 1.54ms | 1.62ms |
| 128 | 65 | 2.12ms | 2.24ms |
| 256 | 129 | 3.35ms | 3.52ms |
| 512 | 257 | 5.56ms | 5.82ms |
| 1024 | 513 | 10.74ms | 11.24ms |
あれ?結構速くね?FPUを持ってないCortex-M0+の速度じゃないよねこれ。
FFTの処理に限定するとどれくらいの速度が出ているのか?
先のプログラムではFFTの処理以外にFFTエンジンが受け付けるデータへの変換、FFTの結果データの読み出しが付随していました。実際に利用する場合はこの結果を基準にプログラムを作ることになるのですが、FFTそのものの速度はいったいどれくらいなのか? という興味本位のテストもやってみました。FFTの結果を取り出さない意味のないテストですが、お付き合いください。
#include "data/fft_input1024.h"
void FFT_Test(void) {
bfloat16 x[sizeof(fft_input64) / sizeof(fft_input64[0])];
uint16_t size = sizeof(x) / sizeof(x[0]); // 入力データ数
ODL_ToBfloat16(x, fft_input64, 12U, size);
fft_Init(size, FFT_WINDOW_NONE); // もしくはFFT_WINDOW_HANN
while(1) {
smpl_offLED1();
fft_Start(x, size);
while (fft_IsBusy()) {
__NOP();
}
wdt_clear();
smpl_onLED1();
fft_Start(x, size);
while (fft_IsBusy()) {
__NOP();
}
wdt_clear();
}
}
測定結果 (fft_Startとビジーポーリングのみ)
| 入力サイズ(size) | 窓なし | ハニング窓 |
|---|---|---|
| 2 | 0.018ms | 0.021ms |
| 4 | 0.027ms | 0.031ms |
| 8 | 0.045ms | 0.05ms |
| 16 | 0.086ms | 0.094ms |
| 32 | 0.158ms | 0.172ms |
| 64 | 0.34ms | 0.37ms |
| 128 | 0.71ms | 0.76ms |
| 256 | 1.63ms | 1.73ms |
| 512 | 3.48ms | 3.65ms |
| 1024 | 7.92ms | 8.3ms |
あぁ^~これは速いわぁ^~
今回のまとめ
- ハードウェア処理は意外と速い
- 上手いプログラムを作れる人なら音声帯域くらいのリアルタイム処理が可能かも
- 無理やり2048とか大きなデータを突っ込むとハードフォルトが起きてCPUが再起動する
- UARTがstdio.hの出力ストリームとして使われていた。どういう仕組みなのかが気になる
Discussion