İçindekiler:

Atmega1284 Kullanan 1024 Örnek FFT Spektrum Analizörü: 9 Adım
Atmega1284 Kullanan 1024 Örnek FFT Spektrum Analizörü: 9 Adım

Video: Atmega1284 Kullanan 1024 Örnek FFT Spektrum Analizörü: 9 Adım

Video: Atmega1284 Kullanan 1024 Örnek FFT Spektrum Analizörü: 9 Adım
Video: Conditional jump instructions 2024, Kasım
Anonim
Bir Atmega1284 Kullanan 1024 Örnek FFT Spektrum Analizörü
Bir Atmega1284 Kullanan 1024 Örnek FFT Spektrum Analizörü
Bir Atmega1284 Kullanan 1024 Örnek FFT Spektrum Analizörü
Bir Atmega1284 Kullanan 1024 Örnek FFT Spektrum Analizörü

Bu nispeten kolay öğretici (bu konunun karmaşıklığı göz önüne alındığında), bir Arduino tipi kart (1284 Narrow) ve seri çizici kullanarak çok basit bir 1024 örnek spektrum analizörünü nasıl yapabileceğinizi gösterecektir. Her türlü Arduino uyumlu anakart işinizi görür, ancak ne kadar fazla RAM'e sahipse, o kadar iyi frekans çözünürlüğü elde edersiniz. 1024 örnekle FFT'yi hesaplamak için 8 KB'den fazla RAM'e ihtiyaç duyacaktır.

Spektrum analizi, bir sinyalin ana frekans bileşenlerini belirlemek için kullanılır. Birçok ses (bir müzik aleti tarafından üretilenler gibi) temel bir frekanstan ve temel frekansın tam sayı katı olan bir frekansa sahip bazı harmoniklerden oluşur. Spektrum analizörü size tüm bu spektral bileşenleri gösterecektir.

Bu kurulumu bir frekans sayacı olarak kullanmak veya elektronik devrenize biraz gürültü getirdiğinden şüphelendiğiniz her türlü sinyali kontrol etmek isteyebilirsiniz.

Burada yazılım kısmına odaklanacağız. Belirli bir uygulama için kalıcı bir devre yapmak istiyorsanız, sinyali yükseltmeniz ve filtrelemeniz gerekecektir. Bu ön koşullandırma, genliğine, empedansına, maksimum frekansına vb. bağlı olarak çalışmak istediğiniz sinyale tamamen bağlıdır…

Adım 1: Kitaplığı Yükleme

Enrique Condes tarafından yazılmış ArduinoFFT kütüphanesini kullanacağız. RAM'i olabildiğince fazla ayırmak istediğimizden, örneklenen ve hesaplanan verileri depolamak için kayan veri türünü (çift yerine) kullanmaya izin veren bu havuzun geliştirme dalını kullanacağız. Bu yüzden manuel olarak yüklememiz gerekiyor. Endişelenmeyin, arşivi indirin ve Arduino kitaplığı klasörünüzde açın (örneğin, Windows 10 varsayılan yapılandırmasında: C:\Users\_your_user_name_\Documents\Arduino\libraries)

"FFT_01.ino" gibi sağlanan örneklerden birini derleyerek kitaplığın doğru şekilde kurulup kurulmadığını kontrol edebilirsiniz.

Adım 2: Fourier Dönüşümü ve FFT Kavramları

Uyarı: Herhangi bir matematiksel gösterimi görmeye dayanamıyorsanız Adım 3'e geçmek isteyebilirsiniz. Her neyse, hepsini anlamadıysanız, bölümün sonundaki sonucu düşünün.

Frekans spektrumu, Hızlı Fourier Dönüşümü algoritması ile elde edilir. FFT, Fourier Dönüşümünün matematiksel konseptine yaklaşan bir dijital uygulamadır. Bu kavram altında, bir zaman eksenini takip eden bir sinyalin evrimini elde ettiğinizde, karmaşık (gerçek + hayali) değerlerden oluşan bir frekans alanındaki temsilini bilirsiniz. Konsept karşılıklıdır, bu nedenle frekans alanı gösterimini bildiğinizde onu zaman alanına geri dönüştürebilir ve sinyali dönüşümden önceki gibi tam olarak geri alabilirsiniz.

Ama zaman alanındaki bu hesaplanmış karmaşık değerler kümesiyle ne yapacağız? Eh, çoğu mühendislere bırakılacak. Bizim için bu karmaşık değerleri spektral yoğunluk verilerine dönüştürecek başka bir algoritma arayacağız: bu, her bir frekans bandıyla ilişkili bir büyüklük (= yoğunluk) değeridir. Frekans bandı sayısı, örnek sayısı kadar olacaktır.

