İçindekiler:

EasyFFT: Arduino için Hızlı Fourier Dönüşümü (FFT): 6 Adım
EasyFFT: Arduino için Hızlı Fourier Dönüşümü (FFT): 6 Adım

Video: EasyFFT: Arduino için Hızlı Fourier Dönüşümü (FFT): 6 Adım

Video: EasyFFT: Arduino için Hızlı Fourier Dönüşümü (FFT): 6 Adım
Video: Arduino FFT Test 2024, Kasım
Anonim
Image
Image

Yakalanan sinyalden frekansın ölçülmesi, özellikle Arduino'da daha düşük hesaplama gücüne sahip olduğu için zor bir görev olabilir. Sinyalin verilen süre içinde sıfır çizgilerini kaç kez geçtiğini kontrol ederek frekansın yakalandığı sıfır geçişi yakalamak için mevcut yöntemler vardır. Böyle bir yöntem, sinyal çeşitli frekansların bir kombinasyonu olduğunda çalışmayabilir.

Böyle bir geçmişe sahip değilseniz, bunu kodlamak bir şekilde zordur. Ancak bir tamirci olarak bu kod, müzik, sinyal analizi ile ilgili çeşitli projeler için oldukça faydalı olabilir. Bu projenin amacı, arka planına girmeden Arduino üzerinde uygulanması kolay bir kod hazırlamaktı.

Bu proje, FFT'nin Çalışmasını açıklamaz, ancak FFT işlevinin uygulamasını açıklar. Aynı işlem ekteki videoda da anlatılmıştır.

Yalnızca kodun uygulanmasıyla ilgileniyorsanız ve bunun bir açıklamasıyla ilgilenmiyorsanız. Doğrudan 3 numaralı adıma geçebilirsiniz.

Adım 1: Frekans Dönüşümüne Giriş

Frekans Dönüşümüne Giriş
Frekans Dönüşümüne Giriş
Frekans Dönüşümüne Giriş
Frekans Dönüşümüne Giriş

Herhangi bir sinyal, çeşitli sinüzoidal dalgaların bir kombinasyonundan oluşabilir. Dolayısıyla herhangi bir zamana dayalı sinyal, farklı genliklerin çeşitli sinüslerinin bir kombinasyonu olarak da gösterilebilir.

DFT'nin (ayrık Fourier dönüşümü) çalışmasını önceki öğretilebilirlerden birinde açıklamaya çalıştım (https://www.instructables.com/id/Arduino-Frequency…). Bu yöntemler, herhangi bir gerçek zamanlı uygulama için son derece yavaştır. bu da onu neredeyse işe yaramaz hale getiriyor.

Resimde, f2 ve f5 frekanslarının bir kombinasyonu olan bir sinyal gösterilmektedir. Bu sinyal, f1 ila f5 değerlerinin test sinüs dalgaları ile çarpılır.

Farklı frekansa sahip iki harmonik veri kümesinin çarpımının toplamının sıfıra meylettiği matematiksel olarak gösterilebilir (daha fazla veri, meyilli sonuca yol açabilir). Bizim durumumuzda, bu iki çarpma frekansı aynı (veya çok yakın) frekansa sahipse, çarpma toplamı sıfır olmayan sayıdır.

Yani sinyalimiz f1 ile çarpılırsa çarpmanın toplamı sıfır olacaktır (gerçek uygulama için sıfıra yakın). f3, f4 için de durum aynıdır. Ancak değer için f2 ve f5 çıktısı sıfır olmayacak, ancak diğer değerlerden önemli ölçüde yüksek olacaktır.

Burada bir sinyal 5 frekansla test edilir, bu nedenle sinyalin beş frekansla çarpılması gerekir. Böyle yoğun bir hesaplama daha fazla zaman alır. Matematiksel olarak, N sayıda örnek için N*N karmaşık çarpım aldığı gösterilmiştir.

Adım 2: Hızlı Fourier Dönüşümü

DFT'nin daha hızlı hesaplanmasını sağlamak için FFT algoritması James Cooley ve John Tukey tarafından geliştirilmiştir. Bu algoritma aynı zamanda 20. yüzyılın en önemli algoritmalarından biri olarak kabul edilmektedir. Bir sinyali, bir dizi gerekli hesaplamayı daha düşük yapan tek ve çift sıralı bir parçaya böler. Bunu kullanarak, toplam gerekli karmaşık çarpma NlogN'ye indirgenebilir. bu önemli bir gelişme.

FFT'nin arkasındaki matematiğin ayrıntılı bir şekilde anlaşılması için kodu yazarken atıfta bulunduğum aşağıdaki referanslara başvurabilirsiniz:

1.

2.

3.

4.

Adım 3: Kodun Açıklaması

1. Hızlı sinüs ve Kosinüs:

Hesaplama FFT, çeşitli sinüs ve kosinüs değerlerini birden çok kez alır. Arduino'nun dahili işlevi yeterince hızlı değil ve gerekli değeri sağlamak için çok zaman alıyor. Bu, kodu önemli ölçüde yavaşlatır (64 örnek için süreyi iki katına çıkarır). Bu sorunu gidermek için 0 ila 90 derece için sinüs değeri 255'in katları olarak saklanır. Bunu yapmak, sayıları yüzer olarak saklama ihtiyacını ortadan kaldıracak ve Arduino'da 1/4 alanı kaplayan bayt olarak saklayabiliriz. sine_data öğesinin, onu global bir değişken olarak bildirmek için kodun üstüne yapıştırması gerekir.

sine_data dışında, f_peaks adlı bir dizi global değişken olarak bildirildi. FFT işlevinin her çalışmasından sonra bu dizi güncellenir. Burada f_peaks[0] en baskın frekans ve azalan sırada diğer değerlerdir.

bayt sinüs_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 ile 90 derece arasında sinüs değerini sakladığımız için herhangi bir sinüs veya kosinüs değeri hesaplanabilir. Aşağıda, sayının ilk turunu sıfır ondalık basamağa ve depolanan verilerden değer döndürmeye çalışın. bu yöntem yalnızca bir kayan bölüme ihtiyaç duyar. Bu, sinüs değerlerinin (255 çoklu değil) doğrudan saklanmasıyla daha da azaltılabilir. ama bu Arduino'da yüksek hafızayı yiyor.

Yukarıdaki prosedürün kullanılması doğruluğu azaltır ancak hızı artırır. 64 puan için 8ms, 128 puan için 20ms avantaj sağlar.

Adım 4: Kodun Açıklaması: FFT Fonksiyonu

FFT sadece 2, 4, 8, 16, 32, 64 ve benzeri örneklem büyüklüğü için gerçekleştirilebilir. değer 2^n değilse, değerin alt tarafını alacaktır. Örneğin, örnek boyutunu 70 olarak seçersek, yalnızca ilk 64 örneği dikkate alacak ve dinlenmeyi atlayacaktır.

Örnek boyutunun her zaman 2^n olması önerilir. hangisi olabilir:

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

İki float out_r ve out_im, yüksek miktarda bellek alacaktır. Arduino nano için, kullanılabilir bellek eksikliği nedeniyle 128'den (ve bazı durumlarda 128'den) daha yüksek örnekler için çalışmaz.

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++) //düzeylerin hesaplanması { if(data<=a){o=i;} } int in_ps[data[o]={}; //dizileme için giriş float out_r[data[o]={}; // dönüşümün gerçek kısmı float out_im[data[o]={}; // dönüşümün hayali kısmı

Daha fazla akış aşağıdaki gibidir:

1. Kod, verilen örnek boyutu için sırayı biraz tersine çevirir (referanslarda bitin tersine çevrilmesiyle ilgili ayrıntılar: 2. adım)

2. Oluşturulan siparişe göre sıralanan giriş verileri, 3. FFT gerçekleştirildi

4. Hesaplanan karmaşık sayının genliği, 5. Pikler algılanır ve azalan sırada sıralanır

6. sonuçlara f_peaks adresinden erişilebilir.

[diğer verilere erişmek için (tepe frekansı dışında) kod değiştirilmelidir, böylece yerel değişken önceden tanımlanmış bazı global değişkenlere kopyalanabilir]

Adım 5: Kodu Test Etme

Kodu Test Etme
Kodu Test Etme
Kodu Test Etme
Kodu Test Etme

Giriş olarak örnek bir üçgen dalga verilir. bu dalga için örnekleme frekansı 10 Hz'dir ve dalganın kendisinin frekansı 1,25 Hz'dir.

Ham çıktıdan da anlaşılacağı gibi, değer Scilab tarafından hesaplanan FFT ile eşleşiyor. ancak, bu değerler bizim düşük doğrulukla tam olarak aynı değil, daha hızlı sinüs dalgası.

Çıkış frekansında dizi frekansı 1.25 ve 3.75'tir. her seferinde tam değeri almak gerekli değildir. tipik olarak bu sayılara frekans kutuları denir. bu nedenle çıktı değeri belirtilen kutular içinde herhangi bir yerde olabilir.

Hız:

Arduino nano için şunları alır:

16 Puan: 4ms32 Puan: 10ms 64 Puan: 26ms 128 Puan: 53ms

6. Adım: Sonuç

Bu FFT kodu gerçek zamanlı uygulamalarda kullanılabilir. Hesaplamayı tamamlamak yaklaşık 30 ms sürdüğü için. Ancak çözünürlüğü birkaç örnekle sınırlıdır. Örnek sayısı Arduino hafızası ile sınırlıdır. Arduino Mega veya diğer yüksek performanslı kartlar kullanılarak doğruluk artırılabilir.

Herhangi bir sorunuz, öneriniz veya düzeltmeniz varsa, yorum yapmaktan çekinmeyin.

Güncelleme (2/5/21)

Güncellemeler://-----------------------------FFT İşlevi--------------- ----------------------------------//float FFT(int in, int N, float Frekans)

N veri türü, >255 örnek boyutunu desteklemek için Tamsayı (mevcut Bayt) olarak değiştirildi. Örnek boyutu <=128 ise byte veri tipi kullanılmalıdır.

Önerilen: