電話でのお問い合わせ0120-439-296

第3回 音を目で見る! オーディオ・スペクトログラムの制作

著者:山田浩之(Y-Logic)  企画・編集:ZEPエンジニアリング

● ラズベリー・パイやDC-DCコンバータから出る音を見る

STマイクロエレクトロニクス社のDiscovery Kit“STM32H747I-DISCO”に搭載されたLCDとオーディオ機能を使って、役に立つものを作っていきます。
今回は第3回として、マイクから拾った音のスペクトログラムをLCDに表示するプログラムを実装します(図1)。マイクの音をスペクトログラムとして表示することで、人間には聞こえない音を「目で見る」ことができます。スペクトログラム(Spectrogram)とは、時間、周波数、振幅を可視化したグラフことです。音声や振動など、時間とともに変化する周波数成分を分析するときに使います。

図1 Discovery Kit STM32H747I-DISCOに搭載された
LCDとオーディオ機能を使ってマイクから拾った音のスペクトログラムを制作

ディジタル・カメラが普及する以前、レンズ付きフィルム・カメラがフラッシュ用バッテリを充電するとき、キーンという音を発することを覚えているかもしれません。電子機器の中には音を発するものもあります。その音が実際に聞き取れるかどうかは、年齢や個人差によって変わる人間の聴覚特性に依存します。スペクトログラム表示を実装して、実際に電子機器の発生する音を確認してみましょう。

■ PixelDataWidgetクラスを使ってスペクトログラム表示用のGUIコンポーネントを実装

スペクトログラム表示のプログラムは、マイクとCODECを使ってスピーカ特性を確認する本連載 第2回のプロジェクトをベースに作成します。
TouchGFX DesignerからGUIプロジェクト・ファイル(CM7/TouchGFX/TouchGFX\_AudioPlayRec\.touchgfx)を開き、画像1のようにGUIをデザインしました(図2)。

図2 TouchGFX DesignerでGUIウィジェットを配置する

以前のスペクトル表示をスペクトログラム表示に変更します。以前行ったスペクトル表示はTouchGFX組み込みのGraphWidgetを利用して実装しましたが、スペクトログラムを表示するのに適したウィジェットはありません。
TouchGFXでは、ユーザが描画可能な”PixelDataWidget”というクラスが用意されています。PixelDataWidgetを使えば、ユーザは、C++コードからメモリ上のビットマップ・データを変更することで、画面の表示を自由に書き換えることができます。
ここではPixelDataWidgetを使って、基本的なスペクトログラム表示を実装していきます。

■ 制作手順

● STEP1:PixelDataWidgetの初期化

PixelDataWidgetはTouchGFX DesignerではなくC++のコードから初期化します。

#include <touchgfx/widgets/PixelDataWidget.hpp>

によりヘッダ・ファイルをインクルードしたあと、PixelDataWidgetクラスをインスタンス化します。C++のコードからGUIを編集する場合、Screen、Container、Widgetの関係を理解する必要があります。
図3 のように、TouchGFXではContainerと呼ばれるWidgetをまとめる要素に対して、各Widgetが子として登録される形になっています。たとえば、1つの画面をもつ単純なアプリケーションであれば、その画面(Screen)のもつContainerにWidgetを登録することで、画面にWidgetを表示します。

図3 Screen、Container、Widgetの関係

スワイプ可能な複数画面をもつアプリケーションであれば、スワイプされるそれぞれの画面が1つのContainerになっているので、そこにWidgetを登録することで複数画面を扱います。
なお、Widgetの使用方法はTouchGFX Designerの自動生成するScreenViewBase.cppコードが参考になります。今回の場合は、Screen1View.cppファイルに、親となるScreen1のメンバとなっているContainer要素のadd関数を呼び出しPixelDataWidgetを追加する処理を実装します。

● STEP2:PixelDataWidgetにフレーム・バッファの登録

先ほど追加したPixelDataWidgetを初期化します。setPositionで Widgetの位置、setBitmapFormatで表示するビットマップの形式を指定していきます。また、setPixelDataを呼び、表示するピクセル・データのバッファを設定します。

// C++ のコード例
pixelDataWidget.setPosition(x0, y0, width, height);
pixelDataWidget.setBitmapFormat(Bitmap::RGB888);
pixelDataWidget.setPixelData((uint8_t*) spectrogramFrameBuf);

フレーム・バッファはユーザが管理する必要があります。ここでは、$800\times400$ pixel、RGB888の画面を描画するので、フレーム・バッファは$800\times400\times3 = 960000$バイトのサイズが必要です。このサイズは大きすぎて、マイコン内蔵のSRAMには格納できないので、外部SDRAM(32Mバイト)を使用します。SDRAMは TouchGFXライブラリで使われているので、リンカ・スクリプトを変更して領域を2分割し、その後半領域にフレーム・バッファを確保します。
ビットマップを変更したあと描画を更新するときは、Invalidate関数を呼び出します。画面に登録したタイマから定期的に呼び出せば、簡単なアニメーションが実装できます。

● STEP3:STFTの実装

STFT(Short-Time Fourier Transform)により、スペクトログラム表示に必要な短時間スペクトルを計算します。図4 のように、適当なオーバーラップ幅でセグメントを切り出し、窓関数を掛けてからFFTでフーリエ変換を行い、パワー・スペクトルを計算します。オーバラップさせる幅に応じて画面上のスクロール速度が決まります。FFTなどの信号処理はCMSIS-DSPライブラリを使って実装しています。
同じSTM32H747I-DISCOボードを使ったCMSIS-DSPの導入から応用までの解説が、[VOD/KIT/data]ARM M4/M7/DSP 500MHz!STM32H7計測\&通信用ハイスペックI/O Module開発(ZEPエンジニアリング)で公開されています。

図4 STFTによるパワー・スペクトル計算

● STEP4:画面シフトと描画

パワー・スペクトルが計算できたら、スペクトルの強さに応じて、画面右端ラインに色を表示します。

  • ピクセル位置からパワー・スペクトルの周波数を計算する
  • その周波数におけるパワーをデシベル・スケールに変換する
  • その値に応じた色に変換します。

波数軸をログ・スケールで表示する場合、上記(1)の周波数計算で、linar-log変換を追加します。また、取得信号の強さやバックグラウンド・ノイズに応じて(3)の変換を調整することで、表示を見やすく調整します。プロジェクトでは、それぞれコード上の変数で調整できるようにしています。
1ラインの描画と同時に画面全体を1ピクセル左にシフトすることで、画面スクロールを行います。メモリ上のビットマップは、画面の左上から右下の順に構成されています(図5)。ピクセル数だけオフセットしてメモリ・コピーすれば、スクロールが実装できます。

図5 ビットマップの配列構成

● STEP5:処理をまとめてクラス化

これらのスペクトログラム表示処理をまとめて、1つのCSpectrogramというクラスに実装しました。これにより、今回実装した処理をほかのプロジェクトに再利用できます。コードはプロジェクト中のSpectrogramWidget.cpp、Screen1View.cppファイルなどに記述されています。

● STEP6:基板上PDMマイクのサンプリング・レートを上げる

ここでの目標は、可聴周波数帯(私の場合max. 13kHz)よりも高い周波数の信号を見ることです。基板上のPDMマイク MP34DT05でどこまでの周波数の信号を取得できるでしょうか。MP34DT05のデータシートには、特に上限周波数は規定されていないようです。
第2回のプロジェクトでは、PCM変換後のサンプリング・レートが48kspsになるよう動作させていました。ソフトウェアによるPDM->PCM変換のDecimation Factor = 64になっており、このときのPDMマイクへのクロック周波数は48k$\times64 =$ 3.072MHzです。
入出力サンプリング・レートを96kspsに変更して動作させてみましょう。出力側はBSPオーディオドライバの呼び出し時のSampleRate変数の変更だけで対応できます。2回目のコードと組み合わせて、48kHzまでのテスト・トーンを出力できます。
入力側の96ksps対応はBSPドライバのコードの変更が必要です。入力サンプリング・レートを96kspsにするためには、次の2つの方法があります。

  • Decimation Factorを 32に変更する
  • PDMマイクへのクロックを2倍に増加する

(1)の方法では96kspsが実現できますが、ノイズが目に見えて増えてしまいました。(2)の方法はクロック6.144MHzとなり、PDMマイクの仕様範囲外(データシート上は最大3.25MHz)です。動作させようとするとソフト側処理の都合か、定期的にポップノイズが入ってしまいました。実験した限りは5MHz程度であれば動作しそうです。
折衷案として、PDMクロック4.9152MHz、Decmation Factor = 48で動作させることにします。この設定で102.4kspsになり、ナイキスト周波数の51.2kHzまで表示できます。これは、イヌやネコの可聴周波数帯に近いです。ネコになったつもりでスペクトログラムを見てみましょう。

● STEP7:動作確認と環境音の取得

