SORACOM IoT レシピ:モーターの音からAIで異常検知
この記事は最終更新日から1年以上が経過しています。
高性能マイコンによる音響データ × エッジAIで機器の異常を検知する
作成日: 2022年7月
レシピ難易度:★★★★★
モーターや発電機といった回転する装置には音の周期があり、長期の稼働や故障により変化することがわかっています。本レシピは、AIを用いて音の周期の変化から機器の異常検知を実現します。

本レシピを行うのに必要な時間、概算費用
- 必要な時間:約270分
- 概算費用:約20,000円
※ 概算費用: ハードウェアや SORACOM を始めとした各種サービスの概ねの費用 (送料などの付帯費用や無料枠適用は考慮しないものとしています)
使用するSORACOMサービス
- データ通信サービス SORACOM Air
- データ収集・蓄積サービス SORACOM Harvest Data
- ダッシュボード作成・共有サービス SORACOM Lagoon
用意するもの
本レシピを行うためには以下のものをご用意ください。
ハードウェア
| 品名 | 数量 | 価格 | 備考 |
| Spresense メインボード+ LTE拡張 ボードスターターキット | 1 | 14,828円 | 本キットにはSORACOM 特定地域向け IoT SIM(plan-D nano データ通信のみ)が同梱されています。 |
| SORACOM 特定地域向け IoT SIM (plan-D ナノサイズ) | 1 | ― | SPRESENSE LTE拡張ボードが対応しているSIMサイズはナノサイズです。スターターキットに同梱されています。 |
| Mic-kit for SPRESENSE_LTE | 1 | 2,100円 | SPRESENSEにて音を収集する際に利用するマイクキットです。 |
| microSDカード | 1 | 500-1000円 | 学習データの保存用に利用します。 大容量である必要はありませんので、安価なものやお手持ちのものを利用いただいてもかまいません。 |
| 開発用パソコン | 1 | ― | インターネット接続が可能でサイトへの接続が自由であること。USB Type-A ポートが最低1つ以上用意出来ること。USB ポートからの電力供給が1A以上であること。OS は macOS(10.12 Sierra 以上) Linux Ubuntu 16.04 (64bit版)以降もしくは Windows(8.1 以上)。管理者権限を有しており、アプリケーションやドライバソフトウェアのインストールが自由であること。Arduino IDE と SPRESENSE 開発環境が整っていること (セットアップ方法は Spresense Arduino スタートガイドをご覧ください) |
| (必要な方のみ)USB 変換アダプタ | 1 | ― | SPRESENSE とパソコンを USB ケーブルで接続する際に利用します。パソコンに USB Type-A ポートがない場合はご用意ください。1A 以上の電力が供給できるものを利用してください。(USB 3.0以上に対応していれば概ね安心です) |
| (必要な方のみ)SDカードリーダライター | 1 | ― |
※ 金額はレシピ作成時となります。金額は税込み・送料別です。その他は参考価格となります。
ご購入について
ハードウェアは以下よりご購入いただけます。
- Spresense メインボード + LTE拡張 ボードスターターキット
- SORACOM 特定地域向け IoT SIM (plan-D ナノサイズ)
- Mic-kit for SPRESENSE_LTE
ご購入先にはSORACOM IoT ストア以外のショッピングサイトも含まれています。ご購入先や在庫、動作保証をするものではありませんのでご留意ください。
その他必要な物
| 必要なもの | 費用 | 作成方法など |
| SORACOM アカウント | 無料※ | SORACOM アカウントの作成 (JP) |
| Neural Network Consoleアカウント | 無料※ | https://dl.sony.com/ja/cloud/ の「今すぐはじめる」からメールアドレスとパスワードを入力し、アカウントを作成できます |
※ アカウント作成・維持の費用の料金です。
このコンテンツの進め方
上から内容を読み進みながら作業を行なっていきます。また左サイドに追従する目次からページ内の移動が可能です。
本コンテンツは現状のままで提供され、株式会社ソラコムは、誤りがないことの保証を含め、明示であると黙示であるとを問わず、本コンテンツの記載内容につき、いかなる種類の表明も保証も行いません。
掲載情報の閲覧及び利用により、利用者自身、もしくは第三者が被った損害に対して、直接的、間接的を問わず、株式会社ソラコムは責任を負いかねます。
本コンテンツを実践する中で用意された機器、利用されたサービスについてのご質問は、それぞれの機器やサービスの提供元にお問い合わせをお願いします。機器やサービスの仕様は、本コンテンツ作成当時のものです。
株式会社ソラコムが提供する機器・サービスについてのご質問はフォームで受け付けております。機器・サービスご利用前の導入相談は https://soracom.jp/contact/ に、機器・サービスご利用開始後のサポートは、SORACOMユーザーコンソール内のサポートサイトから「リクエストを送信」(要ログイン)にてお問い合わせください。
Copyright (c) 2023 SORACOM, INC.
Mic-Kit(マイクロフォン)とmicroSDの動作を確認する
事前の確認
開発用パソコンに下の準備が整っているか確認します。整っていない場合は、先にセットアップを済ませてから、作業を続けることになります。
USBドライバのインストール
開発用パソコンに、こちらのサイトからUSBシリアルドライバをダウンロードし、インストールしてください。
ライブラリのインストール
SPRESENSEを利用するためのパッケージをインストールします。
メインボード,拡張ボード,マイクロフォンを組み立てる
外観は以下の通りです。
| メインボード | ![]() |
| LTE拡張ボード | ![]() |
| Mic-kit for SPRESENSE_LTE | ![]() |
メインボードとLTE拡張ボードを付属のスペーサを使って接続します。

Mic-kit for SPRESENSE_LTEの基板のピンソケットをLTE拡張ボードのピンヘッダに接続します。

基板のジャックにアナログマイクを接続します。

LTE拡張ボードのスロットにmicroSDカードを挿入します。

USBドライバーのインストール
開発用PCにArduino IDEで作成したプログラムを書き込むためのドライバーをインストールする必要があります。お使いのプラットフォームに合わせてこちらのサイトから、ダウンロードしてください。
Spresense Arduino Board Packageのインストール
Spresense の Arduino IDE用ライブラリと開発環境をインストールします。ライブラリをインストールするには、以下の手順で、ArduinoIDEのボードマネージャにSpresenseライブラリーを設定してください。
Arduino IDEを起動して、メニューの「ファイル」から「環境設定」を開きます。

「追加のボードマネージャのURL」に次のURLを入力して「OK」をクリックします。
https://github.com/sonydevworld/spresense-arduino-compatible/releases/download/generic/package_spresense_index.json

メニューから「ツール」→「ボード」→「ボードマネージャ」を選択します。

検索ボックスに「Spre」と入力すると、Spresenseのパッケージが見つかるので、「インストール」ボタンをクリックしてインストールします。

ボードマネージャに「インストール済み」と表示されたら、インストール作業は終了です。

ブートローダーのインストール
出荷状態のSPRESENSEを利用するにはブートローダーをインストールする必要があります。
以下の手順で実施します。
micro USB Type-B の USB ケーブルを用いて PC と Spresense メインボードを接続します。
通電すると、青いLEDが点灯します。

「ツール」→「ボード」→「 Spresense Boards」 → 「Spresense」を選択します。

「ツール」→「ポート」から、USBシリアルポートを選択します。

「ツール」→「書き込み装置」→「Spresense Firware Updater」を選択します。

「ツール」→「ブートローダーを書き込む」を選択します。

End User License Agreement のダイアログ内にあるライセンス条項を確認し、 I Accept the terms in the license agreement にチェックを付けた後 OK ボタンをクリックしてください。

「出力」に、
Restarting the board …
Reboot
が表示され、再びSpresenseメインボードの青いLEDが点灯したら完了となります。

DSPファイルをインストールする
Spresenseの録音機能を使うには、DSPファイルを事前にインストールする必要があります。今回はSDカードにDSPファイルをインストールします。
「ファイル」→「スケッチ例」→「Audio」→「dsp_installer」→「mp3_enc_installer」を選択し、スケッチ(mp3_enc_installer.ino)を開きます。

