スペクトログラム このプログラムの説明は,CQ出版社「トランジスタ技術」の2021年10月号から開始された連載記事「STM32マイコンではじめるPC計測」の中にあります.このプログラムといっしょに使うPC側のプログラムについても同誌を参照してください.
Dependencies: Array_Matrix mbed SerialTxRxIntr DSP_ADDA UIT_FFT_Real Window
main.cpp
- Committer:
- MikamiUitOpen
- Date:
- 2021-12-08
- Revision:
- 1:d4e3f39ce206
- Parent:
- 0:3bf11d2ab6ad
- Child:
- 2:2ca9f8a0f6ef
File content as of revision 1:d4e3f39ce206:
//--------------------------------------------------------------------- // スペクトログラム (Nucleo-F446RE 用) // // 標本化周波数を 10 倍に設定し,アンチエイリアシングフィルタを使う // // ● PC 側のプログラム: "CQ_Spectrogram" // ● ボーレート: 最初: 9600 baud // 通信確立後: 460800 baud // ● 受信データの文字列の終了マーク: "\r" // // ● 入力: A1 // // 2021/11/17, Copyright (c) 2021 MIKAMI, Naoki //--------------------------------------------------------------------- #include <string> #include "Array.hpp" #include "DSP_AdcIntr.hpp" #include "FFT_Spectrogram.hpp" #include "DoubleBuffer.hpp" #include "Coefs_IIR_LP.hpp" // 縦続形 IIR フィルタの係数 #include "IirCascade.hpp" // 縦続形 IIR フィルタ #include "XferSpectrum.hpp" using namespace Mikami; #ifndef __STM32F446xx_H #error "Use Nucleo-F446RE" #endif const int N_FFT_ = 512; // FFT の点数 const int N_SMPL_ = N_FFT_/2; // 1度に標本化するデータ数 const int N_SPC_ = N_FFT_/2 + 1; // 有効なスペクトルの点数 const int RATIO_ = 10; // ダウンサンプリングの倍率:1/10 const int N_TX_ = 251; // PC に転送するデータ数 DspAdcIntr myAdc_(10.24f*RATIO_, A1); // 標本化周波数: 100 kHz IirCascade aaf_(ORDER1_, CK1_, G01_); // ダウンサンプリング用 Anti-alias フィルタ DoubleBuffer buf_(N_SMPL_); // ダウンサンプリングの結果を保存するダブル・バッファ // 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() { SerialRxTxIntr rxTx; // PC との通信用 XferSpectrum tx(rxTx, N_TX_); // PC に転送するためのオブジェクトの生成 FftSpectropgram analyzer(N_FFT_); // スペクトログラムで使うオブジェクトの生成 Array<float> sn(N_FFT_, 0.0f); // スペクトル解析の対象となるデータ Array<float> absFt(N_SPC_); // 解析結果:スペクトルの絶対値 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 } if (str.substr(0, 2) == "GO") { analyzer.SwEmphasis(str[2] == 'Y'); okGo = true; // データの転送要求あり } } if (buf_.IsFull()) // 入力データが満杯の場合,以下の処理を行う { // フレームの後半のデータを前半に移動する for (int n=0; n<N_SMPL_; n++) sn[n] = sn[n+N_SMPL_]; // フレームの後半には新しいデータを格納する for (int n=0; n<N_SMPL_; n++) sn[n+N_SMPL_] = buf_.Get(n); analyzer.Execute(sn, absFt); // スペクトル解析の実行 ready = true; // スペクトル解析終了 } // 転送要求がありスペクトル解析が終了している場合にデータを PC へ転送する if (okGo && ready) { tx.ToPC(absFt); // データを PC へ転送 ready = false; okGo = false; } } }