作成したプログラムをボードに書き込み、動作確認します。基板のオーディオ・ジャックにスピーカを接続して、Tone Play/Stopを押してテスト・トーンを出力し、スペクトログラムに反映されるか確認します。
図6 は44kHzの信号を出力して、画面のおよそ4/5の位置(44 /51.2)に線スペクトルが表示されています。このマイクは40kHz以上にも感度があることがわかります。一方、無音状態でも19.2kHz付近に信号が見られます。これはマイク自体または基板上から発生しているようです。

図6 40kHzの超音波をPDMマイクで取得してスペクトログラム表示

[Run]を押すと、スペクトログラム表示を開始します。生活環境で動作させてみると、われわれの環境におけるいろいろな音が画像として表示されてなかなかおもしろいです。

● STEP8:いろんな音を見てみよう

電子回路中のインダクタやキャパシタは、動作中に音を出すものがあります。いずれも微弱な音であり、また音波は多くの場合EMIのように問題になるものではありません。探してみると、もっと大きなレベルの音を出す機器もあるかもしれません。

DC-DCコンバータの音

図7 は、別に用意した電子回路中のDC-DCコンバータにマイクを近づけてみたようすです。人間の聞きとれない35kHzにDC-DCコンバータが発生する音が見えています。なお、画面下部に見えている信号は環境音です。

図7 DC-DCコンバータの発生する音を見る

ラズベリー・パイの音

図8 は、電源を入れた状態のラズベリー・パイPico Wを近づけたようすで、11kHz付近に信号が見られます。実際に動作中に耳を近づけてみると、ラズベリー・パイPico Wから発生する微弱な音を聞くことができます。

図8 ラズベリー・パイPico Wの発生する音を見る

パソコンの音

図9 は、ラップトップPCの隣に置いたところで、ほかの環境ではみられなかった周波数の線スペクトルが増えています。表示から、PCが約27kHzの音を発生していることがわかります。

図9 ラップトップPCの発生する音を見る

■ まとめ

● 1Mspsのマイコンの内蔵ADCを利用する方法も

ここでは実装しませんが、基板上CODECの外部入力を使ったり、マイコンの内蔵ADCを利用することも可能です。STM32H747 マイコン内蔵の ADC は 1Msps 以上のサンプリング・レートで信号を取得することが可能なので、PC やスマートフォンのオーディオ・インターフェースより高い周波数の信号を取得することができます。ただし、内蔵の ADC の分解能はオーディオ向け CODEC ほど高くありません。

● 液晶表示を自作デバイスに活用しよう

ここまで見てきたように、スペクトログラム表示は測定値から特定の信号を見つけ出すような観測に効果的です。オシロスコープやスペクトログラム・アナライザでもパワー・スペクトルは見られますが、スペクトログラムは過去のスペクトルを含めて視認できる特徴があります。
これにより、単発の事象なのか、微弱な信号が継続して入力されているのか、その周波数は変化してるのかなど、さまざまなことがわかります。例えば電源ラインのスペクトログラムを見れば、スペクトルを見るよりも早くノイズの原因を見つけ出すことができるかもしれません。
記事で使用したSTM32H747I-DISCOは、信号処理から解析、LCDへの結果表示まで一貫して実装できるため、高度な処理の必要な実験に適しています。自作デバイスにおけるRGB LCDの対応は、敷居の高い印象でしたが、今回のプロジェクトではTouchGFXライブラリを使うことで比較的簡単に対応できました。このボードで実装したコードをもとにすれば、STM32マイコンを使った自作デバイスに対しても、いまどきの測定器にあるような高度な表示処理の実装が容易になると思います。

参考文献
[1] ] VOD/KIT/data]Arm M4/M7/DSP×500MHz!STM32H7ハイスペック計測通信Module開発、ZEPエンジニアリング株式会社。
[2] タッチパネルLCD搭載!Cortex-M4/M7×500MHz!全部入りマイコン・キット STM32H747I-DISCO誕生、ZEPエンジニアリング株式会社。
[3] 高感度受信!ソフトウェア無線機の心臓部 “Root-Raised Cosine Filter”の設計、ZEP エンジニアリング株式会社。
[4] ソフトウェア無線と通信の同期、ZEP エンジニアリング株式会社。
[5] ディジタル信号処理入門 FFTスペアナの制作、ZEP エンジニアリング株式会社。
[6] ディジタル信号処理入門 再生速度&音程エフェクタの制作、ZEP エンジニアリング株式会社。