「→」ボタンをクリックし、Spresenseに書き込みます。

書き込みが完了したら、「ツール」→「シリアルモニタ」を選択してシリアルモニタを開きます(この時、通信速度は115200を選択してください)。
テキストボックスに「1」と入力して「Enter」を押します。

シリアルモニタに
Finished.
の表示がでたらDSPファイルのインストール完了です。mp3録音機能を使用するときは、DSPファイルをインストールしたmicroSDを忘れずに挿入してください。

マイクから録音した音声をmicroSDにmp3で保存するスケッチ
Arduino IDE を起動し[ファイル]>[New Sketch]を開くと void setup() { から始まる「空のスケッチ」が表示されます。
一度スケッチの内容を削除してから、後述のスケッチで置き換えてください。

/*
* mic_mp3_test.ino - Simple recording example application
* Copyright 2022 Sony Semiconductor Solutions Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Audio.h>
#include <SDHCI.h>
SDClass SD;
File myFile;
AudioClass *theAudio = AudioClass::getInstance();
static const int32_t recording_time_ms = 10000; /* 10秒 */
static int32_t start_time_ms;
void setup() {
Serial.begin(115200);
while (!SD.begin()){ Serial.println("Insert SD card."); }
theAudio->begin();
theAudio->setRecorderMode(AS_SETRECDR_STS_INPUTDEVICE_MIC);
theAudio->initRecorder(AS_CODECTYPE_MP3, "/mnt/sd0/BIN"
, AS_SAMPLINGRATE_48000, AS_CHANNEL_MONO);
if (SD.exists("Sound.mp3")) {
SD.remove("Sound.mp3");
}
myFile = SD.open("Sound.mp3", FILE_WRITE);
if (!myFile) {
Serial.println("File open error\n");
while(1);
}
theAudio->startRecorder();
start_time_ms = millis();
Serial.println("Start Recording");
}
void loop() {
uint32_t duration_ms = millis() - start_time_ms;
err_t err = theAudio->readFrames(myFile);
if (duration_ms > recording_time_ms
|| err != AUDIOLIB_ECODE_OK) {
theAudio->stopRecorder();
theAudio->closeOutputFile(myFile);
theAudio->setReadyMode();
theAudio->end();
Serial.println("End Recording");
while(1);
}
}マイコンボードに書き込む
ファイルの保存ダイアログが表示されたら
ファイルを保存してください。ファイル名は任意ですが mic_mp3_test というファイル名はどうでしょうか。
ファイルを保存しない (キャンセル) してもコンパイルとスケッチの転送はされます。
実行の様子
書き込み完了後、シリアルモニタを開くと、
「Start Recording」と表示された約10秒後に「End Recording」と表示され、10秒間マイクから収音した音声が保存されます。

録音した音声をPCで再生してみる
SpresenseからmicroSDを取り外し、PCのmicroSDスロットに挿入します。
PCかmicroSD内を確認すると「Sound.mp3」という名前のファイルが保存されていることが確認できます。

mp3ファイルを再生できるプレイヤーで再生し、先ほどの10秒間の音声が再生できればマイクとmicroSDが問題なく利用できることの確認は完了です。

音声が聞こえない場合などは、ボードおよびマイクの接続を確認してください。
学習用データを収集する
異常判定をしたい装置の正常動作時の音響データを収集します。

ここでは、収集した音響データをSpresenseでFFT処理した結果を、microSD内に保存していきます。
Arduino IDE を起動し[ファイル]>[新規ファイル]を開くと void setup() { から始まる「空のスケッチ」が表示されます。
一度スケッチの内容を削除してから、後述のスケッチで置き換えてください。
/*
* fft_datacollection.ino - FFT data collection sample for Autoeconder systems
* Copyright 2022 Sony Semiconductor Solutions Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Audio.h>
#include <FFT.h>
#include <SDHCI.h>
SDClass SD;
#define FFT_LEN 1024
// モノラル、1024サンプルでFFTを初期化
FFTClass<AS_CHANNEL_MONO, FFT_LEN> FFT;
AudioClass* theAudio = AudioClass::getInstance();
void avgFilter(float dst[FFT_LEN]) {
static const int avg_filter_num = 8;
static float pAvg[avg_filter_num][FFT_LEN/2];
static int g_counter = 0;
if (g_counter == avg_filter_num) g_counter = 0;
for (int i = 0; i < FFT_LEN/2; ++i) {
pAvg[g_counter][i] = dst[i];
float sum = 0;
for (int j = 0; j < avg_filter_num; ++j) {
sum += pAvg[j][i];
}
dst[i] = sum / avg_filter_num;
}
++g_counter;
}
void setup() {
Serial.begin(115200);
// SDカードの挿入を待つ
while (!SD.begin()) {Serial.println("Insert SD card");};
// ハミング窓、モノラル、オーバーラップ50%
FFT.begin(WindowHamming, AS_CHANNEL_MONO, (FFT_LEN/2));
Serial.println("Init Audio Recorder");
theAudio->begin();
// 入力をマイクに設定
theAudio->setRecorderMode(AS_SETRECDR_STS_INPUTDEVICE_MIC);
// 録音設定:フォーマットはPCM (16ビットRAWデータ)、
// DSPコーデックの場所の指定 (SDカード上のBINディレクトリ)、
// サンプリグレート 48000Hz、モノラル入力
int err = theAudio->initRecorder(AS_CODECTYPE_PCM
,"/mnt/sd0/BIN", AS_SAMPLINGRATE_48000, AS_CHANNEL_MONO);
if (err != AUDIOLIB_ECODE_OK) {
Serial.println("Recorder initialize error");
while(1);
}
Serial.println("Start Recorder");
theAudio->startRecorder(); // 録音開始
}
void loop() {
static const uint32_t buffering_time =
FFT_LEN*1000/AS_SAMPLINGRATE_48000;
static const uint32_t buffer_size = FFT_LEN*sizeof(int16_t);
static const int ch_index = AS_CHANNEL_MONO-1;
static char buff[buffer_size];
static float pDst[FFT_LEN];
uint32_t read_size;
// buffer_sizeで要求されたデータをbuffに格納する
// 読み込みできたデータ量は read_size に設定される
int ret = theAudio->readFrames(buff, buffer_size, &read_size);
if (ret != AUDIOLIB_ECODE_OK &&
ret != AUDIOLIB_ECODE_INSUFFICIENT_BUFFER_AREA) {
Serial.println("Error err = "+String(ret));
theAudio->stopRecorder();
while(1);
}
if (read_size < buffer_size) {
delay(buffering_time);
return;
}
FFT.put((q15_t*)buff, FFT_LEN); //FFTを実行
FFT.get(pDst, 0); // FFT演算結果を取得
avgFilter(pDst); // 過去のFFT演算結果で平滑化
static uint32_t last_capture_time = 0;
uint32_t capture_interval = millis() - last_capture_time;
// 1秒経過したら記録する
if (capture_interval > 1000) {
theAudio->stopRecorder(); // 録音停止
// saveData関数:SDカードにデータを記録
// データへのポインタ(pDst)
// 記録データのサイズ(FFT_LEN/8)
// データ保存数(100)
saveData(pDst, FFT_LEN/8, 100);
theAudio->startRecorder(); // 録音再開
last_capture_time = millis();
}
}
// SDカードにデータを記録
void saveData(float* pDst, int dsize, int quantity) {
static int gCounter = 0; // ファイル名につける追番
char filename[16] = {};
// 指定された保存数以上に達したら何もせずにリターン
if (gCounter > quantity) {
Serial.println("Data accumulated");
return;
}
// データ保存用ファイルを開く
sprintf(filename, "data%03d.csv", gCounter++);
// すでにファイルがあったら削除する
if (SD.exists(filename)) SD.remove(filename);
// ファイルをオープン
File myFile = SD.open(filename, FILE_WRITE);
// データの書き込み
for (int i = 0; i < dsize; ++i) {
myFile.println(String(pDst[i],6));
}
myFile.close(); // ファイルをクローズ
Serial.println("Data saved as " + String(filename));
}データ収集が完了すると、microSD内にdata000.csv〜 data100.csvというファイルが作成されます。
筆者がヘアドライヤー(一定速度で回転する装置を模擬)にマイクロフォンを近づけて取得したデータをプロットしたところ以下のような状況になっていました。
いくつかの周波数で特徴的なピークが見えているため、このピークが出現していることを元に正常・異常の判定をしていきます。また、初回に計測したデータはゲインが低いため学習、評価に使用するデータセットから除外することにします。

AI(オートエンコーダ)学習済みモデルを生成する
オートエンコーダ(自己符号化器)とは、学習によって入力データの特徴的な部分を中間層に圧縮し、出力時に元の次元に復元処理をするニューラルネットワークです。
正常なデータの特徴を圧縮処理し、覚えさせるため異常データが入手しにくい設備監視などによく用いられます。

今回は、前の作業で収集したFFT処理結果を使ってスペクトルの特徴をオートエンコーダに学習させていきます(モデルを作成していきます)。
モデル作成にはSONYの提供するNeural Netowrok Consoleを使用します。
データセットの準備
Spresenseで収集した学習用データをNeural Network Consoleのデータセットの形式に整えていきます。
今回は100個のデータのうち70個を学習用に、残りの30個をモデルの評価用に使用します。
まず、学習データ管理ファイルdata_train.csvを準備します。
data_train.csvには1行目にカラム名[x:fft]を、2行目以降に値の入ったファイルのパスをそれぞれ記載します。
以下をコピーしてテキストエディタなどに貼り付けて作成してください。
x:fft ./data_train/data001.csv ./data_train/data002.csv ./data_train/data003.csv ./data_train/data004.csv ./data_train/data005.csv ./data_train/data006.csv ./data_train/data007.csv ./data_train/data008.csv ./data_train/data009.csv ./data_train/data010.csv ./data_train/data011.csv ./data_train/data012.csv ./data_train/data013.csv ./data_train/data014.csv ./data_train/data015.csv ./data_train/data016.csv ./data_train/data017.csv ./data_train/data018.csv ./data_train/data019.csv ./data_train/data020.csv ./data_train/data021.csv ./data_train/data022.csv ./data_train/data023.csv ./data_train/data024.csv ./data_train/data025.csv ./data_train/data026.csv ./data_train/data027.csv ./data_train/data028.csv ./data_train/data029.csv ./data_train/data030.csv ./data_train/data031.csv ./data_train/data032.csv ./data_train/data033.csv ./data_train/data034.csv ./data_train/data035.csv ./data_train/data036.csv ./data_train/data037.csv ./data_train/data038.csv ./data_train/data039.csv ./data_train/data040.csv ./data_train/data041.csv ./data_train/data042.csv ./data_train/data043.csv ./data_train/data044.csv ./data_train/data045.csv ./data_train/data046.csv ./data_train/data047.csv ./data_train/data048.csv ./data_train/data049.csv ./data_train/data050.csv ./data_train/data051.csv ./data_train/data052.csv ./data_train/data053.csv ./data_train/data054.csv ./data_train/data055.csv ./data_train/data056.csv ./data_train/data057.csv ./data_train/data058.csv ./data_train/data059.csv ./data_train/data060.csv ./data_train/data061.csv ./data_train/data062.csv ./data_train/data063.csv ./data_train/data064.csv ./data_train/data065.csv ./data_train/data066.csv ./data_train/data067.csv ./data_train/data068.csv ./data_train/data069.csv ./data_train/data070.csv
microSDをSpresenseから取り出し、PCのmicroSDスロットに挿入します。以下のような構成でデータを配置します。

Neural Network Consoleに登録するデータセットとするため、これらのファイルとフォルダを圧縮してzipファイルにします。
全てのファイルを選択し、右クリックで出てきたメニューから圧縮を選択します。

作成したzipファイルを「data_train.zip」とします。

評価用データセット「data_valid.zip」を作成します。
学習用データセットを作成した手順と同様に、評価データ管理ファイルdata_valid.csvは、以下の内容として、data071.csv ~ data100.csvを、data_validというフォルダに格納し、これらのファイルを圧縮してください。
x:fft ./data_valid/data071.csv ./data_valid/data072.csv ./data_valid/data073.csv ./data_valid/data074.csv ./data_valid/data075.csv ./data_valid/data076.csv ./data_valid/data077.csv ./data_valid/data078.csv ./data_valid/data079.csv ./data_valid/data080.csv ./data_valid/data081.csv ./data_valid/data082.csv ./data_valid/data083.csv ./data_valid/data084.csv ./data_valid/data085.csv ./data_valid/data086.csv ./data_valid/data087.csv ./data_valid/data088.csv ./data_valid/data089.csv ./data_valid/data090.csv ./data_valid/data091.csv ./data_valid/data092.csv ./data_valid/data093.csv ./data_valid/data094.csv ./data_valid/data095.csv ./data_valid/data096.csv ./data_valid/data097.csv ./data_valid/data098.csv ./data_valid/data099.csv ./data_valid/data100.csv
Neural Network Consoleへデータセットをアップロードする
Neural Network Consoleにログインした後、「データセット」をクリックします。

上部メニューから「ブラウザからアップロード」を選択します。

開いた画面から、作成したデータファイル「data_train.zip」をドラッグアンドドロップした後、「upload」を選択します。

アップロードの準備が完了しました。というメッセージが出たら「OK」を選択します。

登録が完了するまで待ちます。登録が完了するとデータサイズや更新日時が表示されます。
(アップロードしてから、登録が完了するまで、約5分程度かかります。)

同様の手順で、「data_valid.zip」もアップロードします。
データセットから学習モデルを生成する
以下のNeural Network Consoleのプロジェクトファイルを開発用PCに保存します。
[Engine] SDeepEngineType=NNabla [Network_Global] NumLayer=10 NumLink=9 [Layer_0] ID=0 Type=Input Position_0=72 Position_1=48 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=Input Property_1_Name=Size Property_1_Value=128,1 Property_2_Name=Dataset Property_2_Value=x Property_3_Name=Generator Property_3_Value=None Property_4_Name=GeneratorMultiplier Property_4_Value=1.0 Property_5_Name=Order Property_5_Value=-1 NumProperty=6 [Layer_1] ID=40 Type=SquaredError Position_0=72 Position_1=480 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=SquaredError Property_1_Name=T.Dataset Property_1_Value=x Property_2_Name=T.Generator Property_2_Value=None Property_3_Name=T.GeneratorMultiplier Property_3_Value=1.0 NumProperty=4 [Layer_2] ID=51 Type=Affine Position_0=72 Position_1=96 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=Affine Property_1_Name=OutShape Property_1_Value=32 Property_2_Name=WithBias Property_2_Value=True Property_3_Name=ParameterScope Property_3_Value=*Name Property_4_Name=W.File Property_4_Value= Property_5_Name=W.Initializer Property_5_Value=NormalAffineGlorot Property_6_Name=W.InitializerMultiplier Property_6_Value=1.0 Property_7_Name=W.LRateMultiplier Property_7_Value=1.0 Property_8_Name=b.File Property_8_Value= Property_9_Name=b.Initializer Property_9_Value=Constant Property_10_Name=b.InitializerMultiplier Property_10_Value=0.0 Property_11_Name=b.LRateMultiplier Property_11_Value=1.0 NumProperty=12 [Layer_3] ID=53 Type=Affine Position_0=72 Position_1=384 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=Affine_2 Property_1_Name=OutShape Property_1_Value=128,1 Property_2_Name=WithBias Property_2_Value=True Property_3_Name=ParameterScope Property_3_Value=*Name Property_4_Name=W.File Property_4_Value= Property_5_Name=W.Initializer Property_5_Value=NormalAffineGlorot Property_6_Name=W.InitializerMultiplier Property_6_Value=1.0 Property_7_Name=W.LRateMultiplier Property_7_Value=1.0 Property_8_Name=b.File Property_8_Value= Property_9_Name=b.Initializer Property_9_Value=Constant Property_10_Name=b.InitializerMultiplier Property_10_Value=0.0 Property_11_Name=b.LRateMultiplier Property_11_Value=1.0 NumProperty=12 [Layer_4] ID=55 Type=Affine Position_0=72 Position_1=192 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=Affine_3 Property_1_Name=OutShape Property_1_Value=8 Property_2_Name=WithBias Property_2_Value=True Property_3_Name=ParameterScope Property_3_Value=*Name Property_4_Name=W.File Property_4_Value= Property_5_Name=W.Initializer Property_5_Value=NormalAffineGlorot Property_6_Name=W.InitializerMultiplier Property_6_Value=1.0 Property_7_Name=W.LRateMultiplier Property_7_Value=1.0 Property_8_Name=b.File Property_8_Value= Property_9_Name=b.Initializer Property_9_Value=Constant Property_10_Name=b.InitializerMultiplier Property_10_Value=0.0 Property_11_Name=b.LRateMultiplier Property_11_Value=1.0 NumProperty=12 [Layer_5] ID=57 Type=Affine Position_0=72 Position_1=288 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=Affine_4 Property_1_Name=OutShape Property_1_Value=32 Property_2_Name=WithBias Property_2_Value=True Property_3_Name=ParameterScope Property_3_Value=*Name Property_4_Name=W.File Property_4_Value= Property_5_Name=W.Initializer Property_5_Value=NormalAffineGlorot Property_6_Name=W.InitializerMultiplier Property_6_Value=1.0 Property_7_Name=W.LRateMultiplier Property_7_Value=1.0 Property_8_Name=b.File Property_8_Value= Property_9_Name=b.Initializer Property_9_Value=Constant Property_10_Name=b.InitializerMultiplier Property_10_Value=0.0 Property_11_Name=b.LRateMultiplier Property_11_Value=1.0 NumProperty=12 [Layer_6] ID=59 Type=ReLU Position_0=72 Position_1=144 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=ReLU Property_1_Name=InPlace Property_1_Value=*AutoInPlaceOnce NumProperty=2 [Layer_7] ID=60 Type=ReLU Position_0=72 Position_1=240 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=ReLU_2 Property_1_Name=InPlace Property_1_Value=*AutoInPlaceOnce NumProperty=2 [Layer_8] ID=61 Type=ReLU Position_0=72 Position_1=336 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=ReLU_3 Property_1_Name=InPlace Property_1_Value=*AutoInPlaceOnce NumProperty=2 [Layer_9] ID=62 Type=Sigmoid Position_0=72 Position_1=432 Position_2=240 Position_3=48 Property_0_Name=Name Property_0_Value=Sigmoid NumProperty=1 [Link_0] ID=0 SourceLayerID=0 SourcePinIndex=0 DestLayerID=51 DestPinIndex=0 [Link_1] ID=6 SourceLayerID=51 SourcePinIndex=0 DestLayerID=59 DestPinIndex=0 [Link_2] ID=7 SourceLayerID=59 SourcePinIndex=0 DestLayerID=55 DestPinIndex=0 [Link_3] ID=8 SourceLayerID=55 SourcePinIndex=0 DestLayerID=60 DestPinIndex=0 [Link_4] ID=9 SourceLayerID=60 SourcePinIndex=0 DestLayerID=57 DestPinIndex=0 [Link_5] ID=10 SourceLayerID=61 SourcePinIndex=0 DestLayerID=53 DestPinIndex=0 [Link_6] ID=11 SourceLayerID=57 SourcePinIndex=0 DestLayerID=61 DestPinIndex=0 [Link_7] ID=12 SourceLayerID=62 SourcePinIndex=0 DestLayerID=40 DestPinIndex=0 [Link_8] ID=13 SourceLayerID=53 SourcePinIndex=0 DestLayerID=62 DestPinIndex=0 [Dataset] Num=2 MainIndex=0 [Dataset_0] Name=Training URI=D:\My Documents\My Seminar\Spresense-LowPower-EdgeAI\Chap08\nnc_dataset\dataset\pipe_train.csv Shuffle=1 EnableCache=0 ImageNormalization=0 NumData=411 [Dataset_1] Name=Validation URI=D:\My Documents\My Seminar\Spresense-LowPower-EdgeAI\Chap08\nnc_dataset\dataset\pipe_valid.csv Shuffle=0 EnableCache=0 ImageNormalization=0 NumData=103 [Description] Text= [Config] MaxEpoch=100 SaveBest=1 BatchSize=64 TypeConfig=Float MonitorInterval=10 AutoEvaluation=0 NumOptimizer=1 NumMonitor=2 NumExecutor=1 [Optimizer_0] RangeFrom=-1 RangeTo=-1 RangeUnit=0 Optimizer_Name=Optimizer Optimizer_NetworkName=Main Optimizer_DatasetName=Training UpdateInterval=1 SolverName=Adam SolverParameterNum=4 SolverParameterName_0=Alpha SolverParameter_0=0.001 SolverParameterName_1=Beta1 SolverParameter_1=0.9 SolverParameterName_2=Beta2 SolverParameter_2=0.999 SolverParameterName_3=Epsilon SolverParameter_3=1e-08 WeightDecay=0 LearningRateScheduler=Exponential LearningRateMultiplier=1 LearningRateUpdateInterval=1 LearningRateUpdateIntervalUnit=0 LearningRatePower=1 LearningRateSteps= LearningRateWarmupScheduler=None LearningRateWarmupLength=0 LearningRateWarmupLengthUnit=0 [Monitor_0] Monitor_Name=train_error Monitor_NetworkName=MainValidation Monitor_DatasetName=Training [Monitor_1] Monitor_Name=valid_error Monitor_NetworkName=MainValidation Monitor_DatasetName=Validation [Executor_0] Executor_Name=Executor Executor_NetworkName=MainRuntime Executor_DatasetName=Validation NumEvaluations=1 RepeatEvaluationType=0 NeedBackPropagation=0 [StructureSearch] Enabled=0 Method=Random Objective=ErrorAndCalculation Validation_Min=-1 Validation_Max=-1 CostMultiplyAdd_Min=-1 CostMultiplyAdd_Max=-1 EarlyStopping=0 TimeLimit=0 [OutOfCoreTraining] Enabled=0 GPUMemorySize=0 WindowSize=0
このファイルには、128サンプルの入力を中間層で8まで圧縮し、再び128に広げる構造のネットワークの設計が記載されています。
これをNeural Network Consoleに読み込ませます。
Neural Network Console の左側メニューから「プロジェクト」を選択します。

プロジェクトのアップロードを選択します。

先程ダウンロードした「autoencoder.sdcproj」ファイルをドラッグアンドドロップしてアップロードします。

プロジェクトの一覧に表示されたらプロジェクトを選択し、詳細を表示します。

プロジェクトファイルの詳細を確認することで、オートエンコーダの設計が確認できます。

上部の「データセット」を選択し、アップロードしたデータセットをこのプロジェクトに紐づけます。

「Training」を選択し、データセットの選択の右にある「選択されていません」を選択すると表示される一覧から、学習用データセット「data_train」のリンクアイコンを選択してデータを紐付けます。

データの紐付けが正常に実施できると、登録したデータの波形グラフが表示されます。

同様の手順で、Validationに評価用データセット「data_valid」を紐付けます。
学習用および評価用のデータの紐付けが完了したら、「詳細設定」を選択し、「バッチサイズ」を「30」にします(今回の評価用データ数が30個のため、それ以下の大きさにする必要があります)。

バッチサイズを変更したら「編集」画面から、「実行」を選択します。

学習が完了すると、学習曲線が表示されます。
続いて、「実行」を選択して評価を実施します。

評価が完了すると、評価用データをモデルに入力して得られた出力の波形が表示されます。ピーク位置やレベルなどの特徴が抽出できていることを確認します。
右側のメニューのプルダウンで「NNB(NNabla C Runtime file format)」を選択し、「プロジェクトをダウンロード」ボタンをクリックすると、Spresenseで動作可能なモデルを入手できます。

ダウンロードしたファイル「result_v1.nnb」の名前を「model.nnb」に変更したあと、「model.nnb」をmicroSDの第一階層にコピーします。
PCからmicroSDを抜き、Spresenseに再び取り付けます。
SORACOM Harvest Dataにオートエンコーダの判定結果を蓄積する(グループの作成)
SORACOM の IoT データ収集・蓄積サービス SORACOM Harvest Data を利用して、データの可視化を簡単に実現してみましょう。
まずはグループの作成と、作成したグループへ SIM を所属させる事から始めます。
SORACOM Harvest Data とは?
IoT デバイスからのデータの収集や蓄積、およびファイルを保存するサービスが SORACOM Harvest (ソラコム ハーベスト) です。IoT デバイスからのデータの収集・蓄積対応しているのが SORACOM Harvest Data、画像ファイルやログファイルといったファイルに対応しているのが SORACOM Harvest Files となります。
SORACOM ユーザーコンソールにログインした後「メニュー」→「SIM 管理」とクリックして SIM 管理画面を開きます。

SORACOM Harvest Data でデータの収集を行いたい SIM (Spresense に取り付けた SIM) にチェックを付け、[操作]>[所属グループ変更]とクリックします。

「新しい所属グループ」のプルダウンボックスをクリックした後、[新しいグループを作成…]をクリックします。

「グループ作成」のグループ名を入力して「グループ作成」をクリックします。
| 項目 | 例 | 備考 |
| グループ名 | sound |

新しい所属グループが先ほど作成したグループになっていることを確認したら「キャンセル」をクリックします。

自動的に SIM 管理画面に戻ります。
SIM の「グループ」に先ほど作ったグループが設定されていることを確認してください。
SORACOM Harvest Dataにオートエンコーダの判定結果を蓄積する(グループの設定)
グループに「SORACOM Air for セルラー」と「SORACOM Harvest Data」の設定を行います。
SIM 管理画面から、SORACOM LTE-M Button に割り当てたグループ名をクリックします。

[SORACOM Air for セルラー 設定]をクリックして設定ができるように開きます。

「SORACOM Harvest Data 設定」で以下のように設定します。
| 項目 | 設定値 | 備考 |
| バイナリパーサー(スイッチ) | ON | スイッチはクリックすることで OFF から ON に切り替えることができます。 |
| フォーマット | 下記 | Spresensの送信データ(バイナリ)をJSONにパース |
001:0:float:32:little-endian 002:4:float:32:little-endian 003:8:float:32:little-endian 004:12:float:32:little-endian 005:16:float:32:little-endian 006:20:float:32:little-endian 007:24:float:32:little-endian 008:28:float:32:little-endian 009:32:float:32:little-endian 010:36:float:32:little-endian 011:40:float:32:little-endian 012:44:float:32:little-endian 013:48:float:32:little-endian 014:52:float:32:little-endian 015:56:float:32:little-endian 016:60:float:32:little-endian 017:64:float:32:little-endian 018:68:float:32:little-endian 019:72:float:32:little-endian 020:76:float:32:little-endian 021:80:float:32:little-endian 022:84:float:32:little-endian 023:88:float:32:little-endian 024:92:float:32:little-endian 025:96:float:32:little-endian 026:100:float:32:little-endian 027:104:float:32:little-endian 028:108:float:32:little-endian 029:112:float:32:little-endian 030:116:float:32:little-endian 031:120:float:32:little-endian 032:124:float:32:little-endian 033:128:float:32:little-endian 034:132:float:32:little-endian 035:136:float:32:little-endian 036:140:float:32:little-endian 037:144:float:32:little-endian 038:148:float:32:little-endian 039:152:float:32:little-endian 040:156:float:32:little-endian 041:160:float:32:little-endian 042:164:float:32:little-endian 043:168:float:32:little-endian 044:172:float:32:little-endian 045:176:float:32:little-endian 046:180:float:32:little-endian 047:184:float:32:little-endian 048:188:float:32:little-endian 049:192:float:32:little-endian 050:196:float:32:little-endian 051:200:float:32:little-endian 052:204:float:32:little-endian 053:208:float:32:little-endian 054:212:float:32:little-endian 055:216:float:32:little-endian 056:220:float:32:little-endian 057:224:float:32:little-endian 058:228:float:32:little-endian 059:232:float:32:little-endian 060:236:float:32:little-endian 061:240:float:32:little-endian 062:244:float:32:little-endian 063:248:float:32:little-endian 064:252:float:32:little-endian 065:256:float:32:little-endian 066:260:float:32:little-endian 067:264:float:32:little-endian 068:268:float:32:little-endian 069:272:float:32:little-endian 070:276:float:32:little-endian 071:280:float:32:little-endian 072:284:float:32:little-endian 073:288:float:32:little-endian 074:292:float:32:little-endian 075:296:float:32:little-endian 076:300:float:32:little-endian 077:304:float:32:little-endian 078:308:float:32:little-endian 079:312:float:32:little-endian 080:316:float:32:little-endian 081:320:float:32:little-endian 082:324:float:32:little-endian 083:328:float:32:little-endian 084:332:float:32:little-endian 085:336:float:32:little-endian 086:340:float:32:little-endian 087:344:float:32:little-endian 088:348:float:32:little-endian 089:352:float:32:little-endian 090:356:float:32:little-endian 091:360:float:32:little-endian 092:364:float:32:little-endian 093:368:float:32:little-endian 094:372:float:32:little-endian 095:376:float:32:little-endian 096:380:float:32:little-endian 097:384:float:32:little-endian 098:388:float:32:little-endian 099:392:float:32:little-endian 100:396:float:32:little-endian 101:400:float:32:little-endian 102:404:float:32:little-endian 103:408:float:32:little-endian 104:412:float:32:little-endian 105:416:float:32:little-endian 106:420:float:32:little-endian 107:424:float:32:little-endian 108:428:float:32:little-endian 109:432:float:32:little-endian 110:436:float:32:little-endian 111:440:float:32:little-endian 112:444:float:32:little-endian 113:448:float:32:little-endian 114:452:float:32:little-endian 115:456:float:32:little-endian 116:460:float:32:little-endian 117:464:float:32:little-endian 118:468:float:32:little-endian 119:472:float:32:little-endian 120:476:float:32:little-endian 121:480:float:32:little-endian 122:484:float:32:little-endian 123:488:float:32:little-endian 124:492:float:32:little-endian 125:496:float:32:little-endian 126:500:float:32:little-endian 127:504:float:32:little-endian 128:508:float:32:little-endian RMSE:512:float:32:little-endian

[SORACOM Harvest Data 設定]をクリックして設定ができるように開きます。

「SORACOM Harvest Data 設定」で以下のように設定します。
| 項目 | 設定値 | 備考 |
| (スイッチ) | ON | スイッチはクリックすることで OFF から ON に切り替えることができます。 |

最後に[保存]をクリックしてください。
その後表示される「SORACOM Harvest Data が有効になっています」のダイアログでは[OK]をクリックしてください。
以上で「SORACOM Harvest Data」の設定が完了しました。
SORACOM Harvest Dataにオートエンコーダの判定結果を蓄積する(SIMの取り付け)
SPRESENSEにSIM(nanoサイズ)を取り付けます。

SORACOM Harvest Dataにオートエンコーダの判定結果を蓄積する(スケッチの作成から確認まで)
Arduino IDE を起動し[ファイル]>[新規ファイル]を開くと void setup() { から始まる「空のスケッチ」が表示されます。
一度スケッチの内容を削除してから、下記スケッチで置き換えてください。
/*
* fft_autoencoder.ino - Autoencoder sample for a pipe anomaly detection
* Copyright 2022 Sony Semiconductor Solutions Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// libraries
#include <Audio.h>
#include <FFT.h>
#include <SDHCI.h>
SDClass SD;
#include <DNNRT.h>
DNNRT dnnrt;
#include <LTE.h>
// initialize the library instance
LTE lteAccess;
LTEScanner scannerNetworks;
LTEClient client;
/*
#include <ArduinoHttpClient.h>
HttpClient HttpClient;
#include <ArduinoJson.h>
*/
#include <stdio.h>
#define FFT_LEN 1024
// APN name
#define APP_LTE_APN "soracom.io" // replace your APN
/* APN authentication settings
* Ignore these parameters when setting LTE_NET_AUTHTYPE_NONE.
*/
#define APP_LTE_USER_NAME "sora" // replace with your username
#define APP_LTE_PASSWORD "sora" // replace with your password
// APN IP type
#define APP_LTE_IP_TYPE (LTE_NET_IPTYPE_V4V6) // IP : IPv4v6
// #define APP_LTE_IP_TYPE (LTE_NET_IPTYPE_V4) // IP : IPv4
// #define APP_LTE_IP_TYPE (LTE_NET_IPTYPE_V6) // IP : IPv6
// APN authentication type
#define APP_LTE_AUTH_TYPE (LTE_NET_AUTHTYPE_CHAP) // Authentication : CHAP
// #define APP_LTE_AUTH_TYPE (LTE_NET_AUTHTYPE_PAP) // Authentication : PAP
// #define APP_LTE_AUTH_TYPE (LTE_NET_AUTHTYPE_NONE) // Authentication : NONE
/* RAT to use
* Refer to the cellular carriers information
* to find out which RAT your SIM supports.
* The RAT set on the modem can be checked with LTEModemVerification::getRAT().
*/
#define APP_LTE_RAT (LTE_NET_RAT_CATM) // RAT : LTE-M (LTE Cat-M1)
// #define APP_LTE_RAT (LTE_NET_RAT_NBIOT) // RAT : NB-IoT
LTEUDP lteUdp;
char host[] = "harvest.soracom.io";
int port = 8514;
int ad_value = 0;
// URL, path & port (for example: arduino.cc)
//char server[] = "harvest.soracom.io";
unsigned long prev;
static const unsigned long interval = 10000;
// モノラル、1024サンプルでFFTを初期化
FFTClass<AS_CHANNEL_MONO, FFT_LEN> FFT;
AudioClass *theAudio = AudioClass::getInstance();
void avgFilter(float dst[FFT_LEN]) {
static const int avg_filter_num = 8;
static float pAvg[avg_filter_num][FFT_LEN];
static int g_counter = 0;
if (g_counter == avg_filter_num) g_counter = 0;
for (int i = 0; i < FFT_LEN; ++i) {
pAvg[g_counter][i] = dst[i];
float sum = 0;
for (int j = 0; j < avg_filter_num; ++j) {
sum += pAvg[j][i];
}
dst[i] = sum / avg_filter_num;
}
++g_counter;
}
void udpsend(int ad_value) {
Serial.println("UDP Send Start");
if (lteUdp.begin(port) == 1) {
if (lteUdp.beginPacket(host, port) == 1) {
Serial.println("UDP Data make Start");
char ad_str[10];
sprintf(ad_str, "ad=%04x", ad_value);
lteUdp.write(ad_str, 7);
if (lteUdp.endPacket() == 1) {
Serial.println("UDP Data Send OK");
delay(100);
} else {
Serial.println("UDP Data Send NG(endPacket)");
}
} else {
Serial.println("UDP Data make NG(beginPacket)");
}
lteUdp.stop();
Serial.println("UDP Send Stop");
}
}
void ltesetup() {
char apn[LTE_NET_APN_MAXLEN] = APP_LTE_APN;
LTENetworkAuthType authtype = APP_LTE_AUTH_TYPE;
char user_name[LTE_NET_USER_MAXLEN] = APP_LTE_USER_NAME;
char password[LTE_NET_PASSWORD_MAXLEN] = APP_LTE_PASSWORD;
Serial.println("LTE networks scanner");
while (true) {
// モデム電源をONしLTE通信機能を有効化する
if (lteAccess.begin() != LTE_SEARCHING) {
Serial.println("Could not transition to LTE_SEARCHING.");
Serial.println("Please check the status of the LTE board.");
for (;;) {
sleep(1);
}
}
// APNへの接続開始
if (lteAccess.attach(APP_LTE_RAT,
apn,
user_name,
password,
authtype,
APP_LTE_IP_TYPE)
== LTE_READY) {
Serial.println("attach succeeded.");
break;
}
/* If the following logs occur frequently, one of the following might be a cause:
* - APN settings are incorrect
* - SIM is not inserted correctly
* - If you have specified LTE_NET_RAT_NBIOT for APP_LTE_RAT,
* your LTE board may not support it.
* - Rejected from LTE network
*/
Serial.println("An error has occurred. Shutdown and retry the network attach process after 1 second.");
lteAccess.shutdown();
sleep(1);
}
}
void setup() {
Serial.begin(115200);
// SDカードの入力を待つ
while (!SD.begin()) { Serial.println("Insert SD card"); };
ltesetup();
Serial.println("Initialize DNNRT");
// SDカード上にある学習済モデルを読み込む
File nnbfile = SD.open("model.nnb");
;
if (!nnbfile) {
Serial.print("nnb not found");
while (1)
;
}
// 学習済モデルでDNNRTを開始する
int ret = dnnrt.begin(nnbfile);
if (ret < 0) {
Serial.print("DNN Runtime begin fail: " + String(ret));
while (1)
;
}
// ハミング窓、モノラル、オーバーラップ50%
FFT.begin(WindowHamming, AS_CHANNEL_MONO, (FFT_LEN / 2));
Serial.println("Init Audio Recorder");
// 入力をマイクに設定
theAudio->begin();
theAudio->setRecorderMode(AS_SETRECDR_STS_INPUTDEVICE_MIC);
// 録音設定:フォーマットはPCM (16ビットRAWデータ)、
// DSPコーデックの場所の指定 (SDカード上のBINディレクトリ)、
// サンプリグレート 48000Hz、モノラル入力
int err = theAudio->initRecorder(AS_CODECTYPE_PCM,
"/mnt/sd0/BIN", AS_SAMPLINGRATE_48000, AS_CHANNEL_MONO);
if (err != AUDIOLIB_ECODE_OK) {
Serial.println("Recorder initialize error");
while (1)
;
}
Serial.println("Start Recorder");
theAudio->startRecorder(); // 録音開始
//実行時間の初期化
prev = 0;
}
void loop() {
static const uint32_t buffering_time =
FFT_LEN * 1000 / AS_SAMPLINGRATE_48000;
static const uint32_t buffer_size = FFT_LEN * sizeof(int16_t);
static const int ch_index = AS_CHANNEL_MONO - 1;
static char buff[buffer_size]; // 録音データを格納するバッファ
static float pDst[FFT_LEN]; // FFT演算結果を格納するバッファ
uint32_t read_size;
// マイクやファン、パイプ、マイクの状態で数値は大きく変動します
// 実測をしてみて適切と思われる数値に設定してください
float maxSpectrum; // FFT演算結果を見て調整
static const float threshold = 1.0; // RSMEのばらつきを見て調整
// buffer_sizeで要求されたデータをbuffに格納する
// 読み込みできたデータ量は read_size に設定される
int ret = theAudio->readFrames(buff, buffer_size, &read_size);
if (ret != AUDIOLIB_ECODE_OK && ret != AUDIOLIB_ECODE_INSUFFICIENT_BUFFER_AREA) {
Serial.println("Error err = " + String(ret));
theAudio->stopRecorder();
exit(1);
}
if (read_size < buffer_size) {
delay(buffering_time);
return;
}
FFT.put((q15_t *)buff, FFT_LEN); //FFTを実行
FFT.get(pDst, 0); // FFT演算結果を取得
avgFilter(pDst); // 過去のFFT演算結果で平滑化
// DNNRTの入力データにFFT演算結果を設定
DNNVariable input(FFT_LEN / 8);
float *dnnbuf = input.data();
//maxSpectrumの算出
maxSpectrum = 1e-9;
for (int i = 0; i < FFT_LEN / 8; ++i) {
maxSpectrum = max(pDst[i], maxSpectrum);
}
for (int i = 0; i < FFT_LEN / 8; ++i) {
pDst[i] /= maxSpectrum; // 0.0~1.0に正規化
dnnbuf[i] = pDst[i];
}
// 推論を実行
dnnrt.inputVariable(input, 0);
dnnrt.forward();
DNNVariable output = dnnrt.outputVariable(0);
// 二乗平均平方根誤差(RSME)を計算
float sqr_err = 0.0;
for (int i = 0; i < FFT_LEN / 8; ++i) {
float err = pDst[i] - output[i];
sqr_err += sqrt(err * err / (FFT_LEN / 8));
}
// RSMEの結果を平均化
static const int delta_average = 16; // 平均回数
static float average[delta_average];
static uint8_t gCounter = 0;
average[gCounter++] = sqr_err;
if (gCounter == delta_average) gCounter = 0;
float avg_err = 0.0;
for (int i = 0; i < delta_average; ++i) {
avg_err += average[i];
}
avg_err /= delta_average;
// Serial.println("Result: " + String(avg_err, 7));
// 閾値でOK/NGを判定
bool bNG = false;
avg_err > threshold ? bNG = true : bNG = false;
// if (bNG) Serial.println("Fault on the machine");
// 定期的にFFTデータと判定結果をUDPで送信
unsigned long curr = millis(); // 現在時刻を取得
if ((curr - prev) >= interval) { // 前回実行時刻から実行周期以上経過していたら
Serial.println("UDP Send Start");
if (lteUdp.begin(port) == 1) {
if (lteUdp.beginPacket(host, port) == 1) {
Serial.println("UDP Data make Start");
//pDstに入っているfloat(4bytes)128個分のデータをudpの送信データに設定する
lteUdp.write((byte*) pDst,4*128);
float s_avg_err[1];
s_avg_err[0] = avg_err;
lteUdp.write((byte*) s_avg_err,4);
Serial.println(avg_err);
/** データ確認用シリアル出力
for (int i = 0; i < 10; ++i) {
Serial.print(pDst[i]);
Serial.println();
}
**/
if (lteUdp.endPacket() == 1) {
Serial.println("UDP Data Send OK");
delay(100);
} else {
Serial.println("UDP Data Send NG(endPacket)");
}
} else {
Serial.println("UDP Data make NG(beginPacket)");
}
lteUdp.stop();
Serial.println("UDP Send Stop");
}
prev += interval; // 前回実行時刻に実行周期を加算
}
}デフォルトのメモリサイズ(768KB)では、一連の処理を実行するためのメモリが足りなくなるためスケッチを書き込む前にメモリサイズを変更します。
メニューから、「ツール」→「Memory」→「1152KB」を選択します。

ここで選択するメモリサイズは、スケッチに記載された処理を実行するためのメモリサイズとなっており、起動時の初期化処理などにはこの外側のメモリが用いられます。そのため、1152KBより大きなメモリサイズを選択すると、初期化処理が実行できなくなってしまいます。
スケッチの書き込みが完了するとプログラムが開始されます。
正常に動作すると、シリアルモニタには以下のような表示がされます。

SORACOM Harvest Data で蓄積データを確認する
Spresense からのデータが SORACOM Harvest Data に表示されることを確認してみましょう。
SIM管理画面から、SORACOM Harvest Data でデータの収集を行いたい SIM (Spresense に取り付けた SIM) にチェックを付け、「操作」→「データを確認」とクリックします。

表示された画面で「自動更新」を ON にします。
この表示された画面が SORACOM Harvest Data の画面となります。

SORACOM Lagoon でダッシュボードを作成する(有効化まで)
設定と設置が完了したら、蓄積されたデータを SORACOM Lagoon で活用していきます。
| 用語 | 意味 |
| プラン | SORACOM Lagoon の契約プランです。機能と料金が異なります。SORACOM Lagoon のご利用料金に機能や料金の比較表があります。 |
| メトリクス(メトリック) | データが格納されている先です。SORACOM Lagoon では以下の4つの中から選び、その中からノード(SIMや回線)を選択します。・Air = SORACOM Air for セルラー・LoRa = SORACOM Air for LoRaWAN・Sigfox = SORACOM Air for Sigfox・Device = SORACOM Inventory デバイス |
| データソース | メトリクスの参照先です。SORACOM Lagoon では “Harvest” (= SORACOM Harvest) を選ぶとメトリクスが展開されます。 Grafana ではテスト用のランダムデータが表示されます。 |
| パネル | パネルはデータを表示する領域です。データソースとメトリクスを指定すると、そのメトリクス(たとえばSIM)のデータをパネルで使えるようになります。様々なパネルが存在します。 |
| ダッシュボード | 複数のパネルを束ねて「1枚の画面」にしたものがダッシュボードです。共有の単位となります。 |
| SORACOM Lagoon ユーザー(Lagoon ユーザー) | SORACOM Lagoon へログインするためのユーザー(IDとパスワードの組)SORACOM ユーザコンソールへのログインとは異なるユーザ一覧となり、皆さん自身で登録・削除が可能です。ダッシュボードやパネルを編集できる「編集可能」と表示専用の「読み取り」の2段階の権限を設定できます。作成可能数はプランによります。 |
| データリフレッシュ | SORACOM Harvest から SORACOM Lagoon へデータが反映される事、もしくは反映タイミングとなります。反映タイミングはプランによります。 |
| アラート | メトリクスのデータに対して条件を設定し、その条件を満たしたら通知を行う仕組みの事です。 |
SORACOM ユーザーコンソールの[メニュー]>[データ収集・蓄積・可視化]>[SORACOM Lagoon]とクリックします。

[SORACOM Lagoon の利用を開始する]をクリックします。

プランのうち[Free]を選択したあと[続行する]をクリックします。

SORACOM Lagoon ユーザーの初期ユーザーに設定するパスワードを入力した後、[利用開始]をクリックします。

SORACOM Lagoon ユーザーの初期ユーザの ID は?
ID は SORACOM ユーザコンソールにログインしたときのメールアドレスが使われることになります。そのため、ここではパスワードのみ設定することになります。SORACOM ユーザコンソールへのログインとは異なるパスワードを設定する事を強くお勧めします。
利用開始がクリックできない場合は?
パスワードの条件が不足しています。全てに✔がつくようにパスワードを設定してください。
SORACOM Lagoon の有効化に成功すると、以下のように SORACOM Lagoon コンソールへのリンクと、Lagoon ユーザーの一覧が管理できるようになります。

この画面を SORACOM Lagoon 管理画面と呼びます。
SORACOM Lagoon 管理画面を表示したあと、[SORACOM Lagoon3 コンソール]をクリックします。
※ SORACOM Lagoon 管理画面は [Menu]>[データ収集・蓄積・可視化]>[SORACOM Lagoon]で表示する事ができます。
SORACOM Lagoon へログインします。
メールアドレス (SORACOM ユーザコンソールへログインする際のメールアドレス) と、SORACOM Lagoon 初期ユーザ作成時に利用したパスワードでログインします。

ログインに成功すると、以下のような画面が表示されます。これが SORACOM Lagoon ログイン直後の画面です。ここから「ダッシュボード」や「パネル」を作成していきます。

SORACOM Lagoon でダッシュボードを作成する(パネル作成まで)
サイドメニューの「+」→「インポート」を選択します。

Import画面が表示されます。

表示されたImport画面のImport via panel jsonに、以下のJSONの中のIMSIという文字列をSpresenseに取り付けたSIMのIMSIに置換して貼り付けます。
貼り付けた後は「Load」をクリックします。
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 3928,
"links": [],
"panels": [
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"decimals": 3,
"displayName": "frequency",
"mappings": [],
"max": 1,
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 16,
"w": 24,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"displayMode": "gradient",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showUnfilled": true,
"text": {
"titleSize": 0,
"valueSize": 0
}
},
"pluginVersion": "7.5.10",
"targets": [
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "000",
"refId": "000",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "001",
"refId": "001",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "002",
"refId": "002",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "003",
"refId": "003",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "004",
"refId": "004",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "005",
"refId": "005",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "006",
"refId": "006",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "007",
"refId": "007",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "008",
"refId": "008",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "009",
"refId": "009",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "010",
"refId": "010",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "011",
"refId": "011",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "012",
"refId": "012",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "013",
"refId": "013",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "014",
"refId": "014",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "015",
"refId": "015",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "016",
"refId": "016",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "017",
"refId": "017",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "018",
"refId": "018",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "019",
"refId": "019",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "020",
"refId": "020",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "021",
"refId": "021",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "022",
"refId": "022",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "023",
"refId": "023",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "024",
"refId": "024",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "025",
"refId": "025",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "026",
"refId": "026",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "027",
"refId": "027",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "028",
"refId": "028",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "029",
"refId": "029",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "030",
"refId": "030",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "031",
"refId": "031",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "032",
"refId": "032",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "033",
"refId": "033",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "034",
"refId": "034",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "035",
"refId": "035",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "036",
"refId": "036",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "037",
"refId": "037",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "038",
"refId": "038",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "039",
"refId": "039",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "040",
"refId": "040",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "041",
"refId": "041",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "042",
"refId": "042",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "043",
"refId": "043",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "044",
"refId": "044",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "045",
"refId": "045",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "046",
"refId": "046",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "047",
"refId": "047",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "048",
"refId": "048",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "049",
"refId": "049",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "050",
"refId": "050",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "051",
"refId": "051",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "052",
"refId": "052",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "053",
"refId": "053",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "054",
"refId": "054",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "055",
"refId": "055",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "056",
"refId": "056",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "057",
"refId": "057",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "058",
"refId": "058",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "059",
"refId": "059",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "060",
"refId": "060",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "061",
"refId": "061",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "062",
"refId": "062",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "063",
"refId": "063",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "064",
"refId": "064",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "065",
"refId": "065",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "066",
"refId": "066",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "067",
"refId": "067",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "068",
"refId": "068",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "069",
"refId": "069",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "070",
"refId": "070",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "071",
"refId": "071",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "072",
"refId": "072",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "073",
"refId": "073",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "074",
"refId": "074",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "075",
"refId": "075",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "076",
"refId": "076",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "077",
"refId": "077",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "078",
"refId": "078",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "079",
"refId": "079",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "080",
"refId": "080",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "081",
"refId": "081",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "082",
"refId": "082",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "083",
"refId": "083",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "084",
"refId": "084",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "085",
"refId": "085",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "086",
"refId": "086",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "087",
"refId": "087",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "088",
"refId": "088",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "089",
"refId": "089",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "090",
"refId": "090",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "091",
"refId": "091",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "092",
"refId": "092",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "093",
"refId": "093",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "094",
"refId": "094",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "095",
"refId": "095",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "096",
"refId": "096",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "097",
"refId": "097",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "098",
"refId": "098",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "099",
"refId": "099",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "100",
"refId": "100",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "101",
"refId": "101",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "102",
"refId": "102",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "103",
"refId": "103",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "104",
"refId": "104",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "105",
"refId": "105",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "106",
"refId": "106",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "107",
"refId": "107",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "108",
"refId": "108",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "109",
"refId": "109",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "110",
"refId": "110",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "111",
"refId": "111",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "112",
"refId": "112",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "113",
"refId": "113",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "114",
"refId": "114",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "115",
"refId": "115",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "116",
"refId": "116",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "117",
"refId": "117",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "118",
"refId": "118",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "119",
"refId": "119",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "120",
"refId": "120",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "121",
"refId": "121",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "122",
"refId": "122",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "123",
"refId": "123",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "124",
"refId": "124",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "125",
"refId": "125",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "126",
"refId": "126",
"target": "IMSI",
"type": "timeseries"
},
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "127",
"refId": "127",
"target": "IMSI",
"type": "timeseries"
}
],
"title": "Spectrum",
"type": "bargauge"
},
{
"datasource": null,
"description": "",
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 1
},
{
"color": "red",
"value": 2
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 4,
"x": 0,
"y": 16
},
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"text": {},
"textMode": "auto"
},
"pluginVersion": "7.5.10",
"targets": [
{
"datatype": "standard",
"devicetype": "subscribers",
"properties": "RMSE",
"refId": "A",
"target": "IMSI",
"type": "timeseries"
}
],
"title": "RMSE(root mean squared error)",
"type": "stat"
}
],
"refresh": "5s",
"schemaVersion": 27,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-5m",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "SPRESENSE sound spectrum",
"uid": "",
"version": 10
}インポートが完了すると、以下のようなFFTのスペクトラムの最新データと、その左下にRMSE値を示すダッシュボードが表示されます。
「Access denied to this dashboard」と表示されることがあります
[Folder] で「General」を選択して [Import] をクリックすると、「Access denied to this dashboard」と表示されますが、動作に影響はありません。
保存ボタンをクリックするとダッシュボードが保存されます。

