フレームサイズに足を取られる

By | 2020年6月29日

MATLAB/Simulinkには信号の扱い方に「サンプルベース」「フレームベース」があります。ここに足を取られて丸一日悩んだのでメモを兼ねて解説を書いておきます。

先日書いたように、MATLAB/SimulinkのSRCはフレームベースです(先日の時点ではブロックと書いたが、MATLAB/Simulinkではフレームと呼ぶ)。そのため、入力であるFrom Multimedia Fileブロックのフレーム長をSRCの入力フレーム長に合わせる必要がありました。

ところが、問題はこれだけに収まりません。信号同士の演算の場合、両者のフレームサイズを合わせておかなければ正しい結果にならないだけではなく、場合によってはメモリ消費量が爆発することがわかりました。フレームサイズの調整にはbufferブロックを使います。

そもそもの問題

事の起こりは、これまで作ったSimulinkのモデルを組み合わせてみようと考えたことです。

例えば以下のモデルは何の問題もなくすんなり動きます。これはDDSに相当するモデルで、freqにHz単位の周波数を与えると、1サンプルごとに周波数に相当する位相がアキュームレータに加算されていきます。位相は余弦波に変換されて出力されます。

DDSのモデル

また、以下のモデルも正しく動きます。これは入力したオーディオデータに1を足すだけのモデルです。問題の起きようがないように思えます。

ファイルから読んだオーディオデータに1を足す

ところが、この二つを組み合わせた途端、トラブルまみれになりました。まず、オシロスコープの波形を開こうとすると、MATLAB/Simulinkが無応答になり、強制終了以外の道がなくなります。仕方なく信号ログをとるように変更すると動きますが、わずか10秒程度のオーディオ信号処理に気が遠くなるような時間がかかるようになります。

トラブルまみれのモデル

頭を掻きむしりながら調べて分かったのは、上のモデルの実行中に数十GBの主記憶を消費していたことです。そんなバカな。単純なオーディオ信号処理ですよ?

正しい結果にならない

混乱に輪をかけたのは、結果がおかしかったことです。

上のモデルの実行結果をデータインスペクターで開いたのが下の図です。かいつまんで言うと、左上のCarrierと、左下のOffertの要素同士の席が右下のam_outに出てくることを期待しています。

結果がおかしくなる

しかしながら、ごらんのとおり結果は期待値からほど遠いものです。

MATLAB/Simulinkのフレームサイズの扱い

この「莫大なメモリを消費し、おまけに結果がおかしい」問題の原因はフレームサイズの取り扱いにありました。

このモデルでは、From Multimedia Fileブロックの出力がフレームベースになっています。このブロックのフレーム・サイズは1024です。つまり、ステレオ・データの方チャンネル当たり1024サンプルの長さがあります。

このフレーム化されたデータはスカラー値「1」と足し合わされます。この場合、加算器の出力はフレーム単位となります。当然、演算としてはフレーム中の全サンプルに1が足されます。

さて、問題はModulationと銘打たれたProductブロックです。このブロックには下からフレーム・ベースの信号が、上からサンプル・ベースの信号が入ってきます。私はこのブロックはサンプルベースの信号を集めてきてフレームに変換し、フレームベースの信号との間で要素ごとに乗算を行うと思っていました。残念ながらそうはなりません。

実は、フレームベースの信号とサンプルベースの信号の乗算結果がどうなるかは、ドキュメントには書いてありません。実際に何が起きているかは深く調べていませんが、サンプルベースの信号をフレームとして集めた後、クロネッカーテンソル積を取っているように見えます。正確に何をしているかは不明ですが、どうやら要素対要素の演算でないことは確かで、データ数が爆発的に増えています。

先のメモリ使用量の増大は、このデータ数の増加から来ています。また、乗算のしかたが想像と違っているため、当然結果も期待値とは異なっていたわけです。

問題を解決するには、フレームベースの信号をサンプルベースに戻してやります。このモデルに限って言えば、From Multimedia Fileブロックのチャンネル当たりサンプル数を1にすれば済みます。より汎用性のある方法としては下の図のようにBufferブロックを挿入し、プロパティを編集して出力フレームサイズを1にします。

バッファーブロックでフレームサイズを1にする

この変更で正しい結果が得られ、動作も軽快になりました。

GUIの表記がよろしくない

フレームベースの信号処理についてはドキュメントで1ページを割いて説明されており、「フレームベース」という言葉は公式用語のようです。

ところが、ブロックのプロパティではこの言葉が使われていないことがあります。例えば、From Multimedia Fileでは「オーディオチャンネル当たりのサンプル数」と表記されており、これが1ならサンプルベース、1より大きければフレームベースです。

残念ながら「オーディオチャンネル当たりのサンプル数」がフレームサイズのことだとは直感的にわかりにくいです。

From Multimedia Fileブロックのプロパティ

また、Bufferブロックの出力も同じです。こちらは英語ですが、Output buffer size ( per channel )は「オーディオチャンネル当たりのサンプル数」のことですね。

Bufferブロックのプロパティ

Filterブロックではまた表記が変わっていますが、「フレームベース」「チャンネルベース」と注釈が入っているので救われます。

Filterブロックのプロパティ

まとめ

MATLAB/Simulinkはフレームベースの信号とサンプルベースの信号を混ぜて使うと問題が起きる可能性があります。

これは、フレームベースの信号とサンプルベースの信号では信号の解釈が異なるためですが、エラーメッセージが出るわけでもなく分かりにくいです。また、ブロックのプロパティの設定は「フレームベースとサンプルベースの処理がある」と知っていない限り、何のことだかよくわかりません。

フレームベース信号とサンプルベース信号の間で演算を行う場合、フレームベース信号にBufferブロックを挿入し、サンプルベースに変換してしまえば手っ取り早く問題を避けることができます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください