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
main.cpp@0:a539141b9dec, 2017-02-17 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Fri Feb 17 04:55:10 2017 +0000
- Revision:
- 0:a539141b9dec
- Child:
- 1:cc596a8d40c9
1
Who changed what in which revision?
User | Revision | Line number | New 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 | 0:a539141b9dec | 13 | // 2017/02/17, 三上 直樹 |
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 | 0:a539141b9dec | 52 | AnalyzerBase *analyzer_ = fftAnlz_; |
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 | 0:a539141b9dec | 57 | DigitalOut pulse(D2, 0); // 時間測定用 |
MikamiUitOpen | 0:a539141b9dec | 58 | |
MikamiUitOpen | 0:a539141b9dec | 59 | const int DATA_SIZE_ = N_FFT_/2 + 1; |
MikamiUitOpen | 0:a539141b9dec | 60 | Array<int16_t> txData_(DATA_SIZE_); // 送信用データ |
MikamiUitOpen | 0:a539141b9dec | 61 | string rxBuffer_; // 受信バッファ |
MikamiUitOpen | 0:a539141b9dec | 62 | float levelShift_ = 20; // dB 計算の際のシフト量の初期値 |
MikamiUitOpen | 0:a539141b9dec | 63 | float empha_ = 0.8f; // 高域強調器の係数 |
MikamiUitOpen | 0:a539141b9dec | 64 | |
MikamiUitOpen | 0:a539141b9dec | 65 | __IO bool eol_; // "\r" を受信した場合に true |
MikamiUitOpen | 0:a539141b9dec | 66 | |
MikamiUitOpen | 0:a539141b9dec | 67 | // 入力チャンネルを選択する関数とそれを割り当てる関数ポインタ |
MikamiUitOpen | 0:a539141b9dec | 68 | float InputL(float x1, float x2) { return x1; } |
MikamiUitOpen | 0:a539141b9dec | 69 | float InputR(float x1, float x2) { return x2; } |
MikamiUitOpen | 0:a539141b9dec | 70 | float InputLR(float x1, float x2) { return (x1 + x2)/2; } |
MikamiUitOpen | 0:a539141b9dec | 71 | typedef float (*FP_INPUT)(float, float); |
MikamiUitOpen | 0:a539141b9dec | 72 | FP_INPUT InputCurrent = InputLR; // 最初は左右チャンネルを使う |
MikamiUitOpen | 0:a539141b9dec | 73 | FP_INPUT InputNew = InputCurrent; |
MikamiUitOpen | 0:a539141b9dec | 74 | |
MikamiUitOpen | 0:a539141b9dec | 75 | // ADC 変換終了割り込みに対する割り込みサービス・ルーチン |
MikamiUitOpen | 0:a539141b9dec | 76 | void AdcIsr() |
MikamiUitOpen | 0:a539141b9dec | 77 | { |
MikamiUitOpen | 0:a539141b9dec | 78 | uint16_t sn1, sn2; |
MikamiUitOpen | 0:a539141b9dec | 79 | myAdc_.Read(sn1, sn2); |
MikamiUitOpen | 0:a539141b9dec | 80 | uint16_t xn = InputCurrent(sn1, sn2); |
MikamiUitOpen | 0:a539141b9dec | 81 | inPtr_[inCount_] = xn; |
MikamiUitOpen | 0:a539141b9dec | 82 | myDac_.Write(xn, xn); |
MikamiUitOpen | 0:a539141b9dec | 83 | |
MikamiUitOpen | 0:a539141b9dec | 84 | if (++inCount_ >= N_FRAME_) // データが満杯か調べる |
MikamiUitOpen | 0:a539141b9dec | 85 | { |
MikamiUitOpen | 0:a539141b9dec | 86 | full_ = true; // データが満杯 |
MikamiUitOpen | 0:a539141b9dec | 87 | inCount_ = 0; // 以降のデータ取得のため |
MikamiUitOpen | 0:a539141b9dec | 88 | pingPong_ = (pingPong_+1) & 0x01; // バッファの切り替えのため |
MikamiUitOpen | 0:a539141b9dec | 89 | inPtr_ = (pingPong_ == 0) ? xPing_ : xPong_; // バッファのポインタ指定 |
MikamiUitOpen | 0:a539141b9dec | 90 | InputCurrent = InputNew; // 入力の切り替え |
MikamiUitOpen | 0:a539141b9dec | 91 | analyzer_->SetHighEmphasizer(empha_); // 高域強調の有無の指令 |
MikamiUitOpen | 0:a539141b9dec | 92 | } |
MikamiUitOpen | 0:a539141b9dec | 93 | } |
MikamiUitOpen | 0:a539141b9dec | 94 | |
MikamiUitOpen | 0:a539141b9dec | 95 | int main() |
MikamiUitOpen | 0:a539141b9dec | 96 | { |
MikamiUitOpen | 0:a539141b9dec | 97 | float sn[N_DATA_]; // スペクトル解析の対象となるデータ |
MikamiUitOpen | 0:a539141b9dec | 98 | float db[N_FRAME_]; // 解析結果である対数スペクトル [dB] |
MikamiUitOpen | 0:a539141b9dec | 99 | for (int n=0; n<N_DATA_; n++) sn[n] = 0; |
MikamiUitOpen | 0:a539141b9dec | 100 | for (int n=0; n<N_FRAME_; n++) xPong_[n] = 2048; // uint16_t 型の 0 に対応 |
MikamiUitOpen | 0:a539141b9dec | 101 | |
MikamiUitOpen | 0:a539141b9dec | 102 | rxBuffer_ = ""; // 受信バッファのクリア |
MikamiUitOpen | 0:a539141b9dec | 103 | eol_ = false; |
MikamiUitOpen | 0:a539141b9dec | 104 | |
MikamiUitOpen | 0:a539141b9dec | 105 | pc_.baud(115200*4); // ボーレートの設定 |
MikamiUitOpen | 0:a539141b9dec | 106 | pc_.format(); // default: 8 bits, nonparity, 1 stop bit |
MikamiUitOpen | 0:a539141b9dec | 107 | |
MikamiUitOpen | 0:a539141b9dec | 108 | NVIC_SetPriority(ADC_IRQn, 1); // AD変換終了割り込みの優先度が最高 |
MikamiUitOpen | 0:a539141b9dec | 109 | NVIC_SetPriority(USART2_IRQn, 2); |
MikamiUitOpen | 0:a539141b9dec | 110 | |
MikamiUitOpen | 0:a539141b9dec | 111 | pc_.attach(&Rx); // 受信割り込みの割り当て |
MikamiUitOpen | 0:a539141b9dec | 112 | |
MikamiUitOpen | 0:a539141b9dec | 113 | full_ = false; |
MikamiUitOpen | 0:a539141b9dec | 114 | myAdc_.SetIntrVec(&AdcIsr); // AD変換終了割り込みの割り当て |
MikamiUitOpen | 0:a539141b9dec | 115 | |
MikamiUitOpen | 0:a539141b9dec | 116 | __IO bool ready = false; // スペクトルの計算終了で true |
MikamiUitOpen | 0:a539141b9dec | 117 | __IO bool okGo = false; // "GO" を受信したら true |
MikamiUitOpen | 0:a539141b9dec | 118 | while (true) |
MikamiUitOpen | 0:a539141b9dec | 119 | { |
MikamiUitOpen | 0:a539141b9dec | 120 | // PC からのコマンド解析 |
MikamiUitOpen | 0:a539141b9dec | 121 | if (eol_) |
MikamiUitOpen | 0:a539141b9dec | 122 | { |
MikamiUitOpen | 0:a539141b9dec | 123 | if (rxBuffer_.find("ENQ") != string::npos) |
MikamiUitOpen | 0:a539141b9dec | 124 | pc_.printf("ACK\n"); // "ACK" を PC へ転送 |
MikamiUitOpen | 0:a539141b9dec | 125 | else if (rxBuffer_.find("GO") != string::npos) |
MikamiUitOpen | 0:a539141b9dec | 126 | { |
MikamiUitOpen | 0:a539141b9dec | 127 | // rxBuffer_ の内容 |
MikamiUitOpen | 0:a539141b9dec | 128 | // [0] 'G' |
MikamiUitOpen | 0:a539141b9dec | 129 | // [1] 'O' |
MikamiUitOpen | 0:a539141b9dec | 130 | // [2] 入力チャンネルの選択:'L', 'R', or '+' |
MikamiUitOpen | 0:a539141b9dec | 131 | // [3] スペクトルの値のレベルシフト:' ' ~ 'I' が -20 ~ 20 に対応 |
MikamiUitOpen | 0:a539141b9dec | 132 | // [4] 高域強調器の有無:'Y', 'N' |
MikamiUitOpen | 0:a539141b9dec | 133 | // [5] 解析方法 F: FFT,L: 線形予測法 |
MikamiUitOpen | 0:a539141b9dec | 134 | |
MikamiUitOpen | 0:a539141b9dec | 135 | switch (rxBuffer_[2]) // 'L', 'R', or '+' |
MikamiUitOpen | 0:a539141b9dec | 136 | { |
MikamiUitOpen | 0:a539141b9dec | 137 | case 'L': InputNew = InputL; break; |
MikamiUitOpen | 0:a539141b9dec | 138 | case 'R': InputNew = InputR; break; |
MikamiUitOpen | 0:a539141b9dec | 139 | case '+': InputNew = InputLR; break; |
MikamiUitOpen | 0:a539141b9dec | 140 | default : InputNew = InputLR; break; |
MikamiUitOpen | 0:a539141b9dec | 141 | } |
MikamiUitOpen | 0:a539141b9dec | 142 | |
MikamiUitOpen | 0:a539141b9dec | 143 | levelShift_ = (float)(rxBuffer_[3] - ' '); // dB 計算の際のシフト量 |
MikamiUitOpen | 0:a539141b9dec | 144 | |
MikamiUitOpen | 0:a539141b9dec | 145 | if (rxBuffer_[4] == 'Y') empha_ = 0.8f; // 高域強調器は有 |
MikamiUitOpen | 0:a539141b9dec | 146 | else empha_ = 0; // 高域強調器は無 |
MikamiUitOpen | 0:a539141b9dec | 147 | |
MikamiUitOpen | 0:a539141b9dec | 148 | if (rxBuffer_[5] == 'F') analyzer_ = fftAnlz_; // FFT |
MikamiUitOpen | 0:a539141b9dec | 149 | else analyzer_ = lpcAnlz_; // 線形予測法 |
MikamiUitOpen | 0:a539141b9dec | 150 | |
MikamiUitOpen | 0:a539141b9dec | 151 | okGo = true; // データの転送要求あり |
MikamiUitOpen | 0:a539141b9dec | 152 | } |
MikamiUitOpen | 0:a539141b9dec | 153 | |
MikamiUitOpen | 0:a539141b9dec | 154 | eol_ = false; |
MikamiUitOpen | 0:a539141b9dec | 155 | rxBuffer_ = ""; // 受信バッファのクリア |
MikamiUitOpen | 0:a539141b9dec | 156 | wait_ms(1); |
MikamiUitOpen | 0:a539141b9dec | 157 | } |
MikamiUitOpen | 0:a539141b9dec | 158 | |
MikamiUitOpen | 0:a539141b9dec | 159 | if (full_) // 入力データが満杯かどうか調べる |
MikamiUitOpen | 0:a539141b9dec | 160 | { |
MikamiUitOpen | 0:a539141b9dec | 161 | full_ = false; |
MikamiUitOpen | 0:a539141b9dec | 162 | |
MikamiUitOpen | 0:a539141b9dec | 163 | outPtr_ = (pingPong_ == 1) ? xPing_ : xPong_; |
MikamiUitOpen | 0:a539141b9dec | 164 | // フレームの後半のデータを前半に移動する |
MikamiUitOpen | 0:a539141b9dec | 165 | for (int n=0; n<N_FFT_2_; n++) |
MikamiUitOpen | 0:a539141b9dec | 166 | sn[n] = sn[n+N_FRAME_]; |
MikamiUitOpen | 0:a539141b9dec | 167 | // フレームの後半には新しいデータを格納する |
MikamiUitOpen | 0:a539141b9dec | 168 | for (int n=0; n<N_FRAME_; n++) |
MikamiUitOpen | 0:a539141b9dec | 169 | sn[n+N_FFT_2_] = AMP_*(outPtr_[n] - 2048); |
MikamiUitOpen | 0:a539141b9dec | 170 | |
MikamiUitOpen | 0:a539141b9dec | 171 | analyzer_->Execute(sn, db); // スペクトル解析の実行 |
MikamiUitOpen | 0:a539141b9dec | 172 | |
MikamiUitOpen | 0:a539141b9dec | 173 | const float FACTOR = 4095.0f/60.0f; // 表示範囲: 0 ~ 60 dB |
MikamiUitOpen | 0:a539141b9dec | 174 | for (int n=0; n<DATA_SIZE_; n++) |
MikamiUitOpen | 0:a539141b9dec | 175 | { |
MikamiUitOpen | 0:a539141b9dec | 176 | int16_t spc = (int16_t)(FACTOR*(db[n] + 30.0f + levelShift_)); |
MikamiUitOpen | 0:a539141b9dec | 177 | if (spc > 4095) spc = 4095; |
MikamiUitOpen | 0:a539141b9dec | 178 | if (spc < 0) spc = 0; |
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 | } |