これを実装するために、Arduino UNO、エレクトレットマイク( adafruit )、およびMAX7219ドライバーを備えた8x8ディスプレイを使用しました。
アクションプラン
- 十分な数のサンプルを離散化します( 前の記事のプログラムを使用して、256で十分であると確信しました)。
- 文字をエンコードする目的の周波数に対応する周波数応答の振幅を見つけます。
- 振幅の2つの最大値は、目的の文字の行と列のインデックスを示します。たとえば、図3は次のようになります。
実装
実装に着手する前に、質問に答えます-Arduino UNOは私たちにとって十分なパフォーマンスを発揮しますか?
クロック周波数:16MHz
1サンプリングサイクルには13クロックサイクルかかります
最も高い精度を提供するプリスケーラ値:128
16 MHz / 13/128〜9615 Hz-望ましいサンプリング周波数であることがわかります。つまり、最大4.8 kHzの周波数で作業できます。
ADCチューニング
ADCの動作にはいくつかのモードがありますが、最も興味深いモードを以下にリストします(ADCSRBキーワードのデータシートの完全なリスト)
- 単一読み取り-analogRead()メソッドを使用しますが、これは100µsかかるブロッキング呼び出しであり、それを使用して一定のサンプリングレートを提供することは不可能です
- フリーランモード-このモードでは、前のサンプリングサイクルの直後に次のサンプリングサイクルが開始され、最大サンプリング周波数が提供されます。
- タイマーオーバーフロー-サンプリングはタイマーオーバーフローから始まります。これにより、サンプリングレートを微調整できます。
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を実行する必要があり、違いは明らかです。
コースは終わりに近づいていますが、まだ多くのアイデアがあります。
ご清聴ありがとうございました。