Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Manufacturing Technology >> Proses manufaktur

EasyFFT – Library FFT Andalan untuk Proyek Arduino

Komponen dan Perlengkapan

Arduino Nano R3 – 1 unit

Aplikasi dan Layanan Online

Arduino IDE

Tentang Proyek Ini

Pengukuran frekuensi dari sinyal yang tertangkap dapat menjadi tugas yang sulit, terutama pada Arduino karena memiliki daya komputasi yang lebih rendah. Ada metode yang tersedia untuk menangkap titik potong nol di mana frekuensi ditangkap dengan memeriksa berapa kali sinyal melewati garis nol dalam waktu yang diberikan. Metode tersebut mungkin tidak berfungsi ketika sinyal adalah kombinasi dari berbagai frekuensi.

Ini agak sulit untuk dikodekan jika Anda tidak berasal dari latar belakang tersebut. Namun, sebagai seorang pemekat, kode ini mungkin sangat berguna untuk berbagai proyek yang terkait dengan musik, analisis sinyal. Tujuan dari proyek ini adalah untuk menyiapkan kode yang mudah diimplementasikan pada Arduino tanpa perlu memahami latar belakangnya.

Proyek ini tidak menjelaskan cara kerja FFT tetapi menjelaskan aplikasi fungsi FFT. Proses yang sama juga dijelaskan dalam video yang dilampirkan.

Jika Anda hanya tertarik pada aplikasi kode dan bukan pada penjelasannya. Anda dapat langsung melompat ke langkah nomor 3.

Jika Anda perlu melakukan FFT dengan kecepatan tinggi (3x) dengan pengorbanan akurasi yang kecil (sekitar 5%) lihat artikel saya lain tentang ApproxFFT.

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

Langkah 1: Transformasi Fourier Cepat

Untuk membuat komputasi DFT lebih cepat algoritma FFT dikembangkan oleh James Cooley dan John Tukey. Algoritma ini juga dianggap sebagai salah satu algoritma paling penting pada abad ke-20. Ini membagi sinyal menjadi bagian berurutan ganjil dan genap yang membuat jumlah perhitungan yang diperlukan lebih rendah. Dengan menggunakannya total perkalian kompleks yang diperlukan dapat dikurangi menjadi NlogN. yang merupakan perbaikan yang signifikan. DFT biasanya memerlukan N*N perkalian kompleks untuk hasil, sementara FFT hanya memerlukan N*logN. ini merupakan keuntungan yang signifikan ketika jumlah sampel tinggi.

Anda dapat merujuk ke referensi di bawah ini yang saya rujuk saat menulis kode untuk pemahaman yang lebih rinci tentang matematika di balik 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/8D0YvnW1@7.1:zmcmahhR@7/D...
  4. https://en.wikipedia.org/wiki/Fast_Fourier_transfo...

Langkah 2: Penjelasan Kode

1. Sinus dan Cosinus Cepat:

Perhitungan FFT mengambil nilai berbagai sinus dan kosinus berkali-kali. Fungsi bawaan Arduino tidak cukup cepat dan memerlukan waktu yang cukup untuk memberikan nilai yang diperlukan. Ini membuat kode jauh lebih lambat (menggandakan waktu untuk 64 sampel). Untuk mengatasi masalah ini nilai sinus untuk 0 hingga 90 derajat disimpan sebagai kelipatan 255. Melakukan ini akan menghilangkan kebutuhan untuk menyimpan angka sebagai float dan kita dapat menyimpannya sebagai byte yang mengambil 1/4 ruang pada Arduino. sine_data[] perlu ditempel di bagian atas kode untuk mendeklarasikannya sebagai variabel global.

Selain sine_data, sebuah array yang disebut f_peaks[] dideklarasikan sebagai variabel global. Setelah setiap pemrosesan fungsi FFT array ini diperbarui. Di mana f_peaks[0] adalah frekuensi paling dominan dan nilai-nilai lebih lanjut dalam urutan menurun.

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]; 

Karena kita telah menyimpan nilai sinus untuk 0 hingga 90 derajat, setiap nilai sinus atau kosinus dapat dihitung. Di bawah fungsi putaran pertama angka ke nol titik desimal dan mengembalikan nilai dari data yang disimpan. metode ini hanya membutuhkan satu pembagian floating. Ini dapat dikurangi lebih lanjut dengan langsung menyimpan nilai sinus (bukan kelipatan 255). tetapi itu menghabiskan memori tinggi pada Arduino.

Menggunakan prosedur di atas mengurangi akurasi tetapi meningkatkan kecepatan. Untuk 64 titik, ini memberikan keuntungan 8ms dan untuk 128 titik ini memberikan keuntungan 20ms.

Langkah 3: Penjelasan Kode: Fungsi FFT

FFT hanya dapat dilakukan untuk ukuran sampel 2, 4, 8, 16, 32, 64 dan seterusnya. jika nilai bukan 2^n, maka itu akan mengambil sisi lebih rendah dari nilai. Misalnya, jika kita memilih ukuran sampel 70 maka itu hanya akan mempertimbangkan 64 sampel pertama dan mengabaikan sisanya.

Selalu disarankan untuk memiliki ukuran sampel 2^n. yang dapat berupa:

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

Dua float out_r dan out_im akan mengambil sejumlah besar memori. untuk Arduino nano tidak akan berfungsi untuk sampel lebih dari 128 (dan dalam beberapa kasus 128) karena kurangnya memori yang tersedia.

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++) //menghitung tingkat { if(data[i]<=a){o=i;} } int in_ps[data[o]]={}; //masukan untuk sequensi float out_r[data[o]]={}; //bagian riil dari transformasi float out_im[data[o]]={}; //bagian imajiner dari transformasi 

Alur selanjutnya adalah sebagai berikut:

  1. Kode menghasilkan urutan bit terbalik untuk ukuran sampel yang diberikan (detail tentang pembalikan bit pada referensi: langkah 2)
  2. Data masukan diurutkan sesuai dengan urutan yang dihasilkan,
  3. FFT dilakukan
  4. Amplitudo bilangan kompleks dihitung,
  5. Puncak terdeteksi dan diurutkan dalam urutan menurun
  6. Hasil dapat diakses dari f_peaks[].

[untuk mengakses data lain (selain frekuensi puncak) kode harus dimodifikasi, sehingga variabel lokal dapat disalin ke beberapa variabel global yang telah ditentukan]

Langkah 4: Pengujian Kode

Sinyal segitiga contoh diberikan sebagai masukan. untuk gelombang ini frekuensi pemrosesan adalah 10 Hz dan frekuensi gelombang itu sendiri adalah 1,25 Hz.

Seperti yang dapat ditunjukkan dari keluaran mentah, nilai cocok dengan FFT yang dihitung oleh Scilab. namun, nilai-nilai ini tidak sama persis karena kita menggunakan sinus dengan akurasi rendah tetapi lebih cepat.

Dalam array frekuensi keluaran frekuensi adalah 1,25 dan 3,75. tidak perlu untuk mendapatkan nilai yang sama setiap kali. biasanya angka-angka ini disebut bingkai frekuensi. jadi nilai keluaran mungkin berada di mana saja dalam bingkai yang ditentukan.

Kecepatan:

untuk Arduino nano memakan waktu:

Langkah 5: Kesimpulan

Kode FFT ini dapat digunakan dalam aplikasi real-time. Karena memakan waktu sekitar 30 ms untuk menyelesaikan perhitungan. Namun, resolusinya terbatas oleh jumlah sampel. Jumlah sampel terbatas oleh memori Arduino. Dengan menggunakan Arduino Mega atau papan berkinerja lebih tinggi akurasi dapat ditingkatkan.

Jika Anda memiliki pertanyaan, saran, atau koreksi silakan berikan komentar.

Kode

EasyFFTArduino

Kode ini melakukan FFT dan memperbarui array F_peaks dengan 5 frekuensi dominan teratas.

/* //Contoh data: int data[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, //Tempelkan ini di bagian atas program 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]; // 5 puncak frekuensi teratas dalam urutan menurun //---------------------------------------------------------------------------// void setup() { Serial.begin(250000); } void loop() { /* //contoh FFT(data,64,100); //untuk mendapatkan lima nilai teratas dari frekuensi X yang memiliki 64 sampel pada frekuensi pemrosesan 100Hz Serial.println(f_peaks[0]); Serial.println(f_peaks[1]); delay(99999); */ /* setelah menjalankan FFT(), frekuensi tersedia di f_peaks[0],f_peaks[1],f_peaks[2],f_peaks[3],f_peaks[4], */ } //-----------------------------Fungsi FFT----------------------------------------------// float FFT(int in[],int N,float Frequency) { /* Kode untuk melakukan FFT pada arduino, pengaturan: tempelkan sine_data [91] di bagian atas program [variabel global], tempelkan fungsi FFT di bagian akhir program Istilah: 1. in[] : Array data, 2. N : Jumlah sampel (ukuran sampel yang direkomendasikan 2,4,8,16,32,64,128...) 3. Frequency: frekuensi pemrosesan yang diperlukan sebagai masukan (Hz) Jika ukuran sampel bukan dalam pangkat 2, maka akan dipotong ke sisi lebih rendah dari angka. misalnya, untuk 150 jumlah sampel, kode akan mempertimbangkan 128 sampel pertama, sampel sisa akan dihilangkan. Untuk Arduino nano, FFT lebih dari 128 sampel tidak mungkin karena keterbatasan memori (64 direkomendasikan) Untuk jumlah sampel yang lebih tinggi mungkin timbul masalah terkait memori, Kode oleh ABHILASH Kontak: abhilashpatel121@gmail.com Dokumentasi:https://www.instructables.com/member/abhilash_patel/instructables/ 2/3/2021: ubah tipe data N dari float ke int untuk >=256 sampel */ 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++) //menghitung tingkat { if(data[i]<=a){o=i;} } int in_ps[data[o]]={}; //masukan untuk sequensi float out_r[data[o]]={}; //bagian riil dari transformasi float out_im[data[o]]={}; //bagian imajiner dari transformasi x=0; for(int b=0;b<o;b++) // pembalikan bit { c1=data[b]; f=data[o]/(c1+c1); for(int j=0;j<c1;j++) { x=x+1; in_ps[x]=in_ps[j]+f; } } for(int i=0;i<data[o];i++) // perbarui array masukan sesuai urutan bit terbalik { if(in_ps[i]<a) {out_r[i]=in[in_ps[i]];} if(in_ps[i]>a) {out_r[i]=in[in_ps[i]-a];} } int i10,i11,n1; float e,c,s,tr,ti; for(int i=0;i<o;i++) //fft { i10=data[i]; // nilai keseluruhan sinus/kosinus : i11=data[o]/data[i+1]; // loop dengan sinus kosinus yang sama: e=360/data[i+1]; e=0-e; n1=0; for(int j=0;j<i10;j++) { c=cosine(e*j); s=sine(e*j); n1=j; for(int k=0;k<i11;k++) { tr=c*out_r[i10+n1]-s*out_im[i10+n1]; ti=s*out_r[i10+n1]+c*out_im[i10+n1]; out_r[n1+i10]=out_r[n1]-tr; out_r[n1]=out_r[n1]+tr; out_im[n1+i10]=out_im[n1]-ti; out_im[n1]=out_im[n1]+ti; n1=n1+i10+i10; } } } /* for(int i=0;i<data[o];i++) { Serial.print(out_r[i]); Serial.print("\t"); // un comment to print RAW o/p Serial.print(out_im[i]); Serial.println("i"); } */ //--> di sini ke depan out_r berisi amplitudo dan out_im berisi frekuensi (Hz) for(int i=0;i<data[o-1];i++) // mendapatkan amplitudo dari bilangan kompleks { out_r[i]=sqrt(out_r[i]*out_r[i]+out_im[i]*out_im[i]); // untuk meningkatkan kecepatan hapus sqrt out_im[i]=i*Frequency/N; /* Serial.print(out_im[i]); Serial.print("Hz"); Serial.print("\t"); // un comment to print freuency bin Serial.println(out_r[i]); */ } x=0; // deteksi puncak for(int i=1;i<data[o-1]-1;i++) { if(out_r[i]>out_r[i-1] && out_r[i]>out_r[i+1]) {in_ps[x]=i; //in_ps array digunakan untuk penyimpanan nomor puncak x=x+1;} } s=0; c=0; for(int i=0;i<x;i++) // susun ulang menurut magnitudo { for(int j=c;j<x;j++) { if(out_r[in_ps[i]]<out_r[in_ps[j]]) {s=in_ps[i]; in_ps[i]=in_ps[j]; in_ps[j]=s;} } c=c+1; } for(int i=0;i<5;i++) // memperbarui array f_peak (variabel global)dengan urutan menurun { f_peaks[i]=out_im[in_ps[i]]; } } float sine(int i) { int j=i; float out; while(j<0){j=j+360;} while(j>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; float out; 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); } //------------------------------------------------------------------------------------// 

Proses manufaktur

  1. Memahami Transformasi Fourier: Dasar, Aplikasi, dan Dekomposisi Sinyal
  2. Membangun DTMF Decoder Hanya Menggunakan Arduino – Tidak Perlu IC Tambahan
  3. SERENA: Sistem Alarm Kustom Arduino Mega 2560 dengan Layar Sentuh TFT LCD
  4. Python 3 ke Arduino UNO: Kontrol Perintah Mudah dan Demo LED
  5. Sistem Pemantauan Suhu Cerdas untuk Sekolah: Akurat, Real-Time, dan Aman
  6. Pustaka Port IO 8-bit Efisien untuk Arduino – Perluas Kontrol Digital
  7. Matriks Keyboard Prototyp 64-Tombol Arduino – Buat Keyboard Custom dengan Shift Register
  8. Bangun Rangkaian Input Analog Terisolasi untuk Arduino
  9. Kit Robot Navigasi Indoor Cerdas untuk Proyek Arduino
  10. Kode HS untuk Pompa Hidrolik – Klasifikasi & Penggunaan