Daftar Isi:

1024 Sampel FFT Spectrum Analyzer Menggunakan Atmega1284: 9 Langkah
1024 Sampel FFT Spectrum Analyzer Menggunakan Atmega1284: 9 Langkah

Video: 1024 Sampel FFT Spectrum Analyzer Menggunakan Atmega1284: 9 Langkah

Video: 1024 Sampel FFT Spectrum Analyzer Menggunakan Atmega1284: 9 Langkah
Video: Arduino-Based Spectrum Analyzer 2024, November
Anonim
1024 Sampel FFT Spectrum Analyzer Menggunakan Atmega1284
1024 Sampel FFT Spectrum Analyzer Menggunakan Atmega1284
1024 Sampel FFT Spectrum Analyzer Menggunakan Atmega1284
1024 Sampel FFT Spectrum Analyzer Menggunakan Atmega1284

Tutorial yang relatif mudah ini (mengingat kerumitan materi pelajaran ini) akan menunjukkan kepada Anda bagaimana Anda dapat membuat penganalisis spektrum 1024 sampel yang sangat sederhana menggunakan papan tipe Arduino (1284 Narrow) dan plotter serial. Semua jenis papan Arduino yang kompatibel dapat digunakan, tetapi semakin banyak RAM yang dimilikinya, resolusi frekuensi terbaik yang akan Anda dapatkan. Ini akan membutuhkan lebih dari 8 KB RAM untuk menghitung FFT dengan 1024 sampel.

Analisis spektrum digunakan untuk menentukan komponen frekuensi utama dari suatu sinyal. Banyak suara (seperti yang dihasilkan oleh alat musik) terdiri dari frekuensi dasar dan beberapa harmonik yang memiliki frekuensi yang merupakan kelipatan bilangan bulat dari frekuensi dasar. Penganalisis spektrum akan menunjukkan kepada Anda semua komponen spektral ini.

Anda mungkin ingin menggunakan pengaturan ini sebagai penghitung frekuensi atau untuk memeriksa segala jenis sinyal yang Anda curigai membawa gangguan di sirkuit elektronik Anda.

Kami akan fokus di sini pada bagian perangkat lunak. Jika Anda ingin membuat sirkuit permanen untuk aplikasi tertentu, Anda perlu memperkuat dan menyaring sinyal. Pra-kondisi ini sepenuhnya tergantung pada sinyal yang ingin Anda pelajari, tergantung pada amplitudo, impedansi, frekuensi maksimum, dll. Anda dapat memeriksa

Langkah 1: Memasang Perpustakaan

Kami akan menggunakan perpustakaan ArduinoFFT yang ditulis oleh Enrique Condes. Karena kami ingin menghemat RAM sebanyak mungkin, kami akan menggunakan cabang pengembangan dari repositori ini yang memungkinkan untuk menggunakan tipe data float (bukan ganda) untuk menyimpan sampel dan data yang dihitung. Jadi kita harus menginstalnya secara manual. Jangan khawatir, cukup unduh arsip dan uncompress di folder library Arduino Anda (misalnya pada konfigurasi default Windows 10: C:\Users\_your_user_name_\Documents\Arduino\libraries)

Anda dapat memeriksa apakah perpustakaan telah diinstal dengan benar dengan mengkompilasi salah satu contoh yang disediakan, seperti "FFT_01.ino."

Langkah 2: Transformasi Fourier dan Konsep FFT

Peringatan: jika Anda tidak tahan melihat notasi matematika apa pun, Anda mungkin ingin melompat ke Langkah 3. Bagaimanapun, jika Anda tidak mendapatkan semuanya, pertimbangkan saja kesimpulan di akhir bagian ini.

Spektrum frekuensi diperoleh melalui algoritma Fast Fourier Transform. FFT adalah implementasi digital yang mendekati konsep matematika dari Transformasi Fourier. Di bawah konsep ini setelah Anda mendapatkan evolusi sinyal yang mengikuti sumbu waktu, Anda dapat mengetahui representasinya dalam domain frekuensi, yang terdiri dari nilai kompleks (nyata + imajiner). Konsepnya adalah timbal balik, jadi ketika Anda mengetahui representasi domain frekuensi, Anda dapat mengubahnya kembali ke domain waktu dan mendapatkan sinyal kembali persis seperti sebelum transformasi.

Tapi apa yang akan kita lakukan dengan kumpulan nilai kompleks yang dihitung ini dalam domain waktu? Nah, sebagian besar akan diserahkan kepada insinyur. Bagi kami, kami akan memanggil algoritma lain yang akan mengubah nilai kompleks ini menjadi data kerapatan spektral: yaitu nilai magnitudo (= intensitas) yang terkait dengan setiap pita frekuensi. Jumlah pita frekuensi akan sama dengan jumlah sampel.

Anda tentu mengenal konsep equalizer, seperti ini Kembali ke tahun 1980-an Dengan Graphic EQ. Yah, kita akan mendapatkan hasil yang sama tetapi dengan 1024 band bukannya 16 dan resolusi intensitas lebih banyak. Ketika equalizer memberikan pandangan global dari musik, analisis spektral yang halus memungkinkan untuk secara tepat menghitung intensitas dari masing-masing 1024 band.

Konsep yang sempurna, tetapi:

  1. Karena FFT adalah versi digital dari transformasi Fourier, FFT mendekati sinyal digital, dan kehilangan beberapa informasi. Jadi, secara tegas, hasil FFT jika ditransformasikan kembali dengan algoritma FFT terbalik tidak akan memberikan sinyal aslinya secara persis.
  2. Juga teori menganggap sinyal yang tidak terbatas, tapi itu adalah sinyal konstan yang abadi. Karena kami akan mendigitalkannya hanya untuk jangka waktu tertentu (yaitu sampel), beberapa kesalahan lagi akan terjadi.
  3. Akhirnya resolusi konversi analog ke digital akan berdampak pada kualitas nilai yang dihitung.

Dalam praktek

1) Frekuensi pengambilan sampel (dicatat fs)

Kami akan mengambil sampel sinyal, yaitu mengukur amplitudonya, setiap 1/fs detik. fs adalah frekuensi sampling. Misalnya jika kita mengambil sampel pada 8 KHz, ADC (analog to digital converter) yang ada di chip akan memberikan pengukuran setiap 1/8000 detik.

2) Jumlah sampel (dicatat N atau sampel dalam kode)

Karena kita perlu mendapatkan semua nilai sebelum menjalankan FFT, kita harus menyimpannya sehingga kita akan membatasi jumlah sampel. Algoritma FFT membutuhkan sejumlah sampel yang merupakan kekuatan 2. Semakin banyak sampel yang kita miliki semakin baik tetapi membutuhkan banyak memori, semakin banyak kita juga perlu menyimpan data yang diubah, yang merupakan nilai kompleks. Perpustakaan FFT Arduino menghemat ruang dengan menggunakan

  • Satu array bernama "vReal" untuk menyimpan data sampel dan kemudian bagian nyata dari data yang diubah
  • Satu array bernama "vImag" untuk menyimpan bagian imajiner dari data yang diubah

Jumlah RAM yang dibutuhkan sama dengan 2 (array) * 32 (bit) * N (sampel).

Jadi di Atmega1284 kami yang memiliki 16 KB RAM yang bagus, kami akan menyimpan nilai maksimum N = 16000*8 / 64 = 2000. Karena jumlah nilai harus pangkat 2, kami akan menyimpan maksimum 1024 nilai.

3) Resolusi frekuensi

FFT akan menghitung nilai untuk pita frekuensi sebanyak jumlah sampel. Pita-pita ini akan terbentang dari 0 HZ hingga frekuensi sampling (fs). Jadi, resolusi frekuensinya adalah:

Fresolusi = fs / N

Resolusi lebih baik ketika lebih rendah. Jadi untuk resolusi yang lebih baik (lebih rendah) kami ingin:

  • lebih banyak sampel, dan/atau
  • fs yang lebih rendah

Tetapi…

4) Minimal fs

Karena kami ingin melihat banyak frekuensi, beberapa di antaranya jauh lebih tinggi daripada "frekuensi dasar", kami tidak dapat mengatur fs terlalu rendah. Sebenarnya ada teorema pengambilan sampel Nyquist-Shannon yang memaksa kita untuk memiliki frekuensi pengambilan sampel jauh di atas dua kali frekuensi maksimum yang ingin kita uji.

Misalnya, jika kita ingin menganalisis semua spektrum dari 0 Hz hingga katakanlah 15 KHz, yang kira-kira merupakan frekuensi maksimum yang dapat didengar dengan jelas oleh kebanyakan manusia, kita harus menyetel frekuensi sampling pada 30 KHz. Bahkan elektronik sering mengaturnya pada 2,5 (atau bahkan 2,52) * frekuensi maksimum. Dalam contoh ini adalah 2,5 * 15 KHz = 37,5 KHz. Frekuensi pengambilan sampel biasa dalam audio profesional adalah 44,1 KHz (rekaman CD audio), 48 KHz, dan lainnya.

Kesimpulan:

Poin 1 hingga 4 mengarah ke: kami ingin menggunakan sampel sebanyak mungkin. Dalam kasus kami dengan perangkat RAM 16 KB, kami akan mempertimbangkan 1024 sampel. Kami ingin mengambil sampel pada frekuensi pengambilan sampel serendah mungkin, selama itu cukup tinggi untuk menganalisis frekuensi tertinggi yang kami harapkan dalam sinyal kami (setidaknya 2,5 * frekuensi ini).

Langkah 3: Mensimulasikan Sinyal

Mensimulasikan Sinyal
Mensimulasikan Sinyal

Untuk percobaan pertama kami, kami akan sedikit memodifikasi contoh TFT_01.ino yang diberikan di perpustakaan, untuk menganalisis sinyal yang terdiri dari

  • Frekuensi dasar, disetel ke 440 Hz (musik A)
  • Harmonik ke-3 dengan setengah kekuatan fundamental ("-3 dB")
  • Harmonik ke-5 pada 1/4 kekuatan fundamental ("-6 dB)

Anda dapat melihat pada gambar di atas sinyal yang dihasilkan. Memang terlihat sangat mirip dengan sinyal nyata yang kadang-kadang dapat dilihat pada osiloskop (saya akan menyebutnya "Batman") dalam situasi ketika ada kliping sinyal sinusoidal.

Langkah 4: Analisis Sinyal Simulasi - Coding

0) Sertakan perpustakaan

#sertakan "arduinoFFT.h"

1) Definisi

Di bagian deklarasi, kami memiliki

const byte adcPin = 0; // A0

const uint16_t sampel = 1024; // Nilai ini HARUS SELALU pangkat 2 const uint16_t samplingFrequency = 8000; // Akan mempengaruhi nilai maks timer di timer_setup() SYSCLOCK/8/samplingFrequency harus berupa bilangan bulat

Karena sinyal memiliki harmonik ke-5 (frekuensi harmonik ini = 5 * 440 = 2200 Hz), kita perlu mengatur frekuensi sampling di atas 2,5*2200 = 5500 Hz. Di sini saya memilih 8000 Hz.

Kami juga mendeklarasikan array tempat kami akan menyimpan data mentah dan yang dihitung

float vReal[sampel];

float vImag[sampel];

2) Instansiasi

Kami membuat objek ArduinoFFT. Versi dev ArduinoFFT menggunakan template sehingga kita dapat menggunakan tipe data float atau double. Float (32 bit) sudah cukup untuk presisi keseluruhan program kami.

ArduinoFFT FFT = ArduinoFFT(vReal, vImag, sampel, frekuensi sampling);

3) Mensimulasikan sinyal dengan mengisi array vReal, alih-alih mengisinya dengan nilai ADC.

Di awal Loop kami mengisi array vReal dengan:

siklus float = (((sampel) * signalFrequency) / samplingFrequency); //Jumlah siklus sinyal yang akan dibaca oleh sampling

for (uint16_t i = 0; i < sampel; i++) { vReal = float((amplitudo * (sin((i * (TWO_PI * cycles)) / sampel))));/* Membangun data dengan positif dan nilai negatif*/ vReal += float((amplitudo * (sin((3 * i * (TWO_PI * siklus)) / sampel))) / 2.0);/* Membangun data dengan nilai positif dan negatif*/ vReal += float((amplitudo * (sin((5 * i * (TWO_PI * cycles)) / sampel))) / 4.0);/* Membangun data dengan nilai positif dan negatif*/ vImag = 0.0; //Bagian imajiner harus di-nolkan jika terjadi perulangan untuk menghindari perhitungan yang salah dan luapan }

Kami menambahkan digitalisasi gelombang fundamental dan dua harmonik dengan amplitudo yang lebih kecil. Kemudian kita menginisialisasi array imajiner dengan nol. Karena array ini diisi oleh algoritma FFT, kita perlu menghapusnya lagi sebelum setiap perhitungan baru.

4) komputasi FFT

Kemudian kami menghitung FFT dan kerapatan spektral

FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward);

FFT.compute(FFTDirection::Forward); /* Hitung FFT */ FFT.complexToMagnitude(); /* Menghitung besaran */

Operasi FFT.windowing(…) memodifikasi data mentah karena kami menjalankan FFT pada sejumlah sampel terbatas. Sampel pertama dan terakhir menunjukkan diskontinuitas (tidak ada "tidak ada" di salah satu sisinya). Ini adalah sumber kesalahan. Operasi "windowing" cenderung mengurangi kesalahan ini.

FFT.compute(…) dengan arah "Maju" menghitung transformasi dari domain waktu ke domain frekuensi.

Kemudian kami menghitung nilai magnitudo (yaitu intensitas) untuk masing-masing pita frekuensi. Array vReal sekarang diisi dengan nilai magnitudo.

5) Gambar plotter serial

Mari cetak nilai pada plotter serial dengan memanggil fungsi printVector(…)

PrintVector(vReal, (contoh >> 1), SCL_FREQUENCY);

Ini adalah fungsi umum yang memungkinkan untuk mencetak data dengan sumbu waktu atau sumbu frekuensi.

Kami juga mencetak frekuensi pita yang memiliki nilai magnitudo tertinggi

float x = FFT.majorPeak();

Serial.print("f0="); Serial.print(x, 6); Serial.println("Hz");

Langkah 5: Analisis Sinyal Simulasi - Hasil

Analisis Sinyal Simulasi - Hasil
Analisis Sinyal Simulasi - Hasil

Kami melihat 3 paku sesuai dengan frekuensi dasar (f0), harmonik ke-3 dan ke-5, dengan setengah dan 1/4 dari besaran f0, seperti yang diharapkan. Kita dapat membaca di bagian atas jendela f0= 440.430114 Hz. Nilai ini tidak persis 440 Hz, karena semua alasan yang dijelaskan di atas, tetapi sangat dekat dengan nilai sebenarnya. Itu tidak benar-benar perlu untuk menunjukkan begitu banyak desimal tidak signifikan.

Langkah 6: Analisis Sinyal Nyata - Menghubungkan ADC

Analisis Sinyal Nyata - Menghubungkan ADC
Analisis Sinyal Nyata - Menghubungkan ADC

Karena kami tahu bagaimana melanjutkan secara teori, kami ingin menganalisis sinyal nyata.

Pengkabelannya sangat sederhana. Hubungkan ground bersama-sama dan jalur sinyal ke pin A0 papan Anda melalui resistor seri dengan nilai 1 KOhm hingga 10 KOhm.

Resistor seri ini akan melindungi input analog dan menghindari dering. Itu harus setinggi mungkin untuk menghindari dering, dan serendah mungkin untuk menyediakan arus yang cukup untuk mengisi ADC dengan cepat. Lihat lembar data MCU untuk mengetahui impedansi yang diharapkan dari sinyal yang terhubung pada input ADC.

Untuk demo ini saya menggunakan generator fungsi untuk memberi makan sinyal sinusoidal frekuensi 440 Hz dan amplitudo sekitar 5 volt (lebih baik jika amplitudo antara 3 dan 5 volt sehingga ADC digunakan mendekati skala penuh), melalui resistor 1,2 KOhm.

Langkah 7: Analisis Sinyal Nyata - Pengkodean

0) Sertakan perpustakaan

#sertakan "arduinoFFT.h"

1) Deklarasi dan instansiasi

Pada bagian deklarasi kita mendefinisikan input ADC (A0), jumlah sampel dan frekuensi sampling, seperti pada contoh sebelumnya.

const byte adcPin = 0; // A0

const uint16_t sampel = 1024; // Nilai ini HARUS SELALU pangkat 2 const uint16_t samplingFrequency = 8000; // Akan mempengaruhi nilai maks timer di timer_setup() SYSCLOCK/8/samplingFrequency harus berupa bilangan bulat

Kami membuat objek ArduinoFFT

ArduinoFFT FFT = ArduinoFFT(vReal, vImag, sampel, frekuensi sampling);

2) Pengaturan pengatur waktu dan ADC

Kami mengatur timer 1 sehingga siklus pada frekuensi sampling (8 KHz) dan menimbulkan interupsi pada perbandingan output.

batalkan timer_setup(){

// reset Timer 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | sedikit (WGM12); // CTC, prescaler dari 8 TIMSK1 = bit (OCIE1B); OCR1A = ((16000000 / 8) / frekuensi sampling) -1; }

Dan atur ADC jadi

  • Menggunakan A0 sebagai masukan
  • Dipicu secara otomatis pada setiap keluaran timer 1 bandingkan pertandingan B
  • Menghasilkan interupsi ketika konversi selesai

Jam ADC diatur pada 1 MHz, dengan menskalakan jam sistem (16 MHz) sebesar 16. Karena setiap konversi membutuhkan sekitar 13 jam pada skala penuh, konversi dapat dicapai pada frekuensi 1/13 = 0,076 MHz = 76 KHz. Frekuensi pengambilan sampel harus jauh lebih rendah dari 76 KHz agar ADC memiliki waktu untuk mengambil sampel data. (kami memilih fs = 8 KHz).

batal adc_setup() {

ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // aktifkan ADC, ingin interupsi saat selesai ADCSRA |= bit (ADPS2); // Prescaler dari 16 ADMUX = bit (REFS0) | (adcPin & 7); // mengatur input ADC ADCSRB = bit (ADTS0) | sedikit (ADTS2); // Timer/Counter1 Bandingkan sumber pemicu Match B ADCSRA |= bit (ADATE); // aktifkan pemicu otomatis }

Kami mendeklarasikan pengendali interupsi yang akan dipanggil setelah setiap konversi ADC untuk menyimpan data yang dikonversi dalam array vReal, dan menghapus interupsi

// ADC menyelesaikan ISR

ISR (ADC_vect) { vReal[hasilNumber++] = ADC; if(resultNumber == sampel) { ADCSRA = 0; // matikan ADC } } EMPTY_INTERRUPT (TIMER1_COMPB_vect);

Anda dapat memiliki penjelasan lengkap tentang konversi ADC di Arduino (analogRead).

3) Pengaturan

Dalam fungsi pengaturan, kami menghapus tabel data imajiner dan memanggil fungsi pengatur waktu dan pengaturan ADC

nolI(); // fungsi yang disetel ke 0 semua data imajiner - dijelaskan di bagian sebelumnya

pengatur waktu_setup(); adc_setup();

3) Putaran

Penghapusan FFT.dc(); // Hapus komponen DC dari sinyal ini karena ADC direferensikan ke ground

FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward); // Timbang data FFT.compute(FFTDirection::Forward); // Hitung FFT FFT.complexToMagnitude(); // Hitung besaran // mencetak spektrum dan frekuensi dasar f0 PrintVector(vReal, (sampel >> 1), SCL_FREQUENCY); float x = FFT.majorPeak(); Serial.print("f0="); Serial.print(x, 6); Serial.println("Hz");

Kami menghapus komponen DC karena ADC direferensikan ke ground dan sinyal dipusatkan sekitar 2,5 volt.

Kemudian kami menghitung data seperti yang dijelaskan pada contoh sebelumnya.

Langkah 8: Analisis Sinyal Nyata - Hasil

Analisis Sinyal Nyata - Hasil
Analisis Sinyal Nyata - Hasil

Memang kita hanya melihat satu frekuensi dalam sinyal sederhana ini. Frekuensi dasar yang dihitung adalah 440.18194 Hz. Di sini sekali lagi nilainya adalah perkiraan yang sangat dekat dari frekuensi sebenarnya.

Langkah 9: Bagaimana Dengan Sinyal Sinusoidal yang Terpotong?

Bagaimana Dengan Sinyal Sinusoidal yang Terpotong?
Bagaimana Dengan Sinyal Sinusoidal yang Terpotong?

Sekarang mari kita overdrive sedikit ADC dengan meningkatkan amplitudo sinyal di atas 5 volt, sehingga terpotong. Jangan terlalu ditekan agar tidak merusak input ADC!

Kita bisa melihat beberapa harmonik muncul. Memotong sinyal menciptakan komponen frekuensi tinggi.

Anda telah melihat dasar-dasar analisis FFT di papan Arduino. Sekarang Anda dapat mencoba mengubah frekuensi sampling, jumlah sampel dan parameter windowing. Pustaka juga menambahkan beberapa parameter untuk menghitung FFT lebih cepat dengan kurang presisi. Anda akan melihat bahwa jika Anda mengatur frekuensi sampling terlalu rendah, besaran yang dihitung akan tampak benar-benar salah karena pelipatan spektral.

Direkomendasikan: