1.定数一覧
1)FFT
シンボル
|
設定値
|
単位
|
内容
|
FS1
|
16000 = FSREAD / NK1
|
Hz
|
FFT1次サンプリング周波数
マイク:160000 USB:48000/3
|
FT
|
4 (250msec)
|
Hz
|
1/サンプリング時間
|
NS1
|
4000 = FS1 / FT
|
|
読込サンプル数
|
NFFT
|
4096
|
|
FFTサンプル数
|
NPOWER
|
2048 = NFFT / 2
|
|
FFT Power サンプル数
|
FRESO1
|
FS1 / NFFT
|
Hz
|
FFT1次周波数ピッチ
|
FKMIN
|
55.0
|
Hz
|
計測下限周波数
|
FKMAX
|
880.0
|
Hz
|
計測上限周波数
|
PKMIN
|
1000000 * NK1
|
|
計測下限Power(無音レベル)
|
PKK
|
2
|
|
ピーク前後除去係数(Power平均値に掛ける値)
|
2)スプライン
シンボル
|
設定値
|
単位
|
内容
|
NSPS
|
12
|
|
サンプル数 FFTピーク±6相当
|
NSPH
|
100
|
|
補間数
|
PSPH
|
50 = NSPS / 2
|
|
補間倍率 = 1/補間ピッチ = NSPH / 2
|
2.変数一覧
1)FFT
変数名
|
G/L
|
内容
|
uint16_t data_sample[4096 * 2]
|
G
|
読込サンプルデータ 4000個 / 250msec
|
arm_rfft_fast_instance_f32 fft;
|
L
|
RFFT計算
|
float32_t fft_input[NFFT];
|
L
|
float32_t fft_output[NFFT];
|
L
|
float32_t fft_power[NFFT / 2];
|
L
|
uint8_t ifftFlag = 0;
|
L
|
float32_t maxValue;
|
L
|
arm_max_f32 引数
|
uint32_t maxIndex;
|
L
|
2)スプライン
変数名
|
G/L
|
内容
|
arm_spline_instance_f32 S;
|
L
|
スプライン係数
|
arm_spline_type type = ARM_SPLINE_NATURAL;
|
L
|
float32_t x[NSPS];
|
L
|
float32_t y[NSPS];
|
L
|
uint32_t n = NSPS;
|
L
|
float32_t coeffs[3 * (NSPS - 1)];
|
L
|
float32_t tempBuffer[2 * (NSPS - 1)];
|
L
|
float32_t xq[NSPH];
|
L
|
スプライン補間
|
float32_t pDst[NSPH];
|
L
|
uint32_t blockSize = NSPH;
|
L
|
float32_t maxValue_s;
|
L
|
arm_max_f32 引数
|
uint32_t maxIndex_S;
|
L
|
3)計測計算
処理
|
変数名
|
G/L
|
内容
|
FFT1次計算
|
float32_t avg_power
|
L
|
FFT power平均値
|
float32_t fm1_01, fm1_02
|
L
|
FFT1次powerピーク01, 02
|
uint32_t fm1Index_01, fm1Index_02
|
L
|
fm1_01, fm1_02の fft_powerインデックス
|
float32_t fm1
|
L
|
FFT1次計測周波数 fm1=基音*fm1_multi
|
uint32_t fm1Index
|
L
|
fm1の fft_powerインデックス
|
uint32_t fm1_multi
|
L
|
fm1基音の倍数
|
FFT2次準備
|
float32_t xn
|
L
|
サンプリング変換係数
|
float32_t fs2
|
L
|
FFT2次サンプリング周波数
|
float32_t freso2
|
L
|
FFT2次周波数ピッチ
|
uint32_t nk2
|
L
|
fs1 / fs2 サンプリング周波数比
|
FFT2次計算
|
float32_t fm2
|
L
|
FFT2次計測周波数
|
スプライン
|
float32_t fmspl
|
L
|
スプライン補間計測周波数
fmspl=スプライン補間値 / fm1_multi
|
セント値計算
|
int16_t oct_cent
|
L
|
オクターブセント値 1[oct] = 1200[cent]
|
int16_t cent1200
|
L
|
セント値:0 - 1199
|
int16_t note
|
L
|
音階値:0 - 11
|
int16_t cent
|
L
|
表示セント値:±50
|
3.計測手順
1)FFT 1次
処理
|
手順
|
サンプルデータコピー
|
fft_input[0-3999] = sample_data[0-3999]
|
不足分ゼロ埋め
|
fft_input[4000-4095] = {0}
|
FFT計算
|
arm_rfft_fast_init_f32(&fft, NFFT);
arm_rfft_fast_f32(&fft, fft_input, fft_output, ifftFlag);
arm_cmplx_mag_f32(fft_output, fft_power, NFFT / 2);
|
0Hz値をゼロに
|
fft_power[0] = 0
|
fft_power 平均値算出
|
arm_mean_f32
|
ゼロ埋め
|
・計測範囲外 55Hz(55 / FRESO1)<, >880Hz(880 / FRESO1)
・fft_power < 平均値 * 2(PKK)
・fft_power < 無音レベル(PKMIN)
|
ピーク検出 1回目
fm1_01
fm1Index_01
|
arm_max_f32
ピーク前後 fft_power==0 までゼロ埋め
ピークIndex 2.5倍以上ゼロ埋め
|
ピーク検出 2回目
fm1_02
fm1Index_02
|
arm_max_f32
|
ピーク値1,2ソート
|
Index小さい順
|
計測周波数決定
fm1
fm1Index
fm1_multi
|
if power[fm1Index_01]==0 エラー
fm1_multi = 1
if power[fm1Index_02]==0 fm1Index=fm1Index_01
else
if fm1Index_01 * 2 == fm1Index_02±1 fm1Index=fm1Index_01
else
fm1Index = fm1Index_01
fm1_multi = fm1Index_01 / (fm1Index_02 - fm1Index_01)
fm1 = (float32_t)fm1Index * FRESO1
|
2)FFT 2次
処理
|
手順
|
2次サンプリング周波数
と周波数比計算
fs2, nk2, freso2
|
xn = (log(fm1 * 16) – log125)/log2
fs2 = 125 * 2 ^ xn
nk2 = fs1 / fs2
freso2 = fs2 / NFFT:4096;
|
サンプルデータコピー
fft_input
|
nk2 個サンプル加算して1サンプル値とする
データ数:fs2 / 4:FT
残りゼロ埋め
|
FFT計算
|
FFT 1次と同じ
|
ピーク検出
fm2
fm2Index
|
fm1Index±2 相当の間のピーク fm2Index を探す
(fm1Index – 2)*nk2 < 検索 < (fm1Index + 2)*nk2
fm2 = (float32_t)fm2Index * freso2 / fm1_multi;
|
3)スプライン補間
処理
|
手順
|
スプライン係数計算データ
x
y
|
インデックス範囲:maxIndex ±6
データ数:12 = NSPS
|
スプライン補間 x値
xq[]
|
補間区間数 = 100:NSPH
fm2Index±1/2区間を補間倍率 50:PSPH = 100:NSPH/2で補間値算出
|
スプライン計算
|
arm_spline_init_f32(&S, type, x, y, n, coeffs, tempBuffer);
arm_spline_f32(&S, xq, pDst, blockSize);
|
ピーク検出
fmspl
|
・arm_max 補間値yピーク値抽出
・計測周波数算出
fmspl = xq[maxIndex_s] * freso2 / fm1_multi
|
4.表示計算
1)オクターブ値、セント値計算
(1)基本計算式
基準周波数 = 27.5[Hz] A0
オクターブセント:oct_cent = 1200 * log(fmspl / 27.5) / log(2)
セント値 :cent1200 = oct_cent % 1200
音階値 :note = cent1200 / 100
表示セント値 :cent = cent1200 % 100
(2)表示用計算式
表示セント値範囲を±50 符号付にする
基準周波数 = 27.5[Hz] A0
オクターブセント:oct_cent = (int16_t)(1200 * log(fmspl / 27.5) / log(2) + 50.5)
セント値 :cent1200 = oct_cent % 1200
音階値 :note = cent1200 / 100
表示セント値 :cent = cent1200 % 100 - 50
5.補足:マイクアンプとFFT計算
1)マイクアンプ
(1)仕様
・購入先 秋月
・品名 高感度マイクアンプキット
・販売コード 105757
・種別 コンデンサーマイク
・電源電圧 2.5V〜5V
・周波数 50Hz〜6kHz
・出力 0V〜VCC
・DCオフセット 約VCC/2
(2)電源ノイズ対策
VCC/2を仮想グランドとしていることもあり電源ノイズの影響が大きく未対策では計測レンジを小さくしなければならない
マイクアンプの電源にはマイクロインダクター47mHを使ったパイ型フィルターを付けた
2)FFT計算データ処理
(1)DCオフセット対策
DCオフセット相当量は0HzポイントのFFTパワー値に加算される
対策
・AD変換値は加工せずFFT計算し0Hzポイントのパワー値を無視する
今回0Hzポイントは計測範囲外のためこの方法を採用
・各AD変換値からDCオフセット相当量を引き算した後FFT計算する
・各AD変換値からAD変換値の平均値を引き算した後FFT計算する
(2)サンプリング値不足対策
サンプリング周波数とFFTサンプル数の不一致対策
・不足するFFTサンプル値をゼロで埋める
・ゼロで埋めた分は0HzポイントのFFTパワー値に加算されるため0Hzポイントのパワー値を無視する
続く