Mündəricat:

Atmega1284: 9 Addımlarından istifadə edərək 1024 Nümunə FFT Spektr Analizatoru
Atmega1284: 9 Addımlarından istifadə edərək 1024 Nümunə FFT Spektr Analizatoru

Video: Atmega1284: 9 Addımlarından istifadə edərək 1024 Nümunə FFT Spektr Analizatoru

Video: Atmega1284: 9 Addımlarından istifadə edərək 1024 Nümunə FFT Spektr Analizatoru
Video: Aşk Yolunun Tehlikeleri - Acz Fakr Şefkat Tefekkür - [26.Söz Zeyl KADER 9] @Mehmedyildiz 2024, Iyul
Anonim
Atmega1284 istifadə edərək 1024 Nümunə FFT Spektr Analizatoru
Atmega1284 istifadə edərək 1024 Nümunə FFT Spektr Analizatoru
Atmega1284 istifadə edərək 1024 Nümunə FFT Spektr Analizatoru
Atmega1284 istifadə edərək 1024 Nümunə FFT Spektr Analizatoru

Bu nisbətən asan dərslik (bu mövzunun mürəkkəbliyi nəzərə alınmaqla), Arduino tipli bir lövhədən (1284 Dar) və serial qurucusundan istifadə edərək çox sadə 1024 nümunə spektr analizatoru necə edə biləcəyinizi göstərəcəkdir. Hər hansı bir Arduino uyğun lövhə edəcək, ancaq RAM nə qədər çox olsa, ən yaxşı tezlik qətnaməsini alacaqsınız. FFT -ni 1024 nümunə ilə hesablamaq üçün 8 KB -dən çox RAM lazım olacaq.

Bir siqnalın əsas tezlik komponentlərini təyin etmək üçün spektr analizi istifadə olunur. Bir çox səslər (musiqi aləti tərəfindən istehsal edilənlər kimi) əsas tezlikdən və əsas tezliyin tam ədədinə bərabər olan bir tezliyə malik olan bəzi harmoniklərdən ibarətdir. Spektr analizatoru sizə bütün bu spektral komponentləri göstərəcək.

Bu qurğudan tezlik sayğacı kimi istifadə etmək və ya elektron dövrənizə səs -küy gətirdiyindən şübhələndiyiniz hər hansı bir siqnal yoxlamaq istəyə bilərsiniz.

Burada proqram hissəsinə diqqət yetirəcəyik. Xüsusi bir tətbiq üçün daimi bir dövrə etmək istəyirsinizsə, siqnalı gücləndirməli və süzgəcdən keçirməlisiniz. Bu ön kondisioner, amplitüdündən, empedansından, maksimum tezliyindən və s. Asılı olaraq öyrənmək istədiyiniz siqnaldan tamamilə asılıdır.

Addım 1: Kitabxananın quraşdırılması

Enrique Condes tərəfindən yazılan ArduinoFFT kitabxanasından istifadə edəcəyik. RAM -ı mümkün qədər qorumaq istədiyimiz üçün, seçilmiş və hesablanmış məlumatları saxlamaq üçün float məlumat növündən (ikiqat əvəzinə) istifadə etməyə imkan verən bu anbarın inkişaf etdirmə şöbəsindən istifadə edəcəyik. Buna görə əl ilə quraşdırmalıyıq. Narahat olmayın, yalnız arxivi yükləyin və Arduino kitabxana qovluğunda açın (məsələn, Windows 10 standart konfiqurasiyasında: C: / İstifadəçiləriniz_ istifadəçinizin_adı_ / Sənədlər / Arduino / kitabxanaları)

"FFT_01.ino" kimi verilən nümunələrdən birini tərtib edərək kitabxananın düzgün qurulduğunu yoxlaya bilərsiniz.

Addım 2: Fourier Transform və FFT Konseptləri

Xəbərdarlıq: hər hansı bir riyazi işarəni görməyə dözə bilmirsinizsə, 3 -cü addıma keçmək istəyə bilərsiniz. Hər halda, hamısını əldə etməsəniz, bölmənin sonundakı nəticəni düşünün.

Tezlik spektri Fast Fourier Transform alqoritmi ilə əldə edilir. FFT, Fourier Dönüşümünün riyazi konsepsiyasına yaxınlaşan rəqəmsal bir tətbiqdir. Bu anlayışa əsasən, zaman oxundan sonra bir siqnalın təkamülünü əldə etdikdə, onun mürəkkəb (real + xəyali) dəyərlərdən ibarət olan bir tezlik sahəsindəki təmsilçiliyini bilə bilərsiniz. Konsepsiya qarşılıqlıdır, buna görə də tezlik domeninin təmsilçiliyini bildiyiniz zaman onu yenidən zaman sahəsinə çevirə və çevrilmədən əvvəlki kimi siqnalı geri ala bilərsiniz.

Bəs zaman sahəsindəki bu hesablanmış kompleks dəyərlər dəsti ilə nə edəcəyik? Yaxşı, çoxu mühəndislərə qalacaq. Bizim üçün bu kompleks dəyərləri spektral sıxlıq məlumatlarına çevirəcək başqa bir alqoritmi çağıracağıq: bu, hər bir tezlik diapazonu ilə əlaqəli böyüklük (= intensivlik) dəyəridir. Tezlik diapazonunun sayı nümunələrin sayı ilə eyni olacaq.

Əlbəttə ki, 1980 -ci illərə qədər Graphic EQ ilə bərabər ekvalayzer anlayışı ilə tanışsınız. Yaxşı, eyni nəticələr əldə edəcəyik, ancaq 16 yerinə 1024 bant və daha çox intensivlik qətnaməsi ilə. Ekvalayzer musiqiyə qlobal bir fikir verdikdə, incə spektral analiz 1024 bantın hər birinin intensivliyini dəqiq hesablamağa imkan verir.

Mükəmməl bir konsepsiya, amma:

  1. FFT, Fourier çevrilməsinin rəqəmsal bir versiyası olduğu üçün rəqəmsal siqnala yaxınlaşır və bəzi məlumatları itirir. Beləliklə, ciddi şəkildə desək, FFT -in nəticəsi ters FFT alqoritmi ilə geri çevrilərsə, orijinal siqnal vermir.
  2. Həm də nəzəriyyə sonlu olmayan bir siqnal hesab edir, lakin bu daimi bir sabit siqnaldır. Yalnız müəyyən bir müddət üçün rəqəmsal hala gətirəcəyimiz üçün (məsələn, nümunələr), daha bir neçə səhv təqdim ediləcək.
  3. Nəhayət, analoqun rəqəmsal formata çevrilməsi, hesablanan dəyərlərin keyfiyyətinə təsir edəcək.

Praktikada

1) Nümunə götürmə tezliyi (qeyd olunan fs)

Bir siqnaldan nümunə götürəcəyik, yəni amplitüdünü hər 1/saniyədə bir ölçəcəyik. fs nümunə götürmə tezliyidir. Məsələn, 8 KHz -də nümunə götürsək, çipdə olan ADC (analogdan rəqəmsal çeviriciyə) hər 1/8000 saniyədə bir ölçü təmin edəcək.

2) Nümunələrin sayı (kodda qeyd olunan N və ya nümunələr)

FFT -ni işə salmadan əvvəl bütün dəyərləri almalı olduğumuz üçün onları saxlamalı olacağıq və buna görə nümunələrin sayını məhdudlaşdıracağıq. FFT alqoritmi 2 gücə malik bir sıra nümunələrə ehtiyac duyur. Nə qədər çox nümunə götürsək, bir o qədər yaxşı olar, amma yaddaş çox olarsa, daha da mürəkkəb dəyərlər olan çevrilmiş məlumatları saxlamalı olacağıq. Arduino FFT kitabxanası istifadə edərək bir az yer saxlayır

  • Nümunə verilənləri və sonra çevrilən məlumatların əsl hissəsini saxlamaq üçün "vReal" adlı bir sıra
  • Çevrilmiş məlumatların xəyali hissəsini saxlamaq üçün "vImag" adlı bir sıra

Lazım olan RAM miqdarı 2 (dizi) * 32 (bit) * N (nümunə) bərabərdir.

16 KB RAM -a sahib olan Atmega1284 -də maksimum N = 16000*8/64 = 2000 dəyər saxlayacağıq. Dəyərlərin sayı 2 -dən çox olmalı olduğundan, maksimum 1024 dəyər saxlayacağıq.

3) Tezlik həlli

FFT, nümunə sayı qədər tezlik diapazonu üçün dəyərləri hesablayacaq. Bu bantlar 0 HZ -dən nümunə götürmə tezliyinə (fs) qədər uzanacaq. Beləliklə, tezliyin həlli belədir:

Fresolution = fs / N

Çözünürlük aşağı olduqda daha yaxşıdır. Daha yaxşı həll üçün (aşağı) istəyirik:

  • daha çox nümunə və/və ya
  • daha aşağı fs

Amma…

4) Minimum fs

Çox tezlik görmək istədiyimiz üçün, bəziləri "fundamental tezlikdən" çox yüksəkdir, fs -ni çox aşağı qoya bilmərik. Əslində sınamaq istədiyimiz maksimum tezlikdən iki dəfə çox nümunə götürmə tezliyinə sahib olmağa məcbur edən Nyquist -Shannon seçmə teoremi var.

Məsələn, 0 Hz -dən başlayaraq 15 KHz -ə qədər olan bütün spektri təhlil etmək istəyirik ki, bu da təxminən insanların əksəriyyətinin fərqli şəkildə eşitdiyi maksimum tezlikdir, nümunə götürmə tezliyini 30 KHz -ə təyin etməliyik. Əslində elektroniklər tez -tez onu 2.5 (və ya hətta 2.52) * maksimum tezliyə təyin edirlər. Bu nümunədə 2,5 * 15 KHz = 37,5 KHz olardı. Professional səslərdə adi nümunə götürmə tezlikləri 44.1 KHz (audio CD qeyd), 48 KHz və daha çoxdur.

Nəticə:

1 -dən 4 -ə qədər nöqtələr gətirib çıxarır: mümkün qədər çox nümunə istifadə etmək istəyirik. Bizim vəziyyətimizdə 16 KB RAM cihazı ilə 1024 nümunəni nəzərdən keçirəcəyik. Siqnalımızda gözlədiyimiz ən yüksək tezliyi təhlil etmək üçün kifayət qədər yüksək olduğu müddətcə mümkün olan ən aşağı seçmə tezliyində nümunə götürmək istəyirik (ən azı 2,5 * bu tezlik).

Addım 3: Siqnalın simulyasiyası

Siqnalın simulyasiyası
Siqnalın simulyasiyası

İlk sınağımız üçün, kitabxanada verilən TFT_01.ino nümunəsini bir az dəyişdirərək, bir siqnalı təhlil edəcəyik.

  • Əsas tezlik, 440 Hz -ə (musiqi A)
  • Üçüncü harmonik, fundamental gücün yarısında ("-3 dB")
  • Fundamental gücün 1/4 hissəsində 5-ci harmonik ("-6 dB)

Yaranan siqnalı yuxarıdakı şəkildə görə bilərsiniz. Sinusoidal bir siqnal kəsildikdə bəzən bir osiloskopda (buna "Batman" deyərdim) görə biləcəyiniz əsl bir siqnala çox bənzəyir.

Addım 4: Süni Siqnalın Təhlili - Kodlaşdırma

0) Kitabxanaya daxil olun

#"arduinoFFT.h" daxil edin

1) Təriflər

Bəyannamələr bölmələrində var

const bayt adcPin = 0; // A0

const uint16_t nümunələri = 1024; // Bu dəyər hər zaman 2 const uint16_t samplingFrequency = 8000 güc olmalıdır. // timer_setup () SYSCLOCK/8/sampling -də timer max dəyərinə təsir edəcək Tezlik tam ədəd olmalıdır

Siqnal 5 -ci harmonikə malik olduğundan (bu harmonikin tezliyi = 5 * 440 = 2200 Hz) nümunə götürmə tezliyini 2,5 * 2200 = 5500 Hz -dən yuxarı qoymalıyıq. Burada 8000 Hz seçdim.

Xam və hesablanmış məlumatları saxlayacağımız massivləri də elan edirik

float vReal [nümunələri];

float vImag [nümunələri];

2) Təcili

Bir ArduinoFFT obyekti yaradırıq. ArduinoFFT -in inkişaf etdirmə versiyası bir şablondan istifadə edir ki, ya float, ya da ikiqat məlumat növündən istifadə edə bilək. Float (32 bit) proqramımızın ümumi dəqiqliyi baxımından kifayətdir.

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, nümunələr, samplingFrequency);

3) ADC dəyərləri ilə doldurulmaq əvəzinə, vReal massivini dolduraraq siqnalın simulyasiyası.

Döngünün əvvəlində vReal massivini doldururuq:

üzmə dövrləri = (((nümunələr) * siqnalFrequency) / nümunə götürməFrequency); // Nümunə götürmənin oxuyacağı siqnal dövrlərinin sayı

for (uint16_t i = 0; i <nümunələr; i ++) {vReal = float ((amplituda * (günah ((i * (TWO_PI * dövrlər)) / nümunələr))))); / * Müsbət və mənfi dəyərlər */ vReal += float ((amplituda * (günah ((3 * i * (TWO_PI * dövrlər))/ nümunələr)))/ 2.0);/ * Müsbət və mənfi dəyərləri olan məlumatları qurmaq */ vReal += float ((amplituda * (günah ((5 * i * (TWO_PI * dövrlər)) / nümunələr))) / 4.0); / * Müsbət və mənfi dəyərləri olan məlumatları qurun * / vImag = 0.0; // Yanlış hesablamaların və daşmaların qarşısını almaq üçün döngə halında xəyali hissə sıfırlanmalıdır}

Əsas dalğanın və daha az amplitüdlü iki harmonikin rəqəmsallaşdırılmasını əlavə edirik. Xəyali cərgəni sıfırlarla başladıqdan sonra. Bu sıra FFT alqoritmi ilə doldurulduğundan, hər yeni hesablamadan əvvəl onu yenidən silmək lazımdır.

4) FFT hesablama

Sonra FFT və spektral sıxlığı hesablayırıq

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

FFT.compute (FFTDirection:: İrəli); / * Compute FFT */ FFT.complexToMagnitude (); / * Böyüklükləri hesablayın */

FFT.windowing (…) əməliyyatı, xam məlumatları dəyişdirir, çünki FFT -ni məhdud sayda nümunə üzərində işləyirik. İlk və son nümunələr bir fasilə verir (bir tərəfində "heç nə" yoxdur). Bu bir səhv mənbəyidir. "Pəncərələşdirmə" əməliyyatı bu səhvi azaltmağa meyllidir.

"İrəli" istiqaməti ilə FFT.compute (…), zaman alanından tezlik sahəsinə çevrilməni hesablayır.

Sonra hər bir tezlik diapazonu üçün böyüklük (yəni intensivlik) dəyərlərini hesablayırıq. VReal dizisi artıq böyüklük dəyərləri ilə doludur.

5) Serial plotter rəsm

PrintVector funksiyasını çağıraraq serial plotterdəki dəyərləri çap edək (…)

PrintVector (vReal, (nümunələr >> 1), SCL_FREQUENCY);

Bu, vaxt oxu və ya tezlik oxu ilə məlumat çap etməyə imkan verən ümumi bir funksiyadır.

Ən böyük dəyərə malik olan bandın tezliyini də çap edirik

float x = FFT.majorPeak ();

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

Addım 5: Süni Siqnalın Təhlili - Nəticələr

Süni Siqnalın Təhlili - Nəticələr
Süni Siqnalın Təhlili - Nəticələr

Gözlənildiyi kimi f0 böyüklüyünün yarısı və 1/4 hissəsi olan 3 -cü və 5 -ci harmoniklərə əsas frekansa (f0), 3 -cü və 5 -ci harmoniklərə uyğun 3 sünbül görürük. Pəncərənin yuxarı hissəsində oxuya bilərik f0 = 440.430114 Hz. Bu dəyər, yuxarıda izah edilən bütün səbəblərə görə tam olaraq 440 Hz deyil, amma həqiqi dəyərə çox yaxındır. Bu qədər əhəmiyyətsiz ondalıkları göstərmək əslində lazım deyildi.

Addım 6: Həqiqi bir Siqnalın Təhlili - ADC -nin naqilləri

Həqiqi Siqnalın Təhlili - ADC -nin naqilləri
Həqiqi Siqnalın Təhlili - ADC -nin naqilləri

Nəzəri olaraq necə davam edəcəyimizi bildiyimiz üçün əsl bir siqnalı təhlil etmək istərdik.

Kablolama çox sadədir. Zəmini və siqnal xəttini 1 KOhm ilə 10 KOhm aralığında bir müqavimət vasitəsi ilə lövhənizin A0 pininə bağlayın.

Bu seriyalı rezistor analoq girişi qoruyacaq və zəng çalmağın qarşısını alacaq. Zəngdən qaçınmaq üçün mümkün qədər yüksək olmalıdır və ADC -ni sürətlə doldurmaq üçün kifayət qədər cərəyan təmin etmək üçün mümkün qədər aşağı olmalıdır. ADC girişində bağlı olan siqnalın gözlənilən empedansını bilmək üçün MCU məlumat cədvəlinə baxın.

Bu demo üçün 440 Hz tezlikdə sinusoidal siqnal və 5 volt civarında amplitüd vermək üçün bir funksiya generatoru istifadə etdim (amplitudun 3 ilə 5 volt arasında olması ən yaxşısıdır, buna görə ADC tam miqyasda istifadə olunur), 1.2 KOhm rezistor vasitəsilə.

Addım 7: Real Siqnalın Təhlili - Kodlaşdırma

0) Kitabxanaya daxil olun

#"arduinoFFT.h" daxil edin

1) Bəyannamələr və nümunələr

Bəyanat bölməsində, əvvəlki nümunədəki kimi ADC girişini (A0), nümunələrin sayını və seçmə tezliyini təyin edirik.

const bayt adcPin = 0; // A0

const uint16_t nümunələri = 1024; // Bu dəyər hər zaman 2 const uint16_t samplingFrequency = 8000 güc olmalıdır. // timer_setup () SYSCLOCK/8/sampling -də timer max dəyərinə təsir edəcək Tezlik tam ədəd olmalıdır

ArduinoFFT obyekti yaradırıq

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, nümunələr, samplingFrequency);

2) Taymer və ADC qurulması

Taymer 1 -ni təyin edirik ki, nümunə götürmə tezliyində (8 KHz) dövr etsin və çıxış müqayisəsində bir fasilə yaratsın.

boş vaxt timer_setup () {

// Taymeri sıfırla 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | bit (WGM12); // CTC, 8 TIMSK1 = bit (OCIE1B) prescaler; OCR1A = ((16000000 /8) / nümunə götürmə Tezliyi) -1; }

ADC -ni belə qurun

  • Giriş olaraq A0 istifadə edir
  • Hər bir zamanlayıcıda avtomatik olaraq tetikleyiciler 1 çıxış müqayisə B
  • Dönüşüm tamamlandıqda bir fasilə yaradır

ADC saatı, sistem saatını (16 MHz) 16 ilə əvvəlcədən ölçməklə 1 MHz olaraq təyin olunur. Hər bir çevrilmə təxminən 13 saatı tam miqyasda apardığından, dönüşümlər 1/13 = 0.076 MHz = 76 KHz tezliyində əldə edilə bilər. ADC -nin məlumatları nümunə götürmə vaxtına sahib olması üçün nümunə götürmə tezliyi 76 KHz -dən əhəmiyyətli dərəcədə aşağı olmalıdır. (fs = 8 KHz seçdik).

void adc_setup () {

ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // ADC yandırın, tamamlandıqda ADCSRA | = bit (ADPS2); // 16 ADMUX = bit (REFS0) üçün prescaler | (adcPin & 7); // ADC girişini təyin etmək ADCSRB = bit (ADTS0) | bit (ADTS2); // Taymer/Sayıcı1 Match B tetikleyici mənbəyini müqayisə edin ADCSRA | = bit (ADATE); // avtomatik tetiklemeyi yandırın}

Çevrilmiş məlumatları vReal massivində saxlamaq və kəsilmənin təmizlənməsi üçün hər ADC çevrilməsindən sonra çağırılacaq kəsmə işləyicisini elan edirik.

// ADC tam ISR

ISR (ADC_vect) {vReal [resultNumber ++] = ADC; if (resultNumber == nümunələri) {ADCSRA = 0; // ADC -ni söndürün}} EMPTY_INTERRUPT (TIMER1_COMPB_vect);

Arduinoda (analogRead) ADC çevrilməsi ilə bağlı tam bir izahat əldə edə bilərsiniz.

3) Quraşdırma

Quraşdırma funksiyasında xəyali məlumat cədvəlini təmizləyirik və taymer və ADC quraşdırma funksiyalarını çağırırıq

sıfır I (); // bütün xəyali məlumatları 0 olaraq təyin edən bir funksiya - əvvəlki hissədə izah edildi

timer_setup (); adc_setup ();

3) Döngə

FFT.dcRemoval (); // ADC yerə istinad edildiyindən bu siqnalın DC komponentini çıxarın

FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Forward); // FFT.compute məlumatlarını çəkin (FFTDirection:: Forward); // FFT FFT.complexToMagnitude hesablayın (); // Hesablama böyüklükləri // spektrin və əsas frekansın çap edilməsi f0 PrintVector (vReal, (nümunələr >> 1), SCL_FREQUENCY); float x = FFT.majorPeak (); Serial.print ("f0 ="); Serial. çap (x, 6); Serial.println ("Hz");

ADC -nin yerə istinad edildiyi və siqnalın təxminən 2,5 volt ətrafında olduğu üçün DC komponentini çıxarırıq.

Sonra məlumatları əvvəlki nümunədə izah edildiyi kimi hesablayırıq.

Addım 8: Real Siqnalın Təhlili - Nəticələr

Real Siqnalın Təhlili - Nəticələr
Real Siqnalın Təhlili - Nəticələr

Əslində bu sadə siqnalda yalnız bir tezlik görürük. Hesablanmış əsas tezlik 440.118194 Hz -dir. Burada yenə dəyər real tezliyin çox yaxın bir yaxınlaşmasıdır.

Addım 9: Kəsilmiş sinusoidal siqnal haqqında nə demək olar?

Kəsilmiş sinusoidal siqnal haqqında nə demək olar?
Kəsilmiş sinusoidal siqnal haqqında nə demək olar?

İndi siqnalın amplitüdünü 5 voltdan yuxarı artıraraq ADC -ni bir az aşmağa icazə verin, buna görə də kəsilir. ADC girişini məhv etməmək üçün çox itələməyin!

Bəzi harmoniklərin ortaya çıxdığını görə bilərik. Siqnalın kəsilməsi yüksək tezlikli komponentlər yaradır.

Bir Arduino lövhəsində FFT analizinin əsaslarını gördünüz. İndi nümunə götürmə tezliyini, nümunələrin sayını və pəncərə parametrini dəyişməyə cəhd edə bilərsiniz. Kitabxana, FFT -ni daha az dəqiqliklə daha sürətli hesablamaq üçün bəzi parametrlər də əlavə edir. Nümunə götürmə tezliyini çox aşağı qoysanız, spektral qatlama səbəbiylə hesablanan böyüklüklərin tamamilə səhv görünəcəyini görəcəksiniz.

Tövsiyə: