センサーからのデータを複数のサブコアで多段に解析。マルチコア・アプリケーション実践開発ガイド


図

現在、組み込みシステムには多種多様なセンサーが搭載されています。SPRESENSEではAdd-On Boardを活用することにより、基板設計や配線作業をすることなく加速度、回転角速度(ジャイロ)、温度、大気圧といった様々な物理量を測定することができます。

SPRESENSEで特に注目すべきセンサーは、コントローラに統合されたハイレゾ録音に対応したオーディオ入力ハードウェアです。空気の微細な振動を「細かい分解能で標本化」し「最大24bitの分解能で量子化」できる優れた性能により、周辺状況を非接触で推定するアプリケーションに採用可能です。前回(第7回)紹介したソフトウェア・エンコーダにより、わずかな工数でオーディオデータを解析するアプリケーションの開発に着手できます。

今回は、産業向けアプリケーションのPoCをイメージし、SPRESENSE SDKに同梱されたサンプル・アプリケーションである「マルチコアを使った録音プログラム(Audio Recorder)」を改変し、「自身で設計した信号解析アルゴリズムを実行するサブコアと連携」、高速かつ高精度に周辺状況を分析できるアプリケーションの開発方法を紹介いたします。

図

▼目次

高品質なオーディオデータを活用し、非接触に異常音の発信源(音源方向)を推定する

空気の振動である「音」は、これまでにない用途に活用できる可能性があります。マイクにより音声を電気信号へと変換、高精度なA/D変換器により生成されたハイレゾリューションのオーディオデータを解析することができれば、人の聴覚に代わる革新的なシステムを実現できることでしょう。

音源方向の推定

今回は音源方向を推定するアプリケーションを例に、オーディオ機能とマルチコアの魅力を紹介いたします。まず、工場内に立っている作業員をイメージしてください。工場内の機械が故障し異音や衝撃音が発生すると、離れた場所に立っている作業員であっても耳と脳を使って音源の方向を推定することができます。そして、複数の作業員が別々の場所で同じ異音を聞いていれば、全員が推定した音源方向から、故障した機械を特定可能です(図1)。

この仕組みをデバイスで実現し、人間が立ち入ることのできない高温環境や危険の多い現場にも適用することで、よりインテリジェントな工場、IIoT(Industrial-IoT)化されたプラントを実現することができます。

図
図1:音源方向を推定した情報を統合し故障を検知するIIoTサービス(例)

ステレオマイクを使いこなす

ステレオ(L/R)マイクを接続したAPS学習ボードとSPRESENSEを使うことにより、同様のシステムを構築可能です(図2)。APS学習ボードの左右マイク(MIC1/MIC2)は70mm離れて搭載されており、空気中の音は1ミリ秒で340mm進むことから、左のマイクと右のマイクが同じ音を捉えた時間の差から音源方向を推定することができます。

図3はSPRESENSEの周囲で2回の拍手をした際に採取されたオーディオデータです。このデータにより、最初の波が左方向からの拍手音(左のマイクが先に音を拾った)、二番目の波は右方向からの拍手音(右のマイクが先に音を拾った)ということがわかります。

図

図
図2:音源方向により、左右のマイクにより集音したデータにわずかな差が発生する

図
図3:音源方向の違いによるオーディオデータの変化(実測値)

音源角度を算出するアルゴリズム

SPRESENSEの高いサンプリングレート(短いサンプリング間隔)のオーディオ入力機能を活用することにより、左のマイクと右のマイクに音が入射した「時間差」を精密に導出できます。高いサンプリングレートで収録したオーディオデータについて、①まず左のマイクのオーディオデータのの中心点(今回は計測データのうち最大音量となった時点を採用)を決定し、②次に録音済みの右のマイクのオーディオデータとの差分を計算。③サンプリング開始点をずらしながら、左のマイクと右のマイクのオーディオデータを比較し、④絶対値の合計が最も小さくなる時間タイミングを特定することで、⑤左のマイクと右のマイクで同じ音を拾った時間差を算出できます。なお、マイクの間隔は70mmのため±205us以上ずれることはなく、±205usmの範囲を走査するのみで音源方向を推定できます。

音源角度と、左チャンネルと右チャンネルの入射時間の差、SPRESENSEのオーディオ入力機能により採取した「48kHz,16bitのオーディオデータ」のサンプリング点数の対応表を図4に示します。入射角度が0°の場合、右のマイクに音声が入射してから205us後に左のマイクに音声が入射することから、+10点ずれて同じ音がピックアップされます。入射角度が45°の場合は、右のマイクに音声が入射してから145us後に左のマイクに音声が入射することから、+7点のずれとなります。

図
図4:音源方向による入射時間とサンプリング時点変化との対応

一例として図3で紹介した左からの拍手音を解析した結果を図5に示します。ここでは、左チャンネルに対して、8回分遅れたサンプリング時点(-8点目)の右チャンネルのデータの差分が最も小さくなっていることから、推定音源方向は150°となります。

図
図5:左右のオーディオデータの差分を合計

マルチコアを活用したデータ解析システムの構造

マルチコアを活用した音声解析アプリケーションは、①全体を管理するメインコアと、②オーディオ入力ハードウェアから取得した情報からオーディオデータを生成する「ソフトウェア・デコーダ」を実行する1個のサブコア、③取得したオーディオデータを解析するサブコアから構成されます。今回のサンプルプログラムでは、オーディオデータを解析するために1個のサブコアを割り当てていますが、メインコアの制御コードを拡張することにより複数のサブコアを割り当て、より高いスループットを実現する構成も可能です。各コアが決められた処理に専念し、無駄のないパイプラインを設計できるASMPアーキテクチャの特長を活かしたシステムです(図6)。

解析アルゴリズムをメインコアでなくサブコアで実行することにより、メインコアの負荷を軽減することができます。これにより、メインコアが担当するペリフェラルを制御するタイミングや、ソフトウェア・エンコーダを実行しているサブコアを制御するタイミングを大きく変化させることなく、より複雑な解析を適用できる高度なアプリケーションを実現可能です。

なお、②の処理は前回紹介したSPRESENSE SDKのAudio Recorderサンプル・アプリケーションの処理を流用することができます。また、今回はオーディオデータを扱っていますが他種のデータに対する解析も同様の手順で実装可能です。例えば、加速度センサーを使う場合はSPRESENSE SDKのaccelサンプル・アプリケーションが参考になります。

図
図6:ソフトウェア・エンコーダの出力を別のサブコアにより解析する

センシング機能と解析アルゴリズムを協調動作できるマルチコア・アプリケーションの開発手順

それでは、オーディオをメモリ上へと展開するソフトウェア・エンコーダを実行するサブコアと、ユーザのアルゴリズムを実行させるためのサブコアを協調動作させるためのアプリケーションの開発手順を紹介いたします(なお、以降は複数のサブコアを協調させる方法の説明を主題とし、解析アルゴリズムについては解説を省略いたします)。

本記事は、開発結果でなく開発手順の紹介が大切なポイントです。そのため、完成形のソースコードの提供だけでなく、各開発手順の概要と実装内容の詳細もGitHubのコミット履歴表示として併記します。是非、製品開発の参考にご活用ください。

ソースコードの入手

今回のサンプル・ソースコードは「APS-Academy(Multicore) #8 Sample Code」としてリリースされています。下記の手順に従ってソースコード一式をPCにダウンロードしてください。

# SPRESENSEのgitのリリースリストが表示されます
$ git tag -l
v1.0.0
v1.0.1
...
v1.4.0.is.5.0
# ソースコードから"1.4.0.is.4.0"という名前のブランチを生成します
$ git checkout -b 1.4.0.is.5.0 refs/tags/v1.4.0.is.5.0
Switched to a new branch '1.4.0.is.5.0'
# このように切り替わっています
$ git branch
* 1.4.0.is.5.0
	master
# 1.4.0.is.5.0の初期状態にリセットします
$ git reset --hard HEAD

Examplesからオーディオ録音機能をユーザプログラムへ移植する

まず、ユーザーアプリケーションを生成し、SPRESENSE SDKの提供するExamples/Audio_Recorderから必要な機能を切り出したプログラムを作ります。

アプリケーション開発に「C++(.cxx/.cpp)」を使う

SPRESENSE SDKとVisual Studio Codeの提供するソースコード・テンプレートを自動生成する機能を使うことにより、main関数が定義されたC言語のソースコードを自動生成できます。Audio RecorderのようにC++言語で開発する場合、Makefile(ビルドするルール)を一部修正しメインとなるプログラムの拡張子が「.cxx/.cpp」であることを明記する必要があります。

CXXSRCS = $(filter-out $(MAINSRC),$(wildcard *.c) $(wildcard */*.c)) $(wildcard *.cpp) $(wildcard */*.cpp) $(wildcard *.cxx) $(wildcard */*.cxx)

また、NuttXは各ユーザアプリケーションのエントリポイントを「C言語の関数」として結合します。そのため、C++中のエントリポイントをCに読み替える「extern "C"」の宣言を追加します。以上で、C++言語を使ったアプリケーション開発の準備は完了です。

	extern "C" int aps_cxx_audio_detect_main(int argc, char *argv[])
  1. (6e46e12) C++のソースコードを含むプロジェクトを新規作成する

Examples/Audio Recorderを移植し整理する

次に、オーディオデータを収集するAudio Recorderサンプルアプリケーションを、ユーザプログラムへ移植します。実装行数の長いプログラムですが、内部で実行している処理はいくつかのハードウェアやサブコアに対する初期化、開始、終了、要求機能の組み合わせとなっています。そのため、初期化・開始・終了をセットとして、ビルドと実行を繰り返しながら少しずつ確実に移植を進めていきましょう。今回は、以下の8ステップを踏んで移植しました。

  1. (98240c8) オーディオ入力機能のビルドに必要な宣言を追加する
  2. (caddb6b) オーディオ入力機能の初期化機能を追加
  3. (af274ac) ソフトウェア・エンコーダの開始/終了機能を追加
  4. (e8f05f1) オーディオ入力機能の録音開始/終了機能を追加
  5. (ae81a08) オーディオ入力機能の後処理を追加
  6. (7a8cf27) ソフトウェア・エンコーダの後処理を追加
  7. (bac1b8c) データの送出先をファイルでなくメモリに限定
  8. (a2fdcdd) データ可視化のためのデバッグ機能を追加

マルチコア制御用のクラスを開発する

続いて、自由に解析アルゴリズムを実装するためのサブコアを制御するためのソースコードを準備します。プログラムの自動生成機能を利用したプログラム(手順10)をそのまま利用することもできますが、1ファイルあたりのソースコードの行数が長くなると不具合解析が難しくなることから、今回は、手順11と手順12でメインコアの制御処理をC++クラス化し、サブコアの初期化処理をstatic関数とすることでソースコードの可読性を改善させました。

  1. (3ecd5b5) マルチコアを制御するテンプレート・プログラムを作成
  2. (8df5cae) 利便性のためメインコアのコア制御機能をclass化
  3. (7cb6b51) 利便性のためサブコアのメインコア連携機能を整理

すべての制御機能を統合する

最後に移植したAudio Recorderのプログラムと、解析アルゴリズムを実装可能な「自由に使える」サブコアの制御処理を統合します。Audio Recorderから抜粋した処理を使ってオーディオデータを共有メモリ上へ格納、サブコア連携プログラムによりメモリ上に展開された有効なオーディオデータの長さをサブコアへ通知し、有効データに対して解析アルゴリズムを実行できるようプログラムを結合します。

  1. (0621b84) オーディオ機能にマルチコア制御コードを統合
  2. (b27ac54) マルチコア動作を確認するデバッグ機能を追加
  3. (bce4626) 録音データをサブコアへ渡す処理を追加

マルチコア・プログラミングにおけるリソース管理の注意点

サブコアを使うプログラムを統合する際、注意しなければならないポイントはリソースの競合です。例えば、図7に示す2個のアプリケーションのソースコードを単純に結合させると、メッセージ・キューを指すリソースの管理番号が衝突し、メインコアとサブコアの連携に不具合が生じます。そのため、リソースの初期化関数に着目、利用しているリソースの管理番号を確認し、競合のある場合は変更する作業が必要となります。

コア間連携の異常から発生する不具合は、タイミングのわずかな違いにより不再現となり、デバッグに多くの工数を消費します。そのため、実装時に十分注意し、開発工数の浪費を未然に防ぐことが大切です。

図
図7:マルチコア・プログラミングでは機能を統合する際、リソースの競合への注意が必要

  • Audio Subsystemが予約しているリソースの管理番号
    msgq_id.h - L50
/* Message queue pool IDs */
#define MSGQ_NULL 0
#define MSGQ_AUD_MGR 1
#define MSGQ_AUD_APP 2
#define MSGQ_AUD_DSP 3
#define MSGQ_AUD_RECORDER 4
#define MSGQ_AUD_CAP 5
#define MSGQ_AUD_CAP_SYNC 6
#define MSGQ_AUD_FRONTEND 7
#define MSGQ_AUD_PREDSP 8
#define NUM_MSGQ_POOLS 9
#define APS_CXX_AUDIO_DETECTKEY_SHM         (80)
#define APS_CXX_AUDIO_DETECTKEY_MQ          (81)
#define APS_CXX_AUDIO_DETECTKEY_MUTEX       (82)

サブコアに計測アルゴリズムを統合する

以降は、サブコア上にデータが揃っていますので、サブコア上にアルゴリズムを実装するだけで、サービスに最適な信号処理を備えたシステムを構築することができます。

まとめ

今回の記事では、SPRESENSE SDKの提供する様々な機能から、自社で開発しているサービスにあわせて必要なパーツをピックアップ、解析処理や加工処理を統合し、マルチコアを活用した高速なエッジデバイスを実現する流れを紹介しました。この年末年始、是非チャレンジしてみてください。

今後はさらに便利なサブコアを直接デバッグする機能の紹介や、クラウドやゲートウェイと連携できるIoTシステムに求められる通信機能との統合(LTE-M)、長期運用を達成するために欠かせない低消費電力化を達成する方法に迫ります。ご期待ください。

SPRESENSE Audio Subsystemをデバッグする際の注意点

ExamplesのAudio RecorderやAudio Playerを支える、オーディオ処理の根幹であるSPRESENSE Audio Subsystemは、サブコア上で実行されるソフトウェア・エンコーダ、SPRESENSE SDKの提供するメモリ管理機能(Memory Manager, Memory Utility)、ハードウェアのオーディオI/O制御機能を統合した高度な機能ブロックです。メインコアの処理だけで完結した機能でないことから、Audio Subsystemが録音/再生中にCPUのブレークポイントがアクティブになると、空きメモリなどが枯渇しAttentionが発生することがあります(図8)。

図
図8:Audio Subsystem実行中にメインコアを停止させるとAttentionが発生する

Attention Codeの詳細はSPRESENSE SDK開発ガイドをご参照ください。