前回、前々回とFIRフィルタで特性も同じ。しかしフィルタを構成する形は異なりました。しかし今回は前々回と形も同じ。違うのはソースコードの書き方のみ。折角のC++のコンパイラだし、「クラス」を使わずにはいられないっと。「テンプレート」もね。確かに見通しよくなるけれど、年寄りはC++には染みついた抵抗がある。
※「手習ひデジタル信号処理」投稿順 Indexはこちら
勝手に手習ひさせていただいております教科書は以下です。
三上直樹先生著、工学社『「Armマイコン」プログラムで学ぶデジタル信号処理』
ソースの引用等は避けますが、Arm社のMbed環境上で公開されています。
年寄りの追憶
組み込み用途のマイコン、特にROM、RAMを搭載したマイクロコントローラ(MCU。マーベルじゃない方)での話です。今でこそC++コンパイラにお世話になることが増えましたが、少し昔は御法度というか、組み込みマイコン対応のC++はサポートされていないことが多かったと思います。
よく考えてみると大昔はコンパイラすらなかったです。MCUでCコンパイラが使えるようになったのも年寄りにとってはつい最近に思えます。使えるようになった後も、例えば、今では開発時に普通に使う printf ですが、Cコンパイラはあっても printf は無いというのが普通だった気がします。printfに代表されるCの標準ライブラリを実装すると結構な大きさになってしまうので、使いたいときもサブセットのサブセットくらいな「なんちゃって」実装でガマンしていました。ましてやC++など。
そうなる原因はメモリ量ですね。プログラムを置くROMにせよ、データを置くRAMにせよ、高々数Kバイト程度の世界ではコンパイラはまず使えませぬ。コンパイラに必要なスタートアップコードで一杯になってしまう。
それが数十Kバイトといった分量がフツーになってきて、そしてコンパイラやらライブラリも「お手頃」になってきたお陰で普通にコンパイラできるようになりました。ありがたいことです。
しかしC++への抵抗?は残った気がします。いろいろ理由はあると思いますが、一番の理由は
動的なメモリの確保、ぶっちゃけ new したくなるから
じゃないかと想像しています。今も昔も組み込み用途での動的メモリの確保は要注意、やらない方が良いことの筆頭じゃないかと思います。たとえCでもmallocは普通やらないと思います。PCのようにGバイト単位のRAMが使える装置と違い、精々数十Kバイトから数百Kバイト程度のRAMしか使えないマイコンで、動的にメモリを確保するのはかなり危険です。それにメモリ管理の仕組みのオーバヘッドも心配だし。基本は、静的にメモリはアロケートして、使いまわすときはプログラマがちゃんと管理してね、という感じ。
でもね、C++使い始めると便利で見通しが良いことも事実、それを体現しているのがArduino環境じゃないかと思います。何かハードを使いたいときに、ライブラリ呼び出してクラスインスタンスを作る。すると以降、そのインスタンスの中のメンバを呼び出すだけで皆出来てしまいます。
Class を使うにあたっての三上先生のご方針(勝手な推測含む)
さて今回、FIRフィルタ機能をクラス化するにあたっての三上先生のご方針(当方の勝手な推測を含みます)その1は、当方も納得の
動的なメモリ確保は行なわない
です。「ヒープ領域からの動的確保」について述べておられるところから、1行引用させていただきましょう。
問題が起きないようなプログラムを作るのは、結構大変です。
それでどうする、というところがちょっとカッコいいです。配列確保のためのテンプレート・クラスを定義されております。テンプレート自体は書いただけでは何もメモリを使うわけでもなく、書き放題?実装するときに静的に決定すれば、「問題ない」上に、とてもカッコよく書けてます。組み込み用途こそ、テンプレート使うのが良い感じがします。
しばりその2は、
クラスの継承は許すけれど、インスタンスのコピーや代入は許さない
だと思います。継承して機能を拡張/変更した派生クラスを作ることはできるけれど、作ったインスタンスをコピーしたり代入したりしようとしたらビルド時にエラーで落とす、という感じ。ある特定のハードウエア(メモリも含む)を占有して動作することになるので、不用意に同じもののコピーを作るのはクラッシュの元、かもしれませんで。
ビルドの結果
さて、ビルドの結果(メモリ使用の様子)を以下に示します。左が今回のクラスとテンプレートを使った「かっちょいい」もので、右が関数で書かれた前々回の「伝統的」なものです。
見れば、Flashの使用容量はクラスを使ったものの方が微妙に大きいですが、RAMの使用量は減っています。テンプレートで最適化したお陰?実際は良く分かりませんが、「ほとんど差がない」です。
動作結果
やはりビルドしたオブジェクトを実機 Nucleo F445REに書き込み、波形を入力して結果を確認せねばなりません。
まずは、時間波形、フィルタの通過域である800Hzの周波数でオフセット0V、振幅1Vの正弦波を与えた結果です。黄色がオシロのCH1で入力、青色がCH2で出力です。通過してますね。
お次は、阻止領域の1.2kHzです。下をご覧くだされ、見事に阻止されておりますがな。
最後は例によって、振幅の周波数特性です。ナイキスト周波数5kHzまでのプロット。
計算アルゴリズムはそのままで、ソースの実装だけを変えただけなので、以前の結果と変わらないのが期待値であります。期待どおり。