本記事では、FP-AI-SENSING1のソースコードを覗いて、プログラム的にどういう作りになっているのか解析していきます。
本記事では、コードの詳細は対象とせず、プログラムの構造に絞って記載します。プログラムの構造が分かれば、動作イメージはつかめますし、詳細を知りたい時は該当箇所がすぐわかるので、直接見に行って確かめれば良いのです。
プログラムの構造とは地図のようなもので、本記事が地図として使えるようになれば良いと思っています。
目次
1.FP-AI-SENSING1の構造の解析
まずは全体の構造を解析し、俯瞰できるようにします。
1-1.ファイル単位の関連
まずはファイル単位の関係性を整理して、全体の構造を理解します。
sensor_sevice.c
アプリケーションのインタフェースの役割を担います。Bluetooth通信を行って、スマホアプリからの各デモ機能のスタート/ストップ要求の実行と、デモ機能の処理結果の送信を行います。
Bluetooth通信のサンプルプログラムとしてもとても有用そうです。
ちなみに、別のインタフェースとしてcli_commands.cにコマンドライン機能が実装されていますが、今回は省略しています。
main.c
アプリケーションのロジック部分はほとんどここに詰め込まれている感じで、約2,500行ほどあります。フラットな作りであまり好みではないですが、1つ1つの関数はわかりやすく書かれているので、読みやすいです。サンプルアプリケーションとしては、こういう書き方の方が正解なのかもしれません。
このファイルが主な解析対象になります。
<各モジュール.c>
各デモ機能が利用する、モジュール化された機能ブロック群です。必要に応じて見ていきたいと思います。
1-2.main.cの構造
main.cの構造を図にしました。(図が煩雑になるのを避けるため、Sempahore等の一部のものは省略しています。)
この図の中の淡い水色の部分(スレッドorタイマ)に着目すると動きが見えてきます。
TimerXXHandle:startProcessing
FreeRTOSのタイマです。TimerXXHandleはタイマのハンドル名で、startProcessingが実際に実行される関数です。デモ機能毎にタイマが存在し、XXに名前が入ります。
- TimerEnvHandle
- TimerBatHandle
- TimerMotionHandle
- TimerAudioLevHandle
- TimerActivityHandle
- TimerSdRecordingHandle
このタイマが各デモ機能の実行フラグを定期的にONすることにより、各デモ機能が定期的に実行されます。
THREAD_1:ProcessThread
このスレッドは各デモ機能のフラグをチェックし、ONされているものがあったら実行します。実行結果はMailQueueに送信します。
各デモ機能の詳細はこのProcessThreadを追えばわかります。各デモ機能を実装している関数と、さらにその中で利用するモジュールを表にまとめました。
デモ | 関数 | モジュール |
Environmental | SendEnvironmentalData() | |
Plot Data |
SendAudioLevelData() SendMotionData() |
|
Activity Recognition | ComputeMotionAR() | har_processing.c |
Acc Event | MEMSCallback() | HWAdvanceFeature.c |
Audio Classification | RunASC() | asc_processing.c |
AI Data Log | DataLogManager.c | |
Rssi & Battery | SendBatteryInfoData() |
A.I.を利用している”Activity Recognition”については、後ほどさらにコードを追いかけて詳細を解析します。
Thread_2:HostThread
MailQueueからデモ機能の実行結果を受信し、sensor_service.cに実行結果のデータ送信を依頼します。
2.Activity Recognitionの解析
A.I.デモ機能は”Activity Recognition”と”Audio Classification”の2つがあります。前者は加速度センサーを使っていて、後者は音声データを使っています。私は加速度センサーを使ったA.I.アプリケーションを作りたいと考えているので、前者のみ解析を行います。
さらに、”Activity Recognition”にはアルゴリズムが3つありますが、使い方を覚える目的なら1つだけで十分なので、デフォルトのGMPを対象とします。
2-1.Activity Recognitionの動作イメージ
”Activity Recognition”の推論だけに着目して抜き出したのが、上の図です。
TimerActivityHandleは32ms間隔で動作します。つまり、”Activity Recognition”のプロセスの実行間隔もそのまま32ms間隔となります。32ms間隔でニューラルネットワークの入力バッファにデータが追加されます。マニュアルと実装が異なっているようで、かなり混乱しました。
For HAR_GMP, 24×3 data matrix (24 x-axis, 24 y-axis, 24 z-axis) is given as input every 0.62 ms to the neural network.
引用:FP-AI-SENSING1_en.DM00568147.pdf
har_Processing.c:HAR_Run()がこのデモ機能の中核です。32ms毎に追加された入力データのバッファがフルサイズの24個たまったら、A.I.推論を実行します。なお、バッファは24個の半分の12個がオーバーラップする作りになっているので、実際には12回に1回、A.I.推論が行われます。
2-2.Activity Recognitionの前処理
推論の前には、har_Preprocessing.c:gravity_supress_rotate()により、入力データの前処理を行います。入力データの前処理として2つ行っています。
- 加速度センサーの値から重力成分を分離
- SensorTileの傾きを無視
加速度センサーは常に重力の影響を受けており、そのままだと純粋な加速度がわからず扱いづらいので、センサーの値から重力成分を分離します。分離は、IIRフィルタを使って低周波成分(1Hz)を重力成分として抜き出します。この処理はhar_Preprocessing.c:dynamic_acceleration()に記述されています。
次に、”Activity Recognition”というアプリケーションの特性上、SensorTileはどういう持ち運び方をされるかわからないので、SensorTileの傾きは無視したくなります。先ほど重力成分を抜き出したので、ここからSensorTileがどの程度傾いているのかわかるので、傾きを補正します。補正にはロドリゲスの回転公式を使っています。この処理は、har_Preprocessing.c:gravity_suppress_rotate()に記述されています。
2-3.Activity Recognitionの推論処理
ニューラルネットワークの構造としては、畳み込みネットワークを使っているようです。推論モデルは自前で作ろうと考えているので、詳細は調べませんでした。
A.I.推論アプリケーションの作り方は下記を参考にしてください。
X-CUBE-AIを使った推論プログラムの作り方をわかりやすく解説
2-4.Activity Recognitionの後処理
推論の後のhar_Postprocessing.c:har_Postprocess()は、推論結果から最も適合度の高いクラス(立つ、歩く、走る、自転車をこぐ、車を運転する)を返します。
3.おわりに
FP-AI-SENSING1をリバースエンジニアリングしたことで、SensorTileを使った推論アプリケーションの作り方を理解しました。
ただSensorTile本体にユーザインタフェースが何もないので、別途ユーザインタフェースを持ったBluetoothでSensorTileをコントロールするアプリケーションが必要になります。ST社がiOSアプリ/Androidアプリ/Pythonのライブラリを用意しているので、これのどれかを使うことになるでしょう。しばらくは調査の日々が続きそうです。
続き:まだ