圏9研究所 工作室

圏9研究所の開発情報資料など

STM32F411 BlackPill CMSIS-DSPによる楽器用チューナー(7)コード

計測用コードのみ記載
1.コード
1)計測
(1)<fft_peak.h>

/**
 Project Name:FFT_F4

 File Name:fft_peak.h

 Description:
 USB speaker with isochronous transfer
 Generation Information :
 Device			:  STM32F411CEU6
 Version			:  01
 Created on		: 2023/12/20
 */
/**
 Copyright (c) 2023 luke24e-hbid

 This software is released under the MIT License.
 http://opensource.org/licenses/mit-license.php
 */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef INC_FFT_PEAK_H_
#define INC_FFT_PEAK_H_

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#define ARM_MATH_CM4
#include "arm_math.h"
#include "arm_const_structs.h"
#include "arm_common_tables.h"

/* Private defines -----------------------------------------------------------*/

/* Function prototype declaration ------------------------------------------*/
//	Read FFT Data
void read_data_sin(float32_t fin);

// FFT peak detect
float32_t rfft_spline(uint32_t nfft);

#endif /* INC_FFT_PEAK_H_ */

STM32F411 BlackPill CMSIS-DSPによる楽器用チューナー(6)定数、変数、処理

1.定数一覧
1)FFT

シンボル

設定値

単位

内容

FS1

16000 = FSREAD / NK1

Hz

FFT1次サンプリング周波数

 マイク:160000 USB48000/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

FFT1powerピーク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 / NFFT4096;

サンプルデータコピー

 fft_input

nk2 個サンプル加算して1サンプル値とする

 データ数:fs2 / 4FT

 残りゼロ埋め

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[]

補間区間 = 100NSPH

 fm2Index±/2区間を補間倍率 50PSPH = 100NSPH/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ポイントのパワー値を無視する

続く

STM32F411 BlackPill CMSIS-DSPによる楽器用チューナー(4)CMSIS DSP実装

1.概要
 arm CMSIS-DSPライブラリの使用方法
 STM32CubeIDE内蔵のCMSIS-DSPはバージョンが古くスプライン補間関数が使えなかったので最新版を導入する

2.先生とお手本
1)先生
(1)CMSIS-DSP導入方法について

aptechlabs.com

ioloa.com

 

(2)スプライン補間について

qiita.com

qiita.com

https://www.rajgunesh.com/resources/downloads/numerical/cubicsplineinterpol.pdf

2)お手本
(1)FFT

klangstrom.dennisppaul.de

 

(2)スプライン補間

bbs.elecfans.com

 

3.STM32CubeIDEへの導入
1)ライブラリー入手
 STM32CubeIDE内蔵のCMSIS-DSPはバージョンが古いので最新版を導入する

(1)最新のライブラリー

github.com

  .a .lib ファイルのある最新版CMSIS 5.7.0 をdownloadする

 

2)STM32CubeIDEへの導入
 cortexM4を搭載するSTM32F411での導入例

(1)ライブラリーファイルインポート
 ARM.CMSIS.5.7.0/CMSIS/DSP/Lib/ARM/arm_cortexM4lf_math.lib
 ARM.CMSIS.5.7.0/CMSIS/DSP/Lib/GCC/libarm_cortexM4lf_math.a

(2)インクルードファイルインポート
 ARM.CMSIS.5.7.0/CMSIS/DSP/Include
  arm_math.h
  arm_const_structs.h
  arm_common_tables.h

(3)ライブラリー設定
 Librarys                arm_cortexM4lf_math
 Library search path    workspace を設定

(4)設定ハードコピー

 

4.コード例
1)三角関数

/* USER CODE BEGIN Includes */
#define ARM_MATH_CM4
#include "arm_math.h"
#include "arm_const_structs.h"
/* USER CODE END Includes */

float armsinVal = arm_sin_f32((float32_t)num*2*M_PI/255);
float armcosVal = arm_cos_f32((float32_t)num*2*M_PI/255);

STM32F411 BlackPill CMSIS-DSPによる楽器用チューナー(3)トレースサポート実装

コーディング準備

1.トレースサポート実装
1)概要
 FFTの計算結果をモニターしたいので実装する
 デバッガのトレースサポート機能を使ってstdoutをデバッガのコンソールに接続してprintf関数等で状態を表示させる
 UARTを使って外部ターミナルに表示させることもできるがST LINKだけで動作するので実装してみる

2)実装方法
(1)お手本

lujji.github.io

deepbluembedded.com

moons.link

(2)手順
 詳細はお手本に詳しく記載されているので概要のみ
 ・ mini ST-LINK V2 からSWO線を引き出しPB3に接続する
 ・STM32CubeMXでトレース設定する
 ・stdoutをリダイレクトしprintf関数等をコーディングする
 ・デバッガのコンソールを設定する
 ・デバッグ実行

2.補足解説
1)コード
 最後のお手本のコードがシンプル

2) mini ST-LINK V2 改造
  難関の引き出し線はんだ付け手順について補足
 ・ICピンピッチ0.5mmのためはんだ付けが難しい
 ・導線 導線径がピンピッチの半分程度の単線を使う
     AWG30 ラッピングワイヤーとかUEW 0.26 ポリウレタン銅線とか
 ・導線端全周漏れなくはんだ上げする
  ポリウレタン銅線の被覆除去はムラが出ないようにはんだごての温度は高め
 ・導線を基板に仮固定する
  作業中に導線端がICピンから浮いたりズレたりしないように固定
 ・フラックスを塗る
 ・薄くハンダをのせたはんだごてを当てる
  フラックスを塗っておけばブリッジしにくいので隣接するピンに当てても大丈夫
  ブリッジした場合はこて先のハンダを除去しフラックスを塗り直して再度はんだごてを当てる
 ・アルコールで洗浄する
  筆とか歯ブラシを使うとやりやすい
 ・ルーペではんだの状態を確認する
 ・導線を接着剤等で基板に固定する

続く

STM32F411 BlackPill CMSIS-DSPによる楽器用チューナー(2)仕様・課題・処理

目標仕様と課題及び処理方法について

1.目標仕様

項目

目標値

備考

用途

弦楽器の調弦

弦を使うピアノも含む

計測値

音名、セント値

オクターブ値は実用上必要ないので参考値とする

計測範囲

55[Hz]〜880[Hz]

下限がベース下限周波数より高いが下記により選定

・使用するマイクの帯域下限が50Hz

倍音で計測しオクターブ値は参考

計測精度

±1[セント]

セント値=1200log2(計測周波数/基準周波数)

計測周波数=基準周波数・2^(セント値/1200)

サンプリング周期

250[msec]

4/ サンプリング設定と使いやすさの相関から選定

2.課題と対策
1)基音
(1)課題
 ・基音より強い倍音が存在する場合がある
 ・計測したい基音周波数が計測範囲外にある
(2)対策
 ・特許公報H3-10118より
  最も大きなスペクトル値よりも30dB程度の範囲内で小さなスペクトル値を示す周波数成分の周波数を基音として判定する
 ・計測範囲外の基音については2次高調波と3次高調波の差または3次高調波と4次高調波の差を基音周波数とする

2)計測精度
(1)課題
 ・CMSIS-DPS Real FFTライブラリーの最大ポイント数4096では分割ピッチが目標計測精度より荒い
  分割ピッチ=サンプリング周波数/4096
(2)対策
 ・サンプリング周波数を基音に対して可変させて分割ピッチを最適化する
 ・スプライン補間で誤差を少なくする

3.処理方法

処理

手順

詳細

データサンプリンング

計測:内蔵ADC

サンプリング周波数 16,000[Hz]

分解能 12bit

読込 DMA

デバッグ

USB Speaker

サンプリング周波数 48,000[Hz] / 3

分解能 16bit / 16

読込 USB Speaker ISO プロジェクト流用

基音判定

CMSIS Real FFT 1回目

R FFT計算

各ポイントのパワー計算

ピークパワーポイント選定

 ピーク平均値の2倍以下はピーク判定から除外

 大きい順に2個選定

if ピークパワーポイント最小値≒ピークパワーポイント間隔

 基音=ピークパワーポイント最小値

 ピークパワーポイントの次数=1

else

 基音=ピークパワーポイント間隔

 スプライン補間で使用するピークパワーポイントの次数を計算

基音周波数計測

サンプリング周波数最適化

2回目サンプリング周波数 = 125 * 2 ^ xn

xn は2回目サンプリング周波数が基音周波数の概略16倍となる整数

CMSIS Real FFT 2回目

サンプリング周波数を変更

R FFT計算

各ポイントのパワー計算

CMSIS Spline Interpolation

基音またはR FFTピークパワーポイントを中央としてスプライン補間

補間したピークパワーポイントを抽出

基音周波数計算

基音周波数=スプライン補間ピーク周波数/次数

4.解説
1)サンプリング周波数
(1)周波数選定
FFTポイント数の倍数が処理しやすいがデバッグで使う48kHzとサンプリング周期をもとに選定

(2)サンプリング最適化周波数
・理論的には計測周波数の2倍以上と言われているが16倍にしている
・倍率を下げればFFT分割ピッチがより小さくなり計測精度が上がる
・現状実精度は目標値と同等レベルとなっているが音源の音程が揺れるため正確な検定は難しい

2)オクターブ値
調弦する場合オクターブ値は必要ないので計測を省略している
FFT1回目でピークポイントをより多く抽出して基音判定精度を上げればより正確にオクターブ値を計測できる

3)FFTパワー計測例
 高調波パワーが大きい場合
 Cello C弦 C1 : 65.406[Hz]

続く

STM32F411 BlackPill CMSIS-DSPによる楽器用チューナー(1)概要

1.概要
 ARM社のCMSIS-DSPライブラリーを使ってSTM32F411 Cortec-M4で楽器用チューナーを作ってみる

 表示イメージ:YAMAHA TD-90
  音名、周波数等はOLEDで表示

2.チューナー構成
1)構成と課題
 チューナーは周波数カウンターで出来ています
 楽器の音には多くの倍音成分が含まれていてシンプルな周波数カウンターでは聴感と異なる測定結果となる場合がある
 このため聴感上の基音となる周波数を識別して計測しなければならない

2)構成例
 特許公報から3種類抜粋
(1)特許公報 平3-42412
 発明の名称    ピッチ測定装置及び方法
 出願日        1982年12月13日 優先権主張 1981年12月14日 US330681
 概略        波形のゼロクロス極性と周期の相関により基音成分を抽出識別して周波数を計測する

(2)特許公報 6225818
 発明の名称    ピッチ情報生成装置、ピッチ情報生成方法、及びプログラム
 出願日        2014年4月30日
 概略        エンベロープ波形を生成して基音成分を抽出識別して周波数を計測する

(3)特許公報 H3-10118
 発明の名称    音符の表示装置
 出願日        1983年1月26日
 概略        FFTパワースペクトルで基音を抽出識別する

3.チューナー構成選定
 CMSIS-DSPライブラリーを使ってみることが目的でもあるためFFTで計測する

4.解説
・楽器用チューナーはシンプルな周波数計測とは異なり人間の聴感の基づく計測が必要なため難易度が高い
・従来の手法ではアナログ的なパターンマッチング法とデジタル的なFFT分析法がある
・40年以上前の技術で実用上スマホアプリで十分
・今回はCMSIS-DSPライブラリーの導入を主な目的とする
・特許公報は下のリンクから

www.j-platpat.inpit.go.jp

続く