忘却の微分方程式(11) ScilabでラズパイPicoでひろったPDM生波形を観察

Joseph Halfmoon

ラズパイPicoに「無理やり」MEMSマイクロフォンを接続し、PDM(パルス密度変調)の生波形を取得いたしました。最終的にはマイコン上で処理したいのですが、最初はPC上で生波形がどんなものだかしみじみ味わいたい。ということで久しぶりにScilabを取り出してまいりました。全然微分方程式じゃないのだけれども。

※「忘却の微分方程式」投稿順 index はこちら

MEMSマイクはとても小さい表面実装部品です。デジタル信号でインタフェースがとれるので普通のアナログマイクで必要になるアンプなども不要、とても使いやすい部品じゃないかと思います。といって今まで使ったことが無かったので、以下投稿にてMEMSマイクが出力するPDM生波形をRaspberry Pi Picoで読み取ってパソコンに出力してみました。

MicroPython的午睡(34) ラズパイPico、MEMSマイクのPDM生波形を取得

I2Sインタフェースを搭載しているマイコンなどでは、PDM波形を直接信号処理できたり、専用ライブラリが用意されていたりするものですが、残念ながらラズパイPicoにはそれらは無りません。しかしラズパイPicoにはPIOという宝刀があります。1MHzといったクロック速度に同期してマイクが垂れ流してくる0/1の流れを拾い上げることができました(の筈。)

ただし、パソコンの上で眺めても「音」は全然分かりませぬ。データファイルはこんな感じ。

11000110011010101001011000110101
01001101001100011010101010011010
01010101010101001101001100011011

1個1個の0、1が、1MHzの早さでサンプリングされたPDM信号であります。

通常、処理の流れとしてはこの信号をデシメーションフィルタにかけてPCMフォーマットに変換することになるのだと思います。PCMになるとI2Sバス上を流せるようになるので、圧縮したり、DAからスピーカに出力したりできるようになります。PDM波形からI2Sバス信号への変換ができるハードも手元にあるので、別途実験の予定です。今回は、ほとんど手動でこの波形を操作して、多少「信号」ぽいところを観察したいと思います。この手動操作に使うつもりなのが、Scilabということであります。

蛇足ですが、ScilabはMatlab類似のソフトウエアです。しかしMatlabのようなコストの障壁なく無料。素晴らしい。ただし、Matlabのように充実したサポートは望むべくもありません。現在手元でMatlab使えないのでScilabという選択です。個人的意見としては、理工系の学校に在学していて権利を利用できるか、お金に余裕があるならばMatlabをお勧めしたいです。「お金分の価値がある」ソフトだと思います。なお、Matlab互換のソフトウエアとしてはOctaveも有名で、言語の互換性という点ではOctaveの方が上だと思います。Scilabは似ているけれど互換は狙っていない感じ。一長一短。

まず信号波形の「取り直し」

上の投稿でMEMSマイクの出力波形を取得しましたが、最初に取得したときには、特に目印になるような音声信号をマイクに入力していなかったです。手元のパソコンのファンの音くらいでしょうか。これでは処理したときに「見えてくる」感が期待できないので「目印信号」ありのデータを取り直すことから始めました。

アイキャッチ画像にその様子を掲げました。音源としてスピーカを用意、スピーカにはLM386使用のスピーカアンプを接続し、そのアンプには例によってDigilent Analog Discovery2から正弦波を与えています。以下3通りの周波数の音声信号をMEMSマイクの正面から加えましたです。

  • 1kHz
  • 440Hz
  • 200Hz

ラズパイPicoのPIO(プログラマブルIO。IO処理専用のステートマシン)はMicroPythonからの指示により、MEMSマイクに1MHzクロックを出力しております。そしてクロックエッジに同期してMEMSマイクからのデータ線をキャプチャしています。モノラル動作なので1クロックに0/1を1個読み取り。これを32000個読み込んだところで、その値を接続しているPCのシリアルポートにダンプしています。ちょうど32ms分のデータとなります。1kHzなら32周期分、440Hzならば14周期分、200Hzならば6周期とちょっとがデータに含まれる計算です。

第1ステップ、01のファイルをScilabの行列に読み込む

Scilab使わせていただくのも久しぶり。ほとんど使い方忘れています。まあ、いろいろ調べながら操作していきます。Raspberry Pi PicoのMicroPythonから取り出した0/1のデータファイルは、文字0と1の羅列のテキストファイルになっています。32us分毎に改行。さて、それをScilabで取り込むのはこんな感じにしてみました。以下は1kHzの時のデータの場合。

Fid1=mopen('1kHz.txt', 'r');
TXT1=mfscanf(1000, Fid1, '%s');
mclose(Fid1);
binDat1=ascii(TXT1)-48;

ミソは4行目のascii()関数で、1要素32文字の文字列が1000要素読み込まれた行列を一気に1×32000形式の行列に分解してくれました。勿論ASCIIキャラクタコード(数値)に変換してです。48は文字 ‘0’ のアスキーコードなので、48ひいてやれば0, 文字’1’ならば49だから1というわけで、一気に数値行列に変換できました。

第2ステップ、01の様子をグラフで観察したい

パルス密度変調ということで、パルス(値1)の疎密を観察したかったです。最初32000要素を一気にグラフにしてその失敗に気づきました。データ量多すぎ、真っ黒なグラフで何だか分かりません。GUI操作で拡大しようとしてもうまく行かず。2周期分2000要素を取り出すことにいたしました。こんな操作。

x = 1:2000;
work1 = binDat1(1, 7001:9000);
bar(x, work1);

頭の方を外し、7001番目の要素から2ms分取り出してみました。グラフにするとこんな感じ。Graph0

なにか2周期分の正弦波が見えているような気がするのですが、老眼のせいでしょうか。440Hzや200Hzだと1周期のデータ量が多すぎてなんだか分かりません。

第3ステップ、1を数えて「なんちゃってローパス」してみた。

上の方法では、1kHz、440Hz、200Hzのデータの様子を比較できなかったので、とりあえずの「なんちゃってローパス」処理をかけてみました。本格的なデシメーションフィルタとは違います。64個ずつ01データを区切り、その区間の1の数を数えてその区間の値とする、という方法です。係数も何もあったもんでなし。うまいScilabコードを思いつかなかったので力ずくです。こんなコード。

xx= 1:500;
sumDat1=zeros(1,500);
for I=1:500
    sumDat1(1, I)=sum(binDat1(1,64*I-63:64*I));
end
plot2d(xx, sumDat1);

3つのファイルの全データ32000点にすべて同じ処理を適用して比較してみたのがこちら。上から1kHz、440Hz、200Hz。

Graph1

頭のMEMSマイクの起動時間?のところを除くと、それぞれ異なる波形が得られているので、目印の音声信号により異なる波形になっている、ということだけは確認できます。0/1の羅列じゃそれすら分からなかったし。

でもね、1kHzのグラフでは、ちょうど1kHzっぽい周期がとれているのだけれど、440Hzや200Hzは見えませぬ。ううむ「なんちゃって」ではダメか。

ちゃんと、デジタル信号処理とScilabを学び直さないととても歯が立ちませぬな。とりあえず「デバイスにお任せ」してみるか?ちゃんと立派な部品を買ってあるのだし、「デバイス」のサイトなのだし。。。

忘却の微分方程式(10) OpenModelica、抵抗1個のモデリング へ戻る

忘却の微分方程式(12) 折角なので使ってみた、Wolfram+Raspberry Pi へ進む