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

Committer:
MikamiUitOpen
Date:
Mon Jul 23 05:53:29 2018 +0000
Revision:
4:fe1885675421
Parent:
3:74a50c14d3fd
Child:
5:fcc1b0b4737e
5

Who changed what in which revision?

UserRevisionLine numberNew contents of line
MikamiUitOpen 0:a539141b9dec 1 //---------------------------------------------------------------------
MikamiUitOpen 3:74a50c14d3fd 2 // スペクトログラム (Nucleo-F446RE 用)
MikamiUitOpen 0:a539141b9dec 3 //
MikamiUitOpen 0:a539141b9dec 4 // ● ST-Link Firmware の V2.J28.M16 で動作確認
MikamiUitOpen 0:a539141b9dec 5 //
MikamiUitOpen 0:a539141b9dec 6 // ● ST-Link Firmware のアップグレードには stsw-link07.zip
MikamiUitOpen 0:a539141b9dec 7 // に含まれている "ST-LinkUpgrade.exe" を使う
MikamiUitOpen 0:a539141b9dec 8 //
MikamiUitOpen 0:a539141b9dec 9 // ● PC 側のプログラム: "F446_Spectrogram"
MikamiUitOpen 0:a539141b9dec 10 // ● ボーレート: 460800 baud
MikamiUitOpen 0:a539141b9dec 11 // ● 受信データの文字列の終了マーク: "\r"
MikamiUitOpen 0:a539141b9dec 12 //
MikamiUitOpen 4:fe1885675421 13 // ● 入力 A0: 左チャンネル,A1 右チャンネル
MikamiUitOpen 4:fe1885675421 14 // ● 出力 A2: 左チャンネル,D13 右チャンネル
MikamiUitOpen 4:fe1885675421 15 // 入力をそのまま出力する
MikamiUitOpen 4:fe1885675421 16 //
MikamiUitOpen 4:fe1885675421 17 // 2018/07/23, Copyright (c) 2018 MIKAMI, Naoki
MikamiUitOpen 0:a539141b9dec 18 //---------------------------------------------------------------------
MikamiUitOpen 0:a539141b9dec 19
MikamiUitOpen 0:a539141b9dec 20 #include "mbed.h"
MikamiUitOpen 0:a539141b9dec 21 #include <string>
MikamiUitOpen 4:fe1885675421 22 #include "myFunction.hpp"
MikamiUitOpen 0:a539141b9dec 23 #include "Array.hpp"
MikamiUitOpen 0:a539141b9dec 24 #include "F446_ADC_Interrupt.hpp"
MikamiUitOpen 0:a539141b9dec 25 #include "FFT_Analyzer.hpp"
MikamiUitOpen 0:a539141b9dec 26 #include "LPC_Analyzer.hpp"
MikamiUitOpen 0:a539141b9dec 27 using namespace Mikami;
MikamiUitOpen 0:a539141b9dec 28
MikamiUitOpen 0:a539141b9dec 29 #ifndef __STM32F446xx_H
MikamiUitOpen 0:a539141b9dec 30 #error "Use Nucleo-F446RE"
MikamiUitOpen 0:a539141b9dec 31 #endif
MikamiUitOpen 0:a539141b9dec 32
MikamiUitOpen 0:a539141b9dec 33 const int N_FFT_ = 512; // FFT の点数
MikamiUitOpen 0:a539141b9dec 34 const int N_DATA_ = N_FFT_ + 1; // スペクトル解析に使うデータ数(差分処理を考慮)
MikamiUitOpen 0:a539141b9dec 35 const int N_FRAME_ = N_FFT_/2 + 1; // 1フレーム当たり標本化するデータ数
MikamiUitOpen 0:a539141b9dec 36 const int N_FFT_2_ = N_FFT_/2; // FFT の点数の半分
MikamiUitOpen 0:a539141b9dec 37 const float AMP_ = 1.0f/2048.0f; // uint16_t 型のデータを float 型に変換する際の定数
MikamiUitOpen 0:a539141b9dec 38
MikamiUitOpen 0:a539141b9dec 39 uint16_t xPing_[N_FRAME_]; // 標本化したデータのバッファ1
MikamiUitOpen 0:a539141b9dec 40 uint16_t xPong_[N_FRAME_]; // 標本化したデータのバッファ2
MikamiUitOpen 0:a539141b9dec 41 uint16_t *inPtr_ = xPing_; // AD 変換データの格納先を指すポインタ
MikamiUitOpen 0:a539141b9dec 42 uint16_t *outPtr_ = xPing_; // 取り出すデータを指すポインタ
MikamiUitOpen 0:a539141b9dec 43
MikamiUitOpen 0:a539141b9dec 44 __IO int inCount_ = 0; // 入力データのカウンタ
MikamiUitOpen 0:a539141b9dec 45 __IO int pingPong_ = 0; // 入力データの格納先,0: xPing_[], 1: xPong_[]
MikamiUitOpen 0:a539141b9dec 46 __IO bool full_ = false; // AD 変換データが満杯のとき true
MikamiUitOpen 0:a539141b9dec 47
MikamiUitOpen 0:a539141b9dec 48 const int FS_ = 16000; // 標本化周波数: 16 kHz
MikamiUitOpen 0:a539141b9dec 49 AdcDual_Intr myAdc_(FS_); // "F446_ADC_Interrupt.hpp" で定義
MikamiUitOpen 4:fe1885675421 50 DacDual myDac_; // "F446_DAC.cpp/hpp" で定義
MikamiUitOpen 0:a539141b9dec 51
MikamiUitOpen 0:a539141b9dec 52 // FFT によるスペクトル解析オブジェクトの生成
MikamiUitOpen 0:a539141b9dec 53 FftAnalyzer *fftAnlz_ = new FftAnalyzer(N_DATA_, N_FFT_);
MikamiUitOpen 0:a539141b9dec 54 // 線形予測法 によるスペクトル解析オブジェクトの生成
MikamiUitOpen 0:a539141b9dec 55 LpcAnalyzer *lpcAnlz_ = new LpcAnalyzer(N_DATA_, N_FFT_, 20);
MikamiUitOpen 2:acc16e3f91ac 56 AnalyzerBase *analyzer_ = fftAnlz_; // 最初は FFT を使う
MikamiUitOpen 0:a539141b9dec 57
MikamiUitOpen 4:fe1885675421 58 SerialRxTxIntr rxTx_(32, 115200*4); // PC との通信用
MikamiUitOpen 0:a539141b9dec 59
MikamiUitOpen 1:cc596a8d40c9 60 float empha_ = 1.0f; // 高域強調器の係数
MikamiUitOpen 0:a539141b9dec 61
MikamiUitOpen 0:a539141b9dec 62 // 入力チャンネルを選択する関数とそれを割り当てる関数ポインタ
MikamiUitOpen 0:a539141b9dec 63 float InputL(float x1, float x2) { return x1; }
MikamiUitOpen 0:a539141b9dec 64 float InputR(float x1, float x2) { return x2; }
MikamiUitOpen 0:a539141b9dec 65 float InputLR(float x1, float x2) { return (x1 + x2)/2; }
MikamiUitOpen 0:a539141b9dec 66 typedef float (*FP_INPUT)(float, float);
MikamiUitOpen 0:a539141b9dec 67 FP_INPUT InputCurrent = InputLR; // 最初は左右チャンネルを使う
MikamiUitOpen 0:a539141b9dec 68 FP_INPUT InputNew = InputCurrent;
MikamiUitOpen 0:a539141b9dec 69
MikamiUitOpen 0:a539141b9dec 70 // ADC 変換終了割り込みに対する割り込みサービス・ルーチン
MikamiUitOpen 0:a539141b9dec 71 void AdcIsr()
MikamiUitOpen 0:a539141b9dec 72 {
MikamiUitOpen 0:a539141b9dec 73 uint16_t sn1, sn2;
MikamiUitOpen 0:a539141b9dec 74 myAdc_.Read(sn1, sn2);
MikamiUitOpen 0:a539141b9dec 75 uint16_t xn = InputCurrent(sn1, sn2);
MikamiUitOpen 0:a539141b9dec 76 inPtr_[inCount_] = xn;
MikamiUitOpen 0:a539141b9dec 77 myDac_.Write(xn, xn);
MikamiUitOpen 0:a539141b9dec 78
MikamiUitOpen 0:a539141b9dec 79 if (++inCount_ >= N_FRAME_) // データが満杯か調べる
MikamiUitOpen 0:a539141b9dec 80 {
MikamiUitOpen 0:a539141b9dec 81 full_ = true; // データが満杯
MikamiUitOpen 0:a539141b9dec 82 inCount_ = 0; // 以降のデータ取得のため
MikamiUitOpen 0:a539141b9dec 83 pingPong_ = (pingPong_+1) & 0x01; // バッファの切り替えのため
MikamiUitOpen 0:a539141b9dec 84 inPtr_ = (pingPong_ == 0) ? xPing_ : xPong_; // バッファのポインタ指定
MikamiUitOpen 0:a539141b9dec 85 InputCurrent = InputNew; // 入力の切り替え
MikamiUitOpen 0:a539141b9dec 86 analyzer_->SetHighEmphasizer(empha_); // 高域強調の有無の指令
MikamiUitOpen 0:a539141b9dec 87 }
MikamiUitOpen 0:a539141b9dec 88 }
MikamiUitOpen 0:a539141b9dec 89
MikamiUitOpen 0:a539141b9dec 90 int main()
MikamiUitOpen 0:a539141b9dec 91 {
MikamiUitOpen 4:fe1885675421 92 const int DATA_SIZE = N_FFT_/2 + 1;
MikamiUitOpen 4:fe1885675421 93 Array<uint16_t> txData(DATA_SIZE); // 送信用データ
MikamiUitOpen 0:a539141b9dec 94 float sn[N_DATA_]; // スペクトル解析の対象となるデータ
MikamiUitOpen 0:a539141b9dec 95 float db[N_FRAME_]; // 解析結果である対数スペクトル [dB]
MikamiUitOpen 0:a539141b9dec 96 for (int n=0; n<N_DATA_; n++) sn[n] = 0;
MikamiUitOpen 0:a539141b9dec 97 for (int n=0; n<N_FRAME_; n++) xPong_[n] = 2048; // uint16_t 型の 0 に対応
MikamiUitOpen 0:a539141b9dec 98
MikamiUitOpen 4:fe1885675421 99 NVIC_SetPriority(ADC_IRQn, 0); // AD変換終了割り込みの優先度が最高
MikamiUitOpen 4:fe1885675421 100 NVIC_SetPriority(USART2_IRQn, 1);
MikamiUitOpen 0:a539141b9dec 101
MikamiUitOpen 4:fe1885675421 102 float levelShift = 20; // dB 計算の際のシフト量の初期値
MikamiUitOpen 0:a539141b9dec 103
MikamiUitOpen 0:a539141b9dec 104 full_ = false;
MikamiUitOpen 0:a539141b9dec 105 __IO bool ready = false; // スペクトルの計算終了で true
MikamiUitOpen 0:a539141b9dec 106 __IO bool okGo = false; // "GO" を受信したら true
MikamiUitOpen 4:fe1885675421 107
MikamiUitOpen 4:fe1885675421 108 myAdc_.SetIntrVec(&AdcIsr); // AD変換終了割り込みの割り当て
MikamiUitOpen 0:a539141b9dec 109 while (true)
MikamiUitOpen 0:a539141b9dec 110 {
MikamiUitOpen 1:cc596a8d40c9 111 // PC からのコマンドの解析
MikamiUitOpen 4:fe1885675421 112 if (rxTx_.IsEol()) // 受信バッファのデータが有効になった場合の処理
MikamiUitOpen 0:a539141b9dec 113 {
MikamiUitOpen 4:fe1885675421 114 string str = rxTx_.GetBuffer();
MikamiUitOpen 4:fe1885675421 115 if (str.substr(0, 3) == "ENQ")
MikamiUitOpen 4:fe1885675421 116 rxTx_.Tx("ACK");
MikamiUitOpen 4:fe1885675421 117 else if (str.substr(0, 2) == "GO")
MikamiUitOpen 0:a539141b9dec 118 {
MikamiUitOpen 4:fe1885675421 119 // str の内容
MikamiUitOpen 0:a539141b9dec 120 // [0] 'G'
MikamiUitOpen 0:a539141b9dec 121 // [1] 'O'
MikamiUitOpen 0:a539141b9dec 122 // [2] 入力チャンネルの選択:'L', 'R', or '+'
MikamiUitOpen 0:a539141b9dec 123 // [3] スペクトルの値のレベルシフト:' ' ~ 'I' が -20 ~ 20 に対応
MikamiUitOpen 0:a539141b9dec 124 // [4] 高域強調器の有無:'Y', 'N'
MikamiUitOpen 0:a539141b9dec 125 // [5] 解析方法 F: FFT,L: 線形予測法
MikamiUitOpen 0:a539141b9dec 126
MikamiUitOpen 4:fe1885675421 127 switch (str[2])
MikamiUitOpen 0:a539141b9dec 128 {
MikamiUitOpen 0:a539141b9dec 129 case 'L': InputNew = InputL; break;
MikamiUitOpen 0:a539141b9dec 130 case 'R': InputNew = InputR; break;
MikamiUitOpen 0:a539141b9dec 131 case '+': InputNew = InputLR; break;
MikamiUitOpen 0:a539141b9dec 132 default : InputNew = InputLR; break;
MikamiUitOpen 0:a539141b9dec 133 }
MikamiUitOpen 0:a539141b9dec 134
MikamiUitOpen 4:fe1885675421 135 levelShift = (float)(str[3] - ' '); // dB 計算の際のシフト量
MikamiUitOpen 0:a539141b9dec 136
MikamiUitOpen 4:fe1885675421 137 if (str[4] == 'Y') empha_ = 1.0f; // 高域強調器は有
MikamiUitOpen 4:fe1885675421 138 else empha_ = 0; // 高域強調器は無
MikamiUitOpen 0:a539141b9dec 139
MikamiUitOpen 4:fe1885675421 140 if (str[5] == 'F') analyzer_ = fftAnlz_; // FFT
MikamiUitOpen 4:fe1885675421 141 else analyzer_ = lpcAnlz_; // 線形予測法
MikamiUitOpen 0:a539141b9dec 142
MikamiUitOpen 0:a539141b9dec 143 okGo = true; // データの転送要求あり
MikamiUitOpen 0:a539141b9dec 144 }
MikamiUitOpen 0:a539141b9dec 145 }
MikamiUitOpen 0:a539141b9dec 146
MikamiUitOpen 0:a539141b9dec 147 if (full_) // 入力データが満杯かどうか調べる
MikamiUitOpen 0:a539141b9dec 148 {
MikamiUitOpen 0:a539141b9dec 149 full_ = false;
MikamiUitOpen 0:a539141b9dec 150
MikamiUitOpen 0:a539141b9dec 151 outPtr_ = (pingPong_ == 1) ? xPing_ : xPong_;
MikamiUitOpen 0:a539141b9dec 152 // フレームの後半のデータを前半に移動する
MikamiUitOpen 0:a539141b9dec 153 for (int n=0; n<N_FFT_2_; n++)
MikamiUitOpen 0:a539141b9dec 154 sn[n] = sn[n+N_FRAME_];
MikamiUitOpen 0:a539141b9dec 155 // フレームの後半には新しいデータを格納する
MikamiUitOpen 0:a539141b9dec 156 for (int n=0; n<N_FRAME_; n++)
MikamiUitOpen 0:a539141b9dec 157 sn[n+N_FFT_2_] = AMP_*(outPtr_[n] - 2048);
MikamiUitOpen 0:a539141b9dec 158
MikamiUitOpen 0:a539141b9dec 159 analyzer_->Execute(sn, db); // スペクトル解析の実行
MikamiUitOpen 0:a539141b9dec 160
MikamiUitOpen 2:acc16e3f91ac 161 const float FACTOR = 10000.0f/80.0f; // 表示範囲: 0 ~ 80 dB
MikamiUitOpen 4:fe1885675421 162 for (int n=0; n<DATA_SIZE; n++)
MikamiUitOpen 0:a539141b9dec 163 {
MikamiUitOpen 4:fe1885675421 164 float xDb = FACTOR*(db[n] + 30.0f + levelShift);
MikamiUitOpen 2:acc16e3f91ac 165 if (xDb > 10000.0f) xDb = 10000.0f;
MikamiUitOpen 2:acc16e3f91ac 166 if (xDb < 0.0f) xDb = 0.0f;
MikamiUitOpen 2:acc16e3f91ac 167 uint16_t spc = (uint16_t)xDb;
MikamiUitOpen 4:fe1885675421 168 txData[n] = spc;
MikamiUitOpen 0:a539141b9dec 169 }
MikamiUitOpen 0:a539141b9dec 170 ready = true; // スペクトル解析終了
MikamiUitOpen 0:a539141b9dec 171 }
MikamiUitOpen 0:a539141b9dec 172
MikamiUitOpen 0:a539141b9dec 173 // 転送要求がありスペクトル解析が終了している場合にデータを PC へ転送する
MikamiUitOpen 0:a539141b9dec 174 if (okGo && ready)
MikamiUitOpen 0:a539141b9dec 175 {
MikamiUitOpen 4:fe1885675421 176 Xfer(txData); // データを PC へ転送
MikamiUitOpen 0:a539141b9dec 177 ready = false;
MikamiUitOpen 0:a539141b9dec 178 okGo = false;
MikamiUitOpen 0:a539141b9dec 179 }
MikamiUitOpen 0:a539141b9dec 180 }
MikamiUitOpen 0:a539141b9dec 181 }
MikamiUitOpen 4:fe1885675421 182