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:
Wed Mar 08 09:46:11 2017 +0000
Revision:
2:acc16e3f91ac
Parent:
1:cc596a8d40c9
Child:
3:74a50c14d3fd
3

Who changed what in which revision?

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