工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

EasyFFT:Arduino用の高速フーリエ変換(FFT)

コンポーネントと消耗品

>
Arduino Nano R3
× 1

アプリとオンラインサービス

>
Arduino IDE

このプロジェクトについて

キャプチャされた信号からの周波数の測定は、特にArduinoの計算能力が低いため、困難な作業になる可能性があります。ゼロ交差をキャプチャするために利用できる方法があります。ここでは、指定された時間内に信号がゼロラインを通過する回数をチェックすることによって周波数がキャプチャされます。このような方法は、信号がさまざまな周波数の組み合わせである場合は機能しない可能性があります。

あなたがそのようなバックグラウンドを持っていないのなら、これはどういうわけかコーディングするのが難しいです。しかし、いじくり回しているこのコードは、音楽、信号分析に関連するさまざまなプロジェクトに非常に役立つ可能性があります。このプロジェクトの動機は、Arduinoにバックグラウンドに入ることなく簡単に実装できるコードを準備することでした。

このプロジェクトでは、FFTの動作については説明していませんが、FFT機能の適用について説明しています。同じプロセスは、添付のビデオでも説明されています。

コードの適用のみに関心があり、コードの説明には関心がない場合。ステップ3に直接スキップできます。

精度を少し妥協して(約5%)高速(3x)でFFTを実行する必要がある場合は、約FFTに関する別の記事を参照してください。

https://create.arduino.cc/projecthub/abhilashpatel121/approxfft-fastest-fft-function-for-arduino-fd4917?ref=user&ref_id=1593632&offset=0

ステップ1:高速フーリエ変換

DFTの計算を高速化するために、FFTアルゴリズムはJamesCooleyとJohnTukeyによって開発されました。このアルゴリズムは、20世紀の最も重要なアルゴリズムの1つと見なされています。信号を奇数と偶数のシーケンス部分に分割するため、必要な計算の数が少なくなります。これを使用することにより、必要な複素数乗算の合計をNlogNに減らすことができます。これは大幅な改善です。通常のDFTは結果に対してN * Nの複素数乗算を取りますが、FFTはN * logNのみを取ります。これは、サンプル数が多い場合に大きな利点です。

FFTの背後にある数学の詳細を理解するために、コードを記述しているときに参照した以下の参照を参照してください。

1. https://flylib.com/books/en/2.729.1/derivation_of _...

2. https://jakevdp.github.io/blog/2013/08/28/understa ...

3. https://cnx.org/contents/[email protected]:zmcmahhR @ 7 / D ...

4. https://en.wikipedia.org/wiki/Fast_Fourier_transfo ...

ステップ2:コードの説明

1.高速サインとコサイン:

計算FFTは、さまざまな正弦および余弦の値を複数回取得します。 Arduinoの組み込み関数は十分に高速ではなく、必要な値を提供するのにかなりの時間がかかります。これにより、コードが大幅に遅くなります(64サンプルの場合は時間が2倍になります)。この問題に対処するために、0〜90度の正弦の値は255の倍数として格納されます。そうすることで、数値を浮動小数点数として格納する必要がなくなり、Arduinoで1/4のスペースを占めるバイトとして格納できます。 sine_data []は、コードをグローバル変数として宣言するために、コードの先頭に貼り付ける必要があります。

sine_dataとは別に、グローバル変数として宣言された f_peaks []という配列 。 FFT関数を実行するたびに、この配列が更新されます。ここで、f_peaks [0]は最も支配的な頻度であり、降順でさらに値が続きます。

  byte sine_data [91] ={0、4、9、13、18、22、27、31、35、40、44、49、53、57、62、66、70、75、79 、83、87、91、96、100、104、108、112、116、120、124、127、131、135、139、143、146、150、153、157、160、164、167、171、174 、177、180、183、186、189、192、195、198、201、204、206、209、211、214、216、219、221、223、225、227、229、231、233、235、236 、238、240、241、243、244、245、246、247、248、249、250、251、252、253、253、254、254、254、255、255、255、255}; float f_peaks [5 ];  

