小型IoT端末開発キット「SensorTile.box」 をセンサ・アプリで使ってみた④　音声FFT


今回はST BLE Sensorアプリをカスタマイズして、MEMSマイク（音響センサ）を使ったアプリを作成してみます。カスタム・アプリはExpert Modeで作成可能です。Expert modeの概要については前回記事を参照してください。
[小型IoT端末開発キット「SensorTile.box」 をセンサ･アプリで使ってみた③　振動FFT](https://qiita.com/ykawano/items/e45390b235e9f54d4ea8)

SensorTile.boxのセットアップ方法および基本情報についてはこちらの記事を参照してください。
[小型IoT端末開発キット「SensorTile.box」 をセンサ･アプリで使ってみた①　セットアップと使い方](https://qiita.com/ykawano/items/9aed0be1ca919ad4551d)


![00_overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/0ad136b7-0c38-8015-8f01-773ae3bd63bb.png)



## 1．MEMSマイク（音響センサ）

SensorTile.boxには、アナログMEMSマイク（[MP23ABS1](https://www.st.com/ja/mems-and-sensors/mp23abs1.html)）が搭載されています。今回はこちらのマイクを使用します。

![10_Board&Mic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/0d8acfac-18c3-9b27-fc2f-5d4ee68148be.png)

![11_mic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/6fe5fd78-4d36-dac6-5942-0f5d8cc7bd4c.png)



MEMSマイクには **“デジタル”** と **“アナログ”** がありますが、これはインタフェースの違いで基本的に中身の構造は同じです。SensorTile.box内のマイクはアナログ･インタフェース･タイプなので、STM32マイコン側との入力接続ポートとしてはADCポート（ADコンバータ）を使用しています。また、マイクとの間にオペアンプが必要です。いわゆる一般的なコンデンサ･マイクと同じ接続方法になります。

![12_block.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/eabdc5a3-f555-6c35-2ea4-a8dac7a78105.png)







## 2．サウンドレベル・モニタ
それでは実際に、MEMSマイクを使ったアプリを作成していきましょう。最初に基本的なサウンドレベル･モニタを作成します。
マイク入力レベルを、リアルタイムにグラフ表示するアプリです。
音声レベルが時間軸ベースにデシベル（dB）で出力されます。1秒間に数十サンプリング程度でグラフプロットされますので、レベルメータ的な使い方ができます。

### 2-1．セットアップ
以下内容でカスタム･アプリをセットアップしてみます。

・入力センサ: **Microphone（MP23ABS1）**
・ファンクション: **無し**
・出力データ先: **Bluetooth®経由でスマホへ**
スマホのST BLE Sensorアプリを起動して以下手順でExpert modeに入り、新規アプリ作成用のページに移動します。



![21_AppSetup1_miclevel_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/18753a75-f522-9e95-93a2-9917f29ddd4c.png)


##### 入力センサ: Microphone

まずは入力センサとしてMicrophoneを選択します。
念のため詳細設定ページに移動してみると、サンプリング周波数（ここではODR（OUTPUT DATA RATE）と表示）が16000Hzとなっているのがわかります。つまり、取り扱える音の帯域としてはサンプリング周波数の半分の約8kHzより下の周波数帯域が対象になります。ここをクリックしても他の数値は選べず、アプリ上では今のところ変更できないようです。


![22_AppSetup2_miclevel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/cf4edbf1-4bd5-24e5-2145-1180ed16bd63.png)



##### ファンクション: なし
ソフト仕様上、ファンクションは設定しません。

##### 出力: Bluetoothでスマホへ

スマホ側でデータを受信するようにします。最後にアプリ名を入力して保存します。ここでは“mic level”としました。



![23_AppSetup3_miclevel__.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/c64d40ae-5b14-1714-b601-74283d3cb4fc.png)




アプリをアップロード後、スマホとBluetooth接続します。




![24_AppConnect_miclevel_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/91435c24-264f-6e9e-70a3-7fedf22fd8dd.png)



##### 設定まとめ

|           |選択アイテム        | 設定内容  |
|:------------:|:---------:|:--------:|
|Input  |Microphone（MP23ABS1）|ODR = 16000Hz（変更不可）|
|Function  |無し||
|Output  |Stream to Bluetooth|Bluetooth経由でスマホへ演算結果送信|


### 2-2．動作確認


接続後、Playボタンクリックでプロット開始です。サウンドレベルをリアルタイムで確認できます。右上のメニューからログ保存も可能です。全アプリ共通ですが、グラフプロット動作中にログスタート & ストップ操作をします（グラフ停止中に操作してもログ記録されません）。






![25_AppConnect_miclevel_plot_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/9b29019c-3bc6-2de5-bcda-3b15575917b4.png)


ログ保存操作後、スマホ内のSTMicroelectronics>logsフォルダ以下を見ると、csvファイルが保存されていました。


![26_miclevel_file.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/4cd5d049-da15-86c1-3c58-4256b63bb271.png)



1秒間に30回ほどのサウンドレベル･データ（dB）が送信されてきているようです。このデータレートは変更できません。


![27_result_excel_1k.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/656ccb7d-2f94-8155-977c-e1bc541bf045.png)





##### 補足
このアプリ作成時はファンクションを設定しませんでしたが、サウンドレベルdBを算出するにあたっては、**Sound MeteR（SMR）** ライブラリを使用しています。関連するサンプルコードは、STM32用オーディオ･プロセッシング･パッケージ[「X-CUBE-AUDIO」](https://www.st.com/ja/embedded-software/x-cube-audio.html)で提供されているので、興味のある方は参考にしてください。

ちなみに、出力先をFile to SD cardにすると、一般的なPCMオーディオ･ファイルとして記録されました（WAVEファイル / 16bitモノラル、16kHz）。ファンクションを同じ“無し”設定にした場合でも、出力設定によって得られるデータ･タイプが異なりますが、ソフト & ハード仕様によるものと思われます。
マイクを入力として選択した場合、現時点では以下ファンクションを利用できます。冒頭で紹介した[「振動FFT」（記事③）](https://qiita.com/ykawano/items/e45390b235e9f54d4ea8)の際も経験しましたが、AVG（Average）を選択するとうまく動作しません。



|Function            |機能        |Note   |
|:------------:|:---------:|:--------:|
|無し  |SMRライブラリが自動で追加され、サウンドレベルを約30ODRで送信|出力設定 = Stream to Bluetooth|
|無し  |音声データを直接録音（16bitモノラル、16kHz）|出力設定: = File to SD card|
|ARMA  |Auto Regressive Moving Average: 自己回帰移動平均モデル|フィルタ係数設定が難しいため省略|
|FFT  |FFT演算|この記事でチェック|
|AVG  |平均値|動作せず|
|Baby Crying  |赤ちゃん鳴き声検知（AI）|未検証|





## 3．音声FFT

次に音声FFTをグラフ表示させるアプリを作成します。加速度センサを使った振動FFTの時と同じく、SesnorTile.box側でFFT演算を行うので、結果だけをBluetoothで受け取ります。

### 3-1．セットアップ


以下内容でカスタム･アプリをセットアップしてみます。
　　・入力センサ: **Microphone（MP23ABS1）**
　　・ファンクション: **FFT**
　　・出力データ先: **Bluetooth経由でスマホへ**

サウンドレベル・モニタ作成時と同様に、Expert Modeから新規アプリ作成用のページに移動後、以下手順ですすめていきます。


![31_AppSetup1_FFT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/42d71475-8e0d-9585-a0a6-8533fb9b825e.png)


FFTファンクションのパラメータ（Frequencies to produce）は、いわゆるFFT演算時におけるポイント数です。数字が大きいほど細かい周波数ステップでの出力を得られます。ここではデフォルト値の256のままとします。
Frequencies to produceは以下から選択可能です。

 - 16
 - 64
 - 256 (デフォルト)
 - 1024



![32_AppSetup2_FFT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/94910806-a409-84e5-64a4-b250a4169f90.png)



作成後、アプリ名を入力 & 保存して再接続します。ここでは、“mic fft”としました。




![33_AppConnect_FFT_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/8f2bb3db-46d4-9a08-6f6a-5e6ffe316d30.png)


#### 設定まとめ

|            |選択アイテム        | 設定内容  |
|:------------:|:---------:|:--------:|
|Input  |Microphone（MP23ABS1）|ODR = 16000Hz（変更不可）|
|Function  |FFT|Frequencies to produce = 256 --> 16 / 64 / 256 / 1024より選択可能（デフォルトは256)|
|Output  |Stream to Bluetooth|Bluetooth経由でスマホへ演算結果送信|


### 3-2．動作確認

接続後、すぐにFFTプロット表示を開始します。右上のメニューからログ保存も可能です。




![34_AppConnect_FFT_play_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/5f9ffe57-ec4c-4fe9-fa13-d79dad4d59f0.png)


テスト用の音出しにはフリー･ツールの[WaveGene](https://efu.jp.net/soft/wg/wg.html?_sm_au_=iQWZMZ346S365PF5cLpsvK618Vf61)を使いました。パソコンにアンプ付きスピーカを接続し、SensorTile.boxをそばに置いて確認します。

![35_PC+Speaker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/b7e9ddd6-de04-6598-2c85-bd4f21138f86.png)


1kHzのSine波音声を出力させてみましたが、およそ1kHzの箇所にピークが出ているのがわかります。
ログを取ってcsvファイルを確認してみると、ピークが出ているのは“992Hz”表記ラベルの箇所でした。



![35_result_FFT_256_1k.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/5b21360b-583f-4434-365f-9e0ea41784c8.png)


Frequencies to produce = 256とした場合、62.5Hz/stepとなるはずですが（16000/256 = 62.5Hz）、csvログデータ見ると、“Frequency”のカラムは62Hz stepとなっています（小数点を切り下げられている。0から始まり、62ステップで0, 62, 124, 186,...7874Hzまでの128ライン）。
ライン数は合っていますが、ログファイル内の周波数ラベル表記はおそらく違っているものと推測します。実際は62.5ステップで、0, 62.5, 125, 187.5,...7937.5Hzに相当するはずです。“992”（= 62 * 16）についても実際は“62.5 * 16 = 1000Hz”に該当するデータとみて良さそうです。
256設定で記録したログファイルを見る場合は注意してください。


試しにFrequencies to produce = 64として同じようにログを取ってみました。
こちらは16000/64 = 250Hzと割り切れるので、csvファイルの周波数ラベルは合っている模様。
1kHz、2kHz、3kHz、…のSine波音声で同じように試しましたが、こちらの設定ではきっちり合っています。
（以下は2kHz Sine波取り込み時の様子）


![36_result_FFT_64_2k.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/339bd74f-470b-a00e-8e45-84390fafc695.png)





## 4．音声FFT＋周波数検出

#### FFT結果を利用できる？

比較用ファンクションを追加することで、特定の周波数が一定スレッショルド（しきい値）を越えたかどうかを検出できるようにします。ここではFFT Line Compareを使います。


|Available Function             |パラメータ         |        |
|:-----------:|:---------:|:--------:|
|FFT Line Compare |Line to compare, Threshold|ラインポイントで比較|
|FFT Compare|Name file FFT to compare, Number of lines to compare, Threshold|マスタ･ファイルと比較|


FFT Compareを利用する場合、比較元のマスタ･ファイル･データが必要です。試しにいくつか保存したファイルを使ってみたところ、正しく比較されているかどうかわからなかったので、今回の記事では省略します。


### 4-1．セットアップ

先ほど作成した**mic fft**アプリを再利用します。FFTファンクションの下にもうひとつ比較判定用ファンクション“FFT Line Compare”を追加します。




![41_AppSetup1_FFT+comp_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/1052e85f-0f3d-c85b-a0ff-d0edda2a7a17.png)


追加したFFT Line Compareファンクションについて、パラメータを設定します。詳細は後述しますが、テスト用として比較周波数を5kHzに仮設定するためにLine to Compare = “80”と入力します。


![42_AppSetup2_FFT+comp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/bf4dabda-cbbf-2cef-c68b-e28376f799cb.png)




最初、Line to Compareの数値をどう設定したらいいか迷いましたが、ここでは「比較する周波数ラインポイント」を設定するようです。Frequencies to produceのところで設定した数値をFFTにおけるサンプリングポイント数と考えると、これと同数の周波数係数（つまり、得たいデータ）が算出されるはずです。

なお、**mic fft**アプリを流用しているので、このポイント数は256です。周波数ステップはサンプリング周波数を分割していけばいいので、256ポイント設定の場合、16kHz/256 = 62.5Hzごとのラインになります。仮にLine to Compare =”80”とした場合、62.5*80 = 5000、つまり5kHzが比較周波数ポイントになります。

FFTファンクション→Frequencies to produceのところで選択した数値によってこの周波数ポイントは変わるため、少し注意が必要です。


|Frequencies to produce   |1周波数ライン・ステップ Hz  | Line to Compare設定範囲 |
|:-----------:|:---------:|:--------:|
|16 |1000 (16000/16)|0~7|
|64|250 (16000/64)|0~31|
|256|62.5 (16000/256)|0~127|
|1024|15.625 (16000/1024)|0~511|

各Frequencies to produceの設定値における比較周波数の目安は以下のテーブルを参考にしてください。

**Line to Compare設定**

|比較したい周波数 Hz   |FP = 16  |FP = 64 |FP = 256 |FP = 1024 |
|:-----------:|:---------:|:--------:|:---------:|:--------:|
|15.625 |---|---|---|1|
|62.5 |---|---|1|4|
|250 |---|1|4|16|
|1000|1|4|16|64|
|2000|2|8|32|128|
|3000|3|12|48|192|
|4000|4|16|64|256|
|5000|5|20|80|320|
|6000|6|24|96|384|
|7000|7|28|112|448|
|上限|7->7000Hz|31->7750Hz|127->7937.5Hz|511->7984.4Hz|

（FP: Frequencies to produce）

ここでは、全てにおいてサンプリング周波数の半分以降の周波数係数は無視されるので、設定される比較周波数が16k/2 = 8kHzより小さくなる必要があります。つまり上限目安としては、 **“選択したFrequencies to produce数値の半分 - 1”** となります。

Thresholdの単位はdBです。ここでは便宜的に40dBとします。
設定が終わったら全体セーブして準備完了です。アプリ名を別名にすれば新規アプリとして登録されます。今回は“mic fft comp”としました。続いてアプリをアップロードして再接続しましょう。




![43_AppSetup3_FFT+comp_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/caf1a5eb-4968-c664-e769-e5ac1066d036.png)



#### 設定まとめ

|            |選択アイテム       | 設定内容  |
|:------------:|:---------:|:--------:|
|Input  |Microphone（MP23ABS1）|（ODR = 16000Hz）|
|Function  |FFT|Frequencies to produce = 256|
|Function  |FFT Line Compare|Line to compare = 80, Threshold = 40|
|Output  |Stream to Bluetooth|Bluetooth経由でスマホへ演算結果送信|


### 4-2．動作確認

ではさっそく、実際に音を出して試してみます。


信号波形はSine波とし、周波数を1kHz、2kHz・・・と変えながらチェックすると、5kHzの時に正しく反応しました。

![46_result_pic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/e1c5dab2-dd8d-6e28-20db-7ddd1c4eccec.png)




次に周波数をもう少し細かくスイープさせながら観察したところ、おおよそ±200Hzの範囲で検出できていることがわかりました。

なお、この結果は当然ながらスレッショルドの設定およびSensorTile.Boxをスピーカからどの程度の距離に置くかによっても変動します。



#### Frequencies to produce = 16、64の場合

FFTのFrequencies to produceを小さくすると、FFTの周波数stepが粗くなります。
Frequencies to produce = 16の場合、およそ±1000Hzくらいの幅で検出されました。例えば4kHzのラインポイントで設定しても、約3kHz～5kHzの音は反応しており、かなりアバウトです。あまりに粗いとおおざっぱな反応になってしまうようです。

出力Sine波を10Hzきざみで調整しながら、それぞれの設定条件で反応する周波数範囲を調べました。


![48_result_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/dec7a9ca-4a3e-a7a5-6ed6-1cbbfe00cee6.png)








FP = 64と256の時は、（スレッショルドの設定およびスピーカとの距離でも変わるので注意）両設定ともに±200Hz程度の範囲で検出できることが確認できたので、この程度の精度で問題ない用途であれば使えそうです。
1024設定時については、FFTそのものがうまく動作しなかったので今回は省略します。

## 5．FFTライブラリについて

SensorTile.box内ソフトウェアで処理している今回の音声データ用のFFTは、Arm社から標準規格として用意されている[CMCIS-DSPライブラリ](https://arm-software.github.io/CMSIS_5/DSP/html/index.html)を利用しています。[『小型IoT端末開発キット「SensorTile.box」 をセンサ･アプリで使ってみた③　振動FFT』](https://qiita.com/ykawano/items/e45390b235e9f54d4ea8)で紹介した加速度センサ用に提供されているMotionSPライブラリとは異なるため（MotionXXは加速度センサ用のライブラリ）ご注意ください。

CMCIS-DSP中のFFT関数情報についてはこちら： [Complex FFT Function](https://arm-software.github.io/CMSIS_5/DSP/html/group__ComplexFFT.html)

ちなみに、マイク関連の他の評価キットの中にもFFTを使うものがありますが、こちらの方では上記CMCISライブラリをベースに最適化したコードを使っています。見たところまだヘルプ･ドキュメントは提供されていませんが、興味のある方はソースコードも見てみてください。（[X-CUBE-MEMSMIC1](https://www.st.com/ja/embedded-software/x-cube-memsmic1.html)）

いかがでしたでしょうか？
引き続きSensorTile.boxを使っていきますが、次回は加速度センサを使った機械学習について試してみます。
[小型IoT端末開発キット「SensorTile.box」 を使って機械学習を体験①](https://qiita.com/ykawano/items/9a78b5e6781e81e75ed2)