耳による数字の定義:Arduinoでの実装

この記事では、すでに腺で行われている実験室作業No. 3で私のインスピレーションを具体化し続けます。 Goertzelアルゴリズムを使用して、Arduinoのトーンダイヤルモードで音で数字を検出することについて話します。



これを実装するために、Arduino UNO、エレクトレットマイク( adafruit )、およびMAX7219ドライバーを備えた8x8ディスプレイを使用しました。



アクションプラン





実装



実装に着手する前に、質問に答えます-Arduino UNOは私たちにとって十分なパフォーマンスを発揮しますか?



クロック周波数:16MHz

1サンプリングサイクルには13クロックサイクルかかります

最も高い精度を提供するプリスケーラ値:128



16 MHz / 13/128〜9615 Hz-望ましいサンプリング周波数であることがわかります。つまり、最大4.8 kHzの周波数で作業できます。



ADCチューニング



ADCの動作にはいくつかのモードがありますが、最も興味深いモードを以下にリストします(ADCSRBキーワードのデータシートの完全なリスト)





ADCセットアップコード、簡単にするためにフリーランモードを使用しました。



ADMUX = 0; // Channel sel, right-adj, use AREF pin ADCSRA = _BV(ADEN) | // ADC enable _BV(ADSC) | // ADC start _BV(ADATE) | // Auto trigger _BV(ADIE) | // Interrupt enable _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128:1 / 13 = 9615 Hz ADCSRB = 0; // Free-run mode DIDR0 = _BV(0); // Turn off digital input for ADC pin TIMSK0 = 0; // Timer0 off
      
      





信号処理



サンプルの完全な配列が入力されるとすぐに、ADCによる割り込みをオフにし、Goertzelアルゴリズムを使用してスペクトルの振幅を計算します。 この網羅的なリソースを使用してアルゴリズムの説明を競うことはしませんが、実装を説明します。



 void goertzel(uint8_t *samples, float *spectrum) { float v_0, v_1, v_2; float re, im, amp; for (uint8_t k = 0; k < IX_LEN; k++) { float cos = pgm_read_float(&(cos_t[k])); float sin = pgm_read_float(&(sin_t[k])); float a = 2. * cos; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i < N; i++) { v_0 = v_1; v_1 = v_2; v_2 = (float)(samples[i]) + a * v_1 - v_0; } re = cos * v_2 - v_1; im = sin * v_2; amp = sqrt(re * re + im * im); spectrum[k] = amp; } }
      
      





サインとコサインは、目的の周波数に対応するサンプルに対して以前に計算されました。 コードの完全版はこちらです。



結論



最も重要なことは、判明したことであり、Arduino UNOリソースは単純なサウンド処理に十分です。





ADCがデリケートなものであることを学んだ主な教訓は、キャラクターをコンソールに正常に認識して送信した後、ディスプレイを操作するために1週間デバッグすることに費やしました。マイクのグラウンドとmax7219を接続し、すべてのサンプルがすぐにノイズに変わったためです。



よかったでしょうか? はい、サンプリング周波数とサンプル数を選択して、目的の周波数がサンプリング格子と一致するようにすると、スペクトルの広がりを防ぐことができます。 このようなパラメーターは既にf = 8 kHz、N = 205です。この場合、フリーランモードではなく、タイマーオーバーフローでADCを実行する必要があり、違いは明らかです。







コースは終わりに近づいていますが、まだ多くのアイデアがあります。

ご清聴ありがとうございました。



All Articles