サインの値を0〜90度で保存しているので、サインまたはコサインの任意の値を計算できます。以下の関数は、小数点以下ゼロまでの数値の最初のラウンドと、保存されたデータからの戻り値です。この方法では、浮動除算が1つだけ必要です。これは、正弦値を直接保存することでさらに減らすことができます(255倍ではありません)。しかし、それはArduinoの高いメモリを消費します。

上記の手順を使用すると、精度は低下しますが、速度は向上します。 64ポイントの場合、8ミリ秒の利点があり、128ポイントの場合、20ミリ秒の利点があります。

ステップ3:コードの説明:FFT関数

FFTは、2、4、8、16、32、64などのサンプルサイズに対してのみ実行できます。値が2 ^ nでない場合は、値の下側になります。たとえば、サンプルサイズを70にすると、最初の64サンプルのみが考慮され、残りは省略されます。

サンプルサイズは常に2 ^ nにすることをお勧めします。次のようになります:

2、4、8、16、32、64、128、256、512、1024、2048、...

2つのfloatout_rとout_imは、大量のメモリを消費します。 Arduino nanoは、使用可能なメモリが不足しているため、128(場合によっては128)を超えるサンプルでは機能しません。

  unsigned int data [13] ={1,2,4,8,16,32,64,128,256,512,1024,2048}; int a、c1、f、o、x; a =N; for(int i =0; i <12; i ++)//レベルの計算{if(data [i] <=a){o =i;}} int in_ps [data [o]] ={}; //シーケンスの入力floatout_r [data [o]] ={}; // transformfloatの実数out_im [data [o]] ={}; //変換の架空の部分 

さらなるフローは次のとおりです:

1.コードは、指定されたサンプルサイズの順序を逆にしたビットを生成します(参照のビット逆の詳細:ステップ2)

2.生成された順序に従って順序付けられたデータを入力します

3.実行されたFFT

4.計算された複素数の振幅

5.ピークが検出され、降順で並べ替えられます

6.結果にはf_peaks []からアクセスできます。

[他のデータ(ピーク頻度を除く)にアクセスするには、ローカル変数を事前定義されたグローバル変数にコピーできるように、コードを変更する必要があります]

ステップ4:コードをテストする

サンプルの三角波が入力として与えられます。この波のサンプリング周波数は10Hzで、波自体の周波数は1.25Hzです。

生の出力からわかるように、値はScilabによって計算されたFFTと一致しています。ただし、これらの値は、精度が低く、正弦波が速いのとまったく同じではありません。

出力周波数では、アレイの周波数は1.25と3.75です。毎回正確な値を取得する必要はありません。通常、これらの数値は周波数ビンと呼ばれます。したがって、出力値は指定されたビン内のどこかにある可能性があります。

速度:

Arduino nanoの場合:

  • 16ポイント:4ミリ秒
  • 32ポイント:10ミリ秒
  • 64ポイント:26ミリ秒
  • 128ポイント:53ミリ秒

ステップ5:結論

このFFTコードは、リアルタイムアプリケーションで使用できます。計算が完了するまでに約30ミリ秒かかります。ただし、その解像度はサンプル数によって制限されます。サンプルの数はArduinoメモリによって制限されています。 Arduino Megaまたは他のより高性能なボードを使用することで、ボードの精度を向上させることができます。

質問、提案、修正があれば、遠慮なくコメントしてください。

コード

  • EasyFFT
EasyFFT Arduino
このコードはFFTを実行し、F_peasks配列を上位5つの最も支配的な周波数で更新します。
 / * //サンプルデータ:intdata [64] ={14、30、35、34、34、40、46、45、30 、4、-26、-48、-55、-49、-37、-28、-24、-22、-13、6、32、55、65、57、38、17、1、-6、- 11、-19、-34、-51、-61、-56、-35、-7、18、32、35、34、35、41、46、43、26、-2、-31、-50、 -55、-47、-35、-27、-24、-21、-10、11、37、58、64、55、34、13、-1、-7}; * /// ---- -------------------------------------------------- --------------------- // byte sine_data [91] ={0、4、9、13、18、22、27、31、35、40、 44、49、53、57、62、66、70、75、79、83、87、91、96、100、104、108、112、116、120、124、127、131、135、139、143、 146、150、153、157、160、164、167、171、174、177、180、183、186、189、192、195、//これをプログラムの先頭に貼り付ける198、201、204、206、209、211 、214、216、219、221、223、225、227、229、231、233、235、236、238、240、241、243、24 4、245、246、247、248、249、250、251、252、253、253、254、254、254、255、255、255、255}; float f_peaks [5]; //上位5つの周波数は降順でピークになります// ------------------------------------------------------- ------------------------------------ // void setup(){Serial.begin(250000); } void loop(){/ * // exampleFFT(data、64,100); // 100Hzで64サンプルのXの周波数の上位5つの値を取得するsamplingSerial.println(f_peaks [0]); Serial.println(f_peaks [1]); delay(99999); * // * FFT( )、f_peaks [0]、f_peaks [1]、f_peaks [2]、f_peaks [3]、f_peaks [4]、* /} // ---------------で利用可能な周波数-------------- FFT関数---------------------------------- ------------ // float FFT(int in []、int N、float Frequency){/ *プログラムの先頭にあるarduino、setup:paste sine_data [91]でFFTを実行するコード[グローバル変数]、programTerm:1の最後にFFT関数を貼り付けます。 in []:データ配列、2。N:サンプル数(推奨サンプルサイズ2、4、8、16、32、64、128 ...)3。周波数:入力として必要なサンプリング周波数(Hz)サンプルサイズが2の累乗でない場合、数値の下側にクリップされます。つまり、サンプル数が150の場合、コードは最初の128サンプルを考慮し、残りのサンプルは省略されます。Arduinonanoの場合、マモリーの制限により128サンプルを超えるFFTは不可能です(64を推奨)。サンプル数が多い場合は、マモリー関連が発生する可能性があります。発行、ABHILASHによるコード連絡先:[email protected]ドキュメント:https://www.instructables.com/member/abhilash_patel/instructables/2/3/2021:> =256サンプルのNのデータ型をfloatからintに変更* / unsigned int data [13] ={1,2,4,8,16,32,64,128,256,512,1024,2048}; int a、c1、f、o、x; a =N; for(int i =0; i <12; i ++)//レベルの計算{if(data [i] <=a){o =i;}} int in_ps [data [o]] ={}; //シーケンスの入力floatout_r [data [o]] ={}; // transformfloatの実数out_im [data [o]] ={}; //変換の架空の部分x =0; for(int b =0; b  a){out_r [i] =in [in_ps [i] -a];}} int i10、i11、n1; float e、c、s、tr、ti; for(int i =0; i ここ以降out_rには振幅が含まれ、our_inには周波数(Hz)が含まれますfor(int i =0; i  out_r [i-1] &&out_r [i]> out_r [i + 1] ){in_ps [x] =i; //ピーク数の保存に使用されるin_ps配列x =x + 1;}} s =0; c =0; for(int i =0; i  360){j =j-360;} if(j> -1 &&j <91){out =sine_data [j];} else if (j> 90 &&j <181){out =sine_data [180-j];} else if(j> 180 &&j <271){out =-sine_data [j-180];} else if(j> 270 &&j <361){out =-sine_data [360-j];} return(out / 255);} float cosine(int i){int j =i;浮き上がる; while(j <0){j =j + 360;} while(j> 360){j =j-360;} if(j> -1 &&j <91){out =sine_data [90-j];} else if(j> 90 &&j <181){out =-sine_data [j-90];} else if(j> 180 &&j <271){out =-sine_data [270-j];} else if(j> 270 &&j <361){out =sine_data [j-270];} return(out / 255);} // ---------------------- -------------------------------------------------- ------------ // 

回路図


製造プロセス

  1. フーリエ変換とは何ですか?
  2. Arduinoのみを使用するDTMFデコーダー
  3. Arduino警報システム:SERENA
  4. Python3とArduinoコミュニケーション
  5. 学校向けのSMART温度監視
  6. Arduino用の8ビットIOポートライブラリ
  7. Arduino用の64キープロトタイピングキーボードマトリックス
  8. ArduinoNano用TFTシールド-開始
  9. Arduino用の絶縁アナログ入力
  10. 超クールな屋内ナビゲーション用ロボット
  11. 油圧ポンプの HS コードとは?