左下の表示色はRMSEの値に応じて変化させることができます。左下のRMSE値は、周囲環境や学習データによって正常と定義する範囲が異なります。
あとかたづけと注意事項
本レシピでは費用がかかるサービスを利用しています。
本項をよく読み、必要な操作や解除作業を行うようにして、想定外の費用が掛からないようにしてください。
費用について
ここで記載している金額は全て税込み、送料別となります。
SORACOM プラットフォームの利用料金
| サービス/機能 | 料金 |
| SORACOM Air (plan-D) | 基本料: 11円/日通信料: 0.22円~/MB(今回の利用であれば 1MB 以内で収まる範囲) |
| SORACOM Harvest Data | 本機能を有効にしたグループに所属する1SIMあたり5.5円/日 (2000リクエスト/日/SIMを含む)2000リクエスト/日を超えた分は0.0044円/リクエスト |
| SORACOM Lagoon | 本レシピでは Free プラン(無料)を使用しました。その他の有料プランで出来るようになること等は SORACOM Lagoon 利用料金のページをご覧ください。 |
※ 費用詳細はリンク先をご確認ください。
無料利用枠について
SORACOMサービスでは一部サービスにおいて無料枠が設定されています。たとえばSORACOM Air for セルラーであればアカウント毎で30円/月の通信分や、SORACOM Harvest Data であれば31日分の書込みリクエストなどです。料金詳細に「無料利用枠」として掲載されていますので、ご確認ください。
グループ解除
SORACOM Harvest Data 等、「機能が有効になっているグループに所属している SIM × 費用」となっているサービスにおいては、「機能を OFF にする」することで費用の発生を抑えることができます。またもう1つの方法として「グループに所属している SIM の数を減らす(= 解除する)」事でも費用を抑える事ができます。
グループ解除の方法はグループからの解除 (JP)をご覧ください。
SORACOM Harvest Data のデータ削除
SORACOM Harvest Data は基本的にはデータ保管料は無料※です。そのため、保存しておいても害はありませんが、デモ等で利用する際にはデータを綺麗にしておく必要が出てくるため、データ削除について解説します。
※発生から40日を超えたデータは削除されます。40日以上データを保管したい場合はデータ保持期間延長オプション利用料金をご利用ください。
SORACOM Harvest Data 画面 ([操作]>[データを確認]) のデータテーブルで、削除したいデータのチェックボックスを付けた後に[削除]をクリックします。表示されたダイアログで改めて[削除]をクリックすると、削除されます。
※ 複数のデータにチェックをつければ一括で削除可能です。
※発生から40日を超えたデータは削除されます。40日以上データを保管したい場合はデータ保持期間延長オプション利用料金をご利用ください。
次のステップ
本レシピでは、SPRESENSEを利用した音響データxエッジAIによる異常検知を実現してみました。データの送信先は SORACOM Harvest Data としましたが、SORACOM Beam / SORACOM Funnel / SORACOM Funk を利用することで通知を行ったり、他の機器を動かすといった事も可能となります。


