Realtime sound spectrogram using FFT or linear prediction. Spectrogram is displayed on the display of PC. リアルタイム・スペクトログラム.解析の手法:FFT,線形予測法.スペクトログラムは PC のディスプレー装置に表示される.PC 側のプログラム:F446_Spectrogram.

Dependencies:   Array_Matrix mbed SerialTxRxIntr F446_AD_DA UIT_FFT_Real

Revision:
7:5ba884060d3b
Parent:
6:c38ec7939609
--- a/main.cpp	Sun Nov 04 10:41:02 2018 +0000
+++ b/main.cpp	Sun Nov 24 11:14:01 2019 +0000
@@ -14,16 +14,17 @@
 //      ● 出力  A2: 左チャンネル,D13 右チャンネル
 //             入力をそのまま出力する
 //
-//  2018/11/04, Copyright (c) 2018 MIKAMI, Naoki
+//  2018/11/24, Copyright (c) 2018 MIKAMI, Naoki
 //---------------------------------------------------------------------
 
 #include "mbed.h"
 #include <string>
-#include "myFunction.hpp"
 #include "Array.hpp"
 #include "F446_ADC_Interrupt.hpp"
 #include "FFT_Analyzer.hpp"
 #include "LPC_Analyzer.hpp"
+#include "DoubleBufferMatrix.hpp"
+#include "Xfer.hpp"
 using namespace Mikami;
 
 #ifndef __STM32F446xx_H
@@ -34,30 +35,11 @@
 const int N_DATA_ = N_FFT_ + 1;     // スペクトル解析に使うデータ数(差分処理を考慮)
 const int N_FRAME_ = N_FFT_/2 + 1;  // 1フレーム当たり標本化するデータ数
 const int N_FFT_2_ = N_FFT_/2;      // FFT の点数の半分
-const float AMP_ = 1.0f/2048.0f;    // uint16_t 型のデータを float 型に変換する際の定数
-
-uint16_t xPing_[N_FRAME_];  // 標本化したデータのバッファ1
-uint16_t xPong_[N_FRAME_];  // 標本化したデータのバッファ2
-uint16_t *inPtr_ = xPing_;  // AD 変換データの格納先を指すポインタ
-uint16_t *outPtr_ = xPing_; // 取り出すデータを指すポインタ
-
-__IO int inCount_ = 0;      // 入力データのカウンタ
-__IO int pingPong_ = 0;     // 入力データの格納先,0: xPing_[], 1: xPong_[]
-__IO bool full_ = false;    // AD 変換データが満杯のとき true
 
 const int FS_ = 16000;      // 標本化周波数: 16 kHz
 AdcDual_Intr myAdc_(FS_);   // "F446_ADC_Interrupt.hpp" で定義
 DacDual myDac_;             // "F446_DAC.cpp/hpp" で定義
-
-// FFT によるスペクトル解析オブジェクトの生成
-FftAnalyzer *fftAnlz_ = new FftAnalyzer(N_DATA_, N_FFT_);
-// 線形予測法 によるスペクトル解析オブジェクトの生成
-LpcAnalyzer *lpcAnlz_ = new LpcAnalyzer(N_DATA_, N_FFT_, 20);
-AnalyzerBase *analyzer_ = fftAnlz_;     // 最初は FFT を使う
-
-SerialRxTxIntr rxTx_(32, 115200*4);     // PC との通信用
-
-float empha_ = 1.0f;        // 高域強調器の係数
+DoubleBuffer<float> buf_(N_FRAME_); // AD の結果を保存するダブル・バッファ
 
 // 入力チャンネルを選択する関数とそれを割り当てる関数ポインタ
 float InputL(float x1, float x2) { return x1; }
@@ -70,50 +52,48 @@
 // ADC 変換終了割り込みに対する割り込みサービス・ルーチン
 void AdcIsr()
 {
-    uint16_t sn1, sn2;
+    float sn1, sn2;
     myAdc_.Read(sn1, sn2);
-    uint16_t xn = InputCurrent(sn1, sn2);
-    inPtr_[inCount_] = xn;
+    float xn = InputCurrent(sn1, sn2);
+    buf_.Store(xn);     // バッファへ格納
     myDac_.Write(xn, xn);
 
-    if (++inCount_ >= N_FRAME_) // データが満杯か調べる
-    {
-        full_ = true;           // データが満杯
-        inCount_ = 0;           // 以降のデータ取得のため
-        pingPong_ = (pingPong_+1) & 0x01;               // バッファの切り替えのため
-        inPtr_ = (pingPong_ == 0) ? xPing_ : xPong_;    // バッファのポインタ指定
-        InputCurrent = InputNew;                // 入力の切り替え
-        analyzer_->SetHighEmphasizer(empha_);   // 高域強調の有無の指令
-    }
+    if (buf_.IsFullSwitch())        // バッファが満杯であればバッファを切り替える
+        InputCurrent = InputNew;    // 入力の切り替え
 }
 
 int main()
 {
-    const int DATA_SIZE = N_FFT_/2 + 1;
-    Array<uint16_t> txData(DATA_SIZE);     // 送信用データ
-    float sn[N_DATA_];      // スペクトル解析の対象となるデータ
-    float db[N_FRAME_];     // 解析結果である対数スペクトル [dB]
-    for (int n=0; n<N_DATA_; n++) sn[n] = 0;
-    for (int n=0; n<N_FRAME_; n++) xPong_[n] = 2048;    // uint16_t 型の 0 に対応
+    // FFT によるスペクトル解析オブジェクトの生成
+    FftAnalyzer *fftAnlz_ = new FftAnalyzer(N_DATA_, N_FFT_);
+    // 線形予測法 によるスペクトル解析オブジェクトの生成
+    LpcAnalyzer *lpcAnlz_ = new LpcAnalyzer(N_DATA_, N_FFT_, 20);
+    AnalyzerBase *analyzer = fftAnlz_;  // 最初は FFT を使う
+    float empha = 1.0f;                 // 高域強調器の係数
+
+    SerialRxTxIntr rxTx(32, 115200*4);  // PC との通信用
+    Xfer tx(rxTx, N_FFT_/2+1);          // PC に転送するためのオブジェクトの生成
+
+    Array<float> sn(N_FFT_, 0.0f);  // スペクトル解析の対象となるデータ
+    Array<float> db(N_FRAME_);      // 解析結果:対数スペクトル [dB]
 
     NVIC_SetPriority(ADC_IRQn, 0);      // AD変換終了割り込みの優先度が最高
     NVIC_SetPriority(USART2_IRQn, 1);
 
     float levelShift = 20;  // dB 計算の際のシフト量の初期値
 
-    full_ = false;
-    __IO bool ready = false;    // スペクトルの計算終了で true
-    __IO bool okGo = false;     // "GO" を受信したら true
+    bool ready = false;     // スペクトルの計算終了で true
+    bool okGo = false;      // "GO" を受信したら true
 
     myAdc_.SetIntrVec(&AdcIsr); // AD変換終了割り込みの割り当て
     while (true)
     {
         // PC からのコマンドの解析
-        if (rxTx_.IsEol())      // 受信バッファのデータが有効になった場合の処理
+        if (rxTx.IsEol())       // 受信バッファのデータが有効になった場合の処理
         {
-            string str = rxTx_.GetBuffer();
+            string str = rxTx.GetBuffer();
             if (str == "Spectrogram")
-                rxTx_.Tx("ACK\n");  // PC からの "Spectrogram" に対して "ACK" を送信する
+                rxTx.Tx("ACK\n");   // PC からの "Spectrogram" に対して "ACK" を送信する
             else if (str.substr(0, 2) == "GO")
             {
                 // str の内容
@@ -134,46 +114,35 @@
 
                 levelShift = (float)(str[3] - ' ');     // dB 計算の際のシフト量
 
-                if (str[4] == 'Y') empha_ = 1.0f;       // 高域強調器は有
-                else               empha_ = 0;          // 高域強調器は無
+                if (str[4] == 'Y') empha = 1.0f;        // 高域強調器は有
+                else               empha = 0;           // 高域強調器は無
 
-                if (str[5] == 'F') analyzer_ = fftAnlz_;    // FFT
-                else               analyzer_ = lpcAnlz_;    // 線形予測法
+                if (str[5] == 'F') analyzer = fftAnlz_; // FFT
+                else               analyzer = lpcAnlz_; // 線形予測法
  
                 okGo = true;            // データの転送要求あり
             }
         }
 
-        if (full_)  // 入力データが満杯かどうか調べる
+        if (buf_.IsFull())  // 入力データが満杯の場合,以下の処理を行う
         {
-            full_ = false;
-
-            outPtr_ = (pingPong_ == 1) ? xPing_ : xPong_;
             // フレームの後半のデータを前半に移動する
             for (int n=0; n<N_FFT_2_; n++)
                 sn[n] = sn[n+N_FRAME_];
             // フレームの後半には新しいデータを格納する
             for (int n=0; n<N_FRAME_; n++)
-                sn[n+N_FFT_2_] = AMP_*(outPtr_[n] - 2048);
-
-            analyzer_->Execute(sn, db); // スペクトル解析の実行
+                sn[n+N_FFT_2_] = buf_.Get(n);
 
-            const float FACTOR = 10000.0f/80.0f;     // 表示範囲: 0 ~ 80 dB
-            for (int n=0; n<DATA_SIZE; n++)
-            {
-                float xDb = FACTOR*(db[n] + 30.0f + levelShift);
-                if (xDb > 10000.0f) xDb = 10000.0f;
-                if (xDb < 0.0f) xDb = 0.0f;
-                uint16_t spc = (uint16_t)xDb;
-                txData[n] = spc;
-            }
-            ready = true;       // スペクトル解析終了
+            analyzer->SetHighEmphasizer(empha); // 高域強調の有無の指令
+            analyzer->Execute(sn, db);  // スペクトル解析の実行
+            tx.Convert(db, levelShift); // スペクトル解析の結果を転送する形式に変換
+            ready = true;               // スペクトル解析終了
         }
 
         // 転送要求がありスペクトル解析が終了している場合にデータを PC へ転送する
         if (okGo && ready)
         {
-            Xfer(txData);       // データを PC へ転送
+            tx.ToPC();      // データを PC へ転送
             ready = false;
             okGo = false;
         }