Bunun gibi ekolayzır konseptine kesinlikle aşinasınızdır. Grafik EQ ile 1980'lere dönüş. Eh, aynı tür sonuçları elde edeceğiz, ancak 16 yerine 1024 bant ve çok daha fazla yoğunluk çözünürlüğü ile. Ekolayzır, müziğin küresel bir görünümünü verdiğinde, ince spektral analiz, 1024 bandın her birinin yoğunluğunu tam olarak hesaplamaya izin verir.

Mükemmel bir konsept, ancak:

  1. FFT, Fourier dönüşümünün dijitalleştirilmiş bir versiyonu olduğundan, dijital sinyale yaklaşır ve bazı bilgileri kaybeder. Bu nedenle, kesinlikle konuşursak, FFT'nin sonucu, ters çevrilmiş bir FFT algoritması ile geri dönüştürülürse, tam olarak orijinal sinyali vermeyecektir.
  2. Ayrıca teori, sonlu olmayan bir sinyali de göz önünde bulundurur, ancak bu sürekli kalıcı bir sabit sinyaldir. Sadece belirli bir süre (yani numuneler) için dijitalleştireceğimiz için bazı hatalar daha ortaya çıkacaktır.
  3. Son olarak, analogdan dijitale dönüştürmenin çözünürlüğü, hesaplanan değerlerin kalitesini etkileyecektir.

Uygulamada

1) Örnekleme frekansı (fs olarak belirtilmiştir)

Bir sinyali örnekleyeceğiz, yani her 1/fs saniyede bir genliğini ölçeceğiz. fs örnekleme frekansıdır. Örneğin, 8 KHz'de örnekleme yaparsak, çipte bulunan ADC (analogdan dijitale dönüştürücü) her 1/8000 saniyede bir ölçüm sağlayacaktır.

2) Numune sayısı (kodda belirtilen N veya numuneler)

FFT'yi çalıştırmadan önce tüm değerleri almamız gerektiğinden, bunları saklamamız gerekecek ve bu nedenle örnek sayısını sınırlayacağız. FFT algoritması, 2'nin gücünde bir dizi örneğe ihtiyaç duyar. Arduino FFT kütüphanesi kullanarak biraz yer tasarrufu sağlar

  • Örneklenen verileri ve ardından dönüştürülmüş verilerin gerçek kısmını depolamak için "vReal" adlı bir dizi
  • Dönüştürülen verilerin sanal kısmını depolamak için "vImag" adlı bir dizi

Gerekli RAM miktarı 2 (dizi) * 32 (bit) * N'ye (örnekler) eşittir.

Yani 16 KB'lık güzel bir RAM'e sahip olan Atmega1284'ümüzde maksimum N = 16000*8 / 64 = 2000 değer depolayacağız. Değerlerin sayısı 2'nin katı olması gerektiğinden, maksimum 1024 değer saklayacağız.

3) Frekans çözünürlüğü

FFT, örnek sayısı kadar frekans bandı için değerleri hesaplayacaktır. Bu bantlar 0 HZ'den örnekleme frekansına (fs) kadar yayılacaktır. Dolayısıyla, frekans çözünürlüğü:

Çözünürlük = fs / N

Çözünürlük daha düşük olduğunda daha iyidir. Yani daha iyi çözünürlük (daha düşük) için şunu istiyoruz:

  • daha fazla örnek ve/veya
  • daha düşük bir fs

Fakat…

4) Minimum fs

Çok sayıda frekans görmek istediğimiz için, bazıları "temel frekanstan" çok daha yüksek, fs'yi çok düşük ayarlayamayız. Aslında, bizi test etmek istediğimiz maksimum frekansın iki katının çok üzerinde bir örnekleme frekansına sahip olmaya zorlayan Nyquist-Shannon örnekleme teoremi vardır.

Örneğin, 0 Hz'den diyelim ki 15 KHz'e kadar tüm spektrumu analiz etmek istersek, bu yaklaşık olarak çoğu insanın net bir şekilde duyabileceği maksimum frekanstır, örnekleme frekansını 30 KHz'e ayarlamamız gerekir. Aslında elektronikçiler bunu genellikle maksimum frekans 2,5'e (hatta 2,52) * ayarlarlar. Bu örnekte 2.5 * 15 KHz = 37.5 KHz olacaktır. Profesyonel seste olağan örnekleme frekansları 44,1 KHz (ses CD'si kaydı), 48 KHz ve daha fazlasıdır.

Çözüm:

1'den 4'e kadar olan noktalar şunlara yol açar: Mümkün olduğu kadar çok örnek kullanmak istiyoruz. 16 KB RAM cihazı ile bizim durumumuzda 1024 örneği ele alacağız. Sinyalimizde beklediğimiz en yüksek frekansı (en az 2,5 * bu frekans) analiz etmek için yeterince yüksek olduğu sürece, mümkün olan en düşük örnekleme frekansında örnekleme yapmak istiyoruz.

Adım 3: Bir Sinyal Simülasyonu

Bir Sinyali Simüle Etme
Bir Sinyali Simüle Etme

İlk denememiz için, kütüphanede verilen TFT_01.ino örneğini, aşağıdakilerden oluşan bir sinyali analiz etmek için biraz değiştireceğiz.

  • 440 Hz'ye ayarlanmış temel frekans (müzikal A)
  • Temelin yarısı gücünde 3. harmonik ("-3 dB")
  • Temelin gücünün 1/4'ünde 5. harmonik ("-6 dB)

Ortaya çıkan sinyali yukarıdaki resimde görebilirsiniz. Sinüzoidal bir sinyalin kırpılması durumunda, bazen bir osiloskopta ("Batman" derdim) görebileceğiniz gerçek bir sinyale çok benziyor.

Adım 4: Simüle Edilmiş Bir Sinyalin Analizi - Kodlama

0) Kütüphaneyi dahil et

#include "arduinoFFT.h"

1. Tanımlar

Bildirimler bölümlerinde, const bayt adcPin = 0; // A0

const uint16_t örnekleri = 1024; // Bu değer DAİMA 2'nin gücü OLMALIDIR. const uint16_t örneklemeFrequency = 8000; // timer_setup() içindeki zamanlayıcı maksimum değerini etkiler SYSCLOCK/8/samplingFrequency bir tamsayı olmalıdır

Sinyal 5. harmoniğe sahip olduğundan (bu harmoniğin frekansı = 5 * 440 = 2200 Hz) örnekleme frekansını 2,5*2200 = 5500 Hz'nin üzerine ayarlamamız gerekiyor. Burada 8000 Hz seçtim.

Ayrıca ham ve hesaplanmış verileri depolayacağımız dizileri de bildiririz.

kayan vReal[örnekler];

kayan vImag[örnekler];

2) Örnekleme

Bir ArduinoFFT nesnesi oluşturuyoruz. ArduinoFFT'nin geliştirici sürümü bir şablon kullanır, böylece kayan nokta veya çift veri türünü kullanabiliriz. Float (32 bit), programımızın genel hassasiyeti açısından yeterlidir.

ArduinoFFT FFT = ArduinoFFT(vReal, vImag, örnekler, örnekleme Frekansı);

3) ADC değerleriyle doldurulması yerine vReal dizisini doldurarak sinyali simüle etmek.

Döngünün başında vReal dizisini aşağıdakilerle doldururuz:

şamandıra döngüleri = (((örnekler) * sinyal Frekansı) / örnekleme Frekansı); //Örneklemenin okuyacağı sinyal döngüsü sayısı

for (uint16_t i = 0; i < örnekler; i++) { vReal = float((genlik * (sin((i * (TWO_PI * döngü)) / örnekler))));/* Pozitif ve negatif değerler*/ vReal += float((genlik * (sin((3 * i * (TWO_PI * döngü)) / örnekler))) / 2.0);/* Pozitif ve negatif değerlerle veri oluştur*/ vReal += float((genlik * (sin((5 * i * (TWO_PI * döngü)) / örnekler))) / 4.0);/* Pozitif ve negatif değerlerle veri oluşturun*/ vImag = 0.0; //Yanlış hesaplamaları ve taşmaları önlemek için döngü durumunda hayali kısım sıfırlanmalıdır }

Temel dalganın sayısallaştırılmasını ve daha az genlikle iki harmoniği ekliyoruz. Daha sonra hayali diziyi sıfırlarla başlatıyoruz. Bu dizi FFT algoritması tarafından doldurulduğundan, her yeni hesaplamadan önce onu tekrar temizlememiz gerekir.

4) FFT hesaplama

Sonra FFT'yi ve spektral yoğunluğu hesaplıyoruz

FFT.windowing(FFTWindow::Hamming, FFTYön::İleri);

FFT.compute(FFTDyön::İleri); /* FFT Hesapla */ FFT.complexToMagnitude(); /* Büyüklükleri hesapla */

FFT.windowing(…) işlemi, FFT'yi sınırlı sayıda örnek üzerinde çalıştırdığımız için ham verileri değiştirir. İlk ve son örnekler bir süreksizlik gösterir (bir tarafta "hiçbir şey" yoktur). Bu bir hata kaynağıdır. "Pencereleme" işlemi bu hatayı azaltma eğilimindedir.

FFT.compute(…) "İleri" yönü ile zaman alanından frekans alanına dönüşümü hesaplar.

Ardından, frekans bantlarının her biri için büyüklük (yani yoğunluk) değerlerini hesaplıyoruz. vReal dizisi şimdi büyüklük değerleriyle doldurulur.

5) Seri çizici çizimi

printVector(…) fonksiyonunu çağırarak seri çiziciye değerleri yazdıralım.

PrintVector(vReal, (örnekler >> 1), SCL_FREQUENCY);

Bu, verilerin bir zaman ekseni veya bir frekans ekseni ile yazdırılmasına izin veren genel bir işlevdir.

En yüksek kadir değerine sahip bandın frekansını da yazdırıyoruz.

kayan nokta x = FFT.majorPeak();

Seri.print("f0="); Seri.baskı(x, 6); Seri.println("Hz");

Adım 5: Simüle Edilmiş Bir Sinyalin Analizi - Sonuçlar

Simüle Edilmiş Bir Sinyalin Analizi - Sonuçlar
Simüle Edilmiş Bir Sinyalin Analizi - Sonuçlar

Beklendiği gibi, f0 büyüklüğünün yarısı ve 1/4'ü ile 3. ve 5. harmonikler olan temel frekansa (f0) karşılık gelen 3 ani görüyoruz. Pencerenin üst kısmında f0= 440.430114 Hz okuyabiliriz. Bu değer, yukarıda açıklanan tüm nedenlerden dolayı tam olarak 440 Hz değildir, ancak gerçek değere çok yakındır. Bu kadar önemsiz ondalık sayı göstermek gerçekten gerekli değildi.

Adım 6: Gerçek Bir Sinyalin Analizi - ADC'nin Kablolanması

Gerçek Sinyalin Analizi - ADC'nin Kablolanması
Gerçek Sinyalin Analizi - ADC'nin Kablolanması

Teoride nasıl ilerleyeceğimizi bildiğimiz için gerçek bir sinyali analiz etmek istiyoruz.

Kablolama çok basittir. Toprakları ve sinyal hattını 1 KOhm ila 10 KOhm değerinde bir seri direnç aracılığıyla kartınızın A0 pinine bağlayın.

Bu seri direnç, analog girişi koruyacak ve çalmayı önleyecektir. Çalmayı önlemek için mümkün olduğunca yüksek ve ADC'yi hızlı bir şekilde şarj etmek için yeterli akımı sağlamak için mümkün olduğunca düşük olmalıdır. ADC girişine bağlanan sinyalin beklenen empedansını öğrenmek için MCU veri sayfasına bakın.

Bu demo için, 440 Hz frekanslı ve yaklaşık 5 voltluk bir sinüzoidal sinyali beslemek için bir fonksiyon üreteci kullandım (genlik 3 ila 5 volt arasındaysa en iyisidir, bu nedenle ADC tam ölçeğe yakın kullanılır), 1.2 KOhm direnç aracılığıyla.

Adım 7: Gerçek Bir Sinyalin Analizi - Kodlama

0) Kütüphaneyi dahil et

#include "arduinoFFT.h"

1) Beyanlar ve örnekleme

Beyan bölümünde, önceki örnekte olduğu gibi ADC girişini (A0), örnek sayısını ve örnekleme frekansını tanımlıyoruz.

const bayt adcPin = 0; // A0

const uint16_t örnekleri = 1024; // Bu değer DAİMA 2'nin gücü OLMALIDIR. const uint16_t örneklemeFrequency = 8000; // timer_setup() içindeki timer max değerini etkiler SYSCLOCK/8/samplingFrequency bir tamsayı olmalıdır

ArduinoFFT nesnesini oluşturuyoruz

ArduinoFFT FFT = ArduinoFFT(vReal, vImag, örnekler, örnekleme Frekansı);

2) Zamanlayıcı ve ADC kurulumu

Zamanlayıcı 1'i, örnekleme frekansında (8 KHz) döngü yapacak ve çıkış karşılaştırmasında bir kesinti oluşturacak şekilde ayarladık.

geçersiz timer_setup(){

// Zamanlayıcı 1'i sıfırla TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | bit (WGM12); // CTC, 8 TIMSK1'in ön ölçekleyicisi = bit (OCIE1B); OCR1A = ((16000000 / 8) / örnekleme Frekansı) -1; }

Ve ADC'yi öyle ayarlayın

  • Giriş olarak A0 kullanır
  • Her zamanlayıcıda otomatik olarak tetiklenir 1 çıkış karşılaştırma eşleşmesi B
  • Dönüştürme tamamlandığında bir kesinti oluşturur

ADC saati, sistem saatini (16 MHz) 16 ile önceden ölçeklendirerek 1 MHz'e ayarlanır. Her dönüşüm tam ölçekte yaklaşık 13 saat sürdüğü için, dönüşümler 1/13 = 0.076 MHz = 76 KHz frekansında elde edilebilir. ADC'nin verileri örnekleme zamanına sahip olması için örnekleme frekansı 76 KHz'den önemli ölçüde düşük olmalıdır. (fs = 8 KHz seçtik).

geçersiz adc_setup() {

ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // ADC'yi aç, tamamlandığında kesme istiyor ADCSRA |= bit (ADPS2); // 16 ADMUX ön ölçekleyicisi = bit (REFS0) | (adcPin & 7); // ADC girişinin ayarlanması ADCSRB = bit (ADTS0) | bit (ADTS2); // Zamanlayıcı/Sayaç1 Karşılaştır Eşleştirme B tetikleyici kaynağı ADCSRA |= bit (ADATE); // otomatik tetiklemeyi aç }

Dönüştürülen verileri vReal dizisinde depolamak için her ADC dönüşümünden sonra çağrılacak kesme işleyicisini ve kesmenin temizlenmesini bildiririz.

// ADC, ISR'yi tamamladı

ISR (ADC_vect) { vReal[resultNumber++] = ADC; if(resultNumber == örnekler) { ADCSRA = 0; // ADC'yi kapat } } EMPTY_INTERRUPT (TIMER1_COMPB_vect);

Arduino'da (analogRead) ADC dönüşümü hakkında kapsamlı bir açıklamaya sahip olabilirsiniz.

3) Kurulum

Kurulum fonksiyonunda hayali veri tablosunu temizliyoruz ve timer ve ADC kurulum fonksiyonlarını çağırıyoruz.

sıfırI(); // tüm hayali verileri 0'a ayarlayan bir fonksiyon - önceki bölümde açıklanmıştır

timer_setup(); adc_setup();

3) döngü

FFT.dcRemoval(); // ADC toprağa referans verildiğinden bu sinyalin DC bileşenini kaldırın

FFT.windowing(FFTWindow::Hamming, FFTYön::İleri); // Verileri tartın FFT.compute(FFTDireksiyon::İleri); // FFT'yi hesapla FFT.complexToMagnitude(); // Büyüklükleri hesapla // spektrumu ve temel frekansı yazdırma f0 PrintVector(vReal, (örnekler >> 1), SCL_FREQUENCY); kayan nokta x = FFT.majorPeak(); Seri.print("f0="); Seri.baskı(x, 6); Seri.println("Hz");

DC bileşenini çıkarıyoruz çünkü ADC toprağa referansta bulunuyor ve sinyal yaklaşık olarak 2,5 volt civarında ortalanıyor.

Ardından verileri önceki örnekte açıklandığı gibi hesaplıyoruz.

Adım 8: Gerçek Bir Sinyalin Analizi - Sonuçlar

Gerçek Sinyalin Analizi - Sonuçlar
Gerçek Sinyalin Analizi - Sonuçlar

Aslında bu basit sinyalde sadece bir frekans görüyoruz. Hesaplanan temel frekans 440.118194 Hz'dir. Burada yine değer, gerçek frekansın çok yakın bir tahminidir.

Adım 9: Kırpılmış Sinüzoidal Sinyale Ne Dersiniz?

Kırpılmış Sinüzoidal Sinyale Ne Dersiniz?
Kırpılmış Sinüzoidal Sinyale Ne Dersiniz?

Şimdi, sinyalin genliğini 5 voltun üzerine çıkararak ADC'yi biraz fazla zorlamaya izin verin, böylece kırpılır. ADC girişini yok etmemek için çok fazla zorlamayın!

Bazı harmoniklerin ortaya çıktığını görebiliriz. Sinyalin kırpılması, yüksek frekanslı bileşenler oluşturur.

Bir Arduino kartında FFT analizinin temellerini gördünüz. Şimdi örnekleme frekansını, örnek sayısını ve pencereleme parametresini değiştirmeyi deneyebilirsiniz. Kitaplık ayrıca FFT'yi daha az hassasiyetle daha hızlı hesaplamak için bazı parametreler ekler. Örnekleme frekansını çok düşük ayarlarsanız, spektral katlama nedeniyle hesaplanan büyüklüklerin tamamen hatalı görüneceğini fark edeceksiniz.

Önerilen: