スペクトログラム このプログラムの説明は,CQ出版社「トランジスタ技術」の2021年10月号から開始された連載記事「STM32マイコンではじめるPC計測」の中にあります.このプログラムといっしょに使うPC側のプログラムについても同誌を参照してください.

Dependencies:   Array_Matrix mbed SerialTxRxIntr DSP_ADDA UIT_FFT_Real Window

Revision:
0:3bf11d2ab6ad
Child:
1:d4e3f39ce206
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Sep 09 08:55:42 2021 +0000
@@ -0,0 +1,124 @@
+//---------------------------------------------------------------------
+//  スペクトログラム (Nucleo-F446RE 用)
+//
+//      標本化周波数を 10 倍に設定し,アンチエイリアシングフィルタを使う
+//
+//      ● PC 側のプログラム: "CQ_Spectrogram"
+//      ● ボーレート:    最初:        9600 baud
+//                      通信確立後: 460800 baud
+//      ● 受信データの文字列の終了マーク: "\r"
+//
+//      ● 入力:  A1
+//
+//  2021/07/11, Copyright (c) 2021 MIKAMI, Naoki
+//---------------------------------------------------------------------
+
+#include <string>
+#include "Array.hpp"
+#include "DSP_AdcIntr.hpp"
+#include "Coefs_IIR_LP.hpp" // 縦続形 IIR フィルタの係数
+#include "IirCascade.hpp"   // 縦続形 IIR フィルタ
+#include "FFT_Spectrogram.hpp"
+#include "DoubleBuffer.hpp"
+#include "XferSpectrum.hpp"
+using namespace Mikami;
+
+#ifndef __STM32F446xx_H
+#error "Use Nucleo-F446RE"
+#endif
+
+const int N_FFT_ = 512;             // FFT の点数
+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 int RATIO_ = 10;              // オーバーサンプリングの倍率
+const int N_TX_ = 251;              // PC に転送するデータ数
+
+DspAdcIntr myAdc_(10.24f*RATIO_, A1);   // 標本化周波数: 100 kHz
+IirCascade aaf_(ORDER1_, CK1_, G01_);   // ダウンサンプリング用 Anti-alias フィルタ
+DoubleBuffer<float> buf_(N_FRAME_); // AD の結果を保存するダブル・バッファ
+
+// ADC 変換終了割り込みに対する割り込みサービス・ルーチン
+void AdcIsr()
+{
+    static int count = 0;
+
+    float xn = myAdc_.Read();
+    float yn = aaf_.Execute(xn);    // ダウンサンプリング用 Anti-alias フィルタの実行
+
+    if (++count >= RATIO_)
+    {
+        buf_.Store(yn);         // ダウンサンプリングされたデータをバッファへ格納
+        count = 0;
+        buf_.IsFullSwitch();    // バッファが満杯であればバッファを切り替える
+    }
+}
+
+int main()
+{
+    // FFT によるスペクトル解析オブジェクトの生成
+    FftSpectropgram analyzer(N_DATA_, N_FFT_);
+    float empha;                    // 高域強調器の係数
+
+    SerialRxTxIntr rxTx;            // PC との通信用
+    XferSpectrum tx(rxTx, N_TX_);   // PC に転送するためのオブジェクトの生成
+
+    Array<float> sn(N_FFT_+1, 0.0f);    // スペクトル解析の対象となるデータ
+    Array<float> absFt(N_FRAME_);   // 解析結果:スペクトルの絶対値
+
+    NVIC_SetPriority(ADC_IRQn, 0);      // AD変換終了割り込みの優先度が最高
+    NVIC_SetPriority(USART2_IRQn, 1);
+
+    bool ready = false;     // スペクトルの計算終了で true
+    bool okGo = false;      // "GO" を受信したら true
+
+    myAdc_.SetIntrVec(&AdcIsr); // AD変換終了割り込みの割り当て
+    while (true)
+    {
+        // PC からのコマンドの解析
+        if (rxTx.IsEol())       // 受信バッファのデータが有効になった場合の処理
+        {
+            string str = rxTx.GetBuffer();
+            if (str == "Spectrogram")
+            {
+                rxTx.TxString("ACK\n"); // PC からの "Spectrogram" に対して "ACK" を送信する
+                wait_ms(10);
+                rxTx.Baud(460800);      // 以降は 460,800 baud
+            }
+            else if (str.substr(0, 2) == "GO")
+            {
+                // str の内容
+                // [0]  'G'
+                // [1]  'O'
+                // [2]  高域強調の有無:'Y', 'N'
+
+                if (str[2] == 'Y') empha = 1.0f;    // 高域強調は有効
+                else               empha = 0;       // 高域強調は無効
+
+                okGo = true;            // データの転送要求あり
+            }
+        }
+
+        if (buf_.IsFull())  // 入力データが満杯の場合,以下の処理を行う
+        {
+            // フレームの後半のデータを前半に移動する
+            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_] = buf_.Get(n);
+
+            analyzer.SetHighEmphasizer(empha);  // 高域強調の有無の指令
+            analyzer.Execute(sn, absFt);        // スペクトル解析の実行
+            ready = true;               // スペクトル解析終了
+        }
+
+        // 転送要求がありスペクトル解析が終了している場合にデータを PC へ転送する
+        if (okGo && ready)
+        {
+            tx.ToPC(absFt);     // データを PC へ転送
+            ready = false;
+            okGo = false;
+        }
+    }
+}
\ No newline at end of file