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

Dependencies:   Array_Matrix mbed SerialTxRxIntr DSP_ADDA UIT_FFT_Real Window

main.cpp

Committer:
MikamiUitOpen
Date:
2022-04-21
Revision:
2:2ca9f8a0f6ef
Parent:
1:d4e3f39ce206

File content as of revision 2:2ca9f8a0f6ef:

//---------------------------------------------------------------------
//  スペクトログラム (Nucleo-F446RE 用)
//
//      標本化周波数を 10 倍に設定し,アンチエイリアシングフィルタを使う
//
//      ● PC 側のプログラム: "CQ_Spectrogram"
//      ● ボーレート:       最初:   9600 baud
//                      通信確立後: 460800 baud
//      ● 受信データの文字列の終了マーク: "\r"
//
//      ● 入力:  A1
//
//  2022/04/21, Copyright (c) 2022 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);   // 標本化周波数: 102.4 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;
        }
    }
}