Съдържание:

EasyFFT: Бърза трансформация на Фурие (FFT) за Arduino: 6 стъпки
EasyFFT: Бърза трансформация на Фурие (FFT) за Arduino: 6 стъпки

Видео: EasyFFT: Бърза трансформация на Фурие (FFT) за Arduino: 6 стъпки

Видео: EasyFFT: Бърза трансформация на Фурие (FFT) за Arduino: 6 стъпки
Видео: Учебник по Python: изучите Scipy — быстрое преобразование Фурье (scipy.fftpack) за 17 минут 2024, Ноември
Anonim
Image
Image

Измерването на честотата от уловения сигнал може да бъде трудна задача, особено на Arduino, тъй като има по -ниска изчислителна мощност. Има налични методи за улавяне на пресичане на нула, където честотата се улавя чрез проверка колко пъти сигналът пресича нулеви линии в рамките на даденото време. Такъв метод може да не работи, когато сигналът е комбинация от различни честоти.

Това по някакъв начин е трудно да се кодира, ако не сте от такъв произход. Но като тинкер, този код може да бъде много полезен за различни проекти, свързани с музика, анализ на сигнали. Мотивът на този проект беше да подготви код, който е лесен за изпълнение на Arduino, без да навлиза в неговия фон.

Този проект не обяснява работата на FFT, но обяснява приложението на функцията FFT. Същият процес е обяснен и в прикаченото видео.

Ако се интересувате само от приложението на кода, а не от неговото обяснение. Можете да преминете директно към стъпка № 3.

Стъпка 1: Въведение в честотната трансформация

Въведение в честотната трансформация
Въведение в честотната трансформация
Въведение в честотната трансформация
Въведение в честотната трансформация

Всеки сигнал може да бъде съставен от комбинация от различни синусоидални вълни. Така че всеки сигнал, базиран на времето, може да бъде показан и като комбинация от различните синуси с различни амплитуди.

Опитах се да обясня работата на DFT (дискретно преобразуване на Фурие) в една от предишните инструкции (https://www.instructables.com/id/Arduino-Frequency…). Тези методи са изключително бавни за всяко приложение в реално време. което го прави почти безполезен.

На изображението е показан сигнал, който е комбинация от две честоти f2 и f5. Този сигнал се умножава по тестови синусоиди със стойности от f1 до f5.

Математически може да се покаже, че -сумирането на умножение на два хармонични набора от данни с различна честота се стреми към нула (по -голям брой данни може да доведе до резултат на тесто). В нашия случай, ако тези две честоти на умножение имат една и съща (или много близка) честота, тази сума на умножението е ненулевото число.

Така че, ако нашият сигнал се умножи по f1, сумирането на умножението ще бъде нула (близо до нула за реално приложение). подобен е случаят с f3, f4. За стойността обаче изходът f2 и f5 няма да е нула, а значително по -висок от останалите стойности.

Тук се тества сигнал с 5 честоти, така че сигналът трябва да се умножи по пет честоти. Такова интензивно изчисление отнема повече време. Математически е показано, че за N брой проби е необходимо N*N комплексно умножение.

Стъпка 2: Бърза трансформация на Фурие

За да се направи изчислението на DFT по -бърз FFT алгоритъм е разработен от Джеймс Кули и Джон Тюки. Този алгоритъм също се счита за един от най -важните алгоритми на 20 -ти век. Той разделя сигнала на нечетна и четна последователна част, което прави редица необходими изчисления по -ниски. Чрез него общото необходимо комплексно умножение може да бъде намалено до NlogN. което е значително подобрение.

Можете да се обърнете по -долу към препратките, които споменах, докато пишех кода за подробно разбиране на математиката зад FFT:

1.

2.

3.

4.

Стъпка 3: Обяснение на кода

1. Бърз синус и косинус:

Изчисляването FFT приема стойността на различни синуси и косинуси многократно. Вградената функция на Arduino не е достатъчно бърза и отнема много време, за да осигури необходимата стойност. Което прави кода значително по -бавен (удвоява времето за 64 проби). За да се противодейства на този проблем, стойността на синуса за 0 до 90 градуса се съхранява като кратна на 255. Това ще премахне необходимостта от използване на съхраняване на числа като поплавък и можем да го съхраним като байт, който заема 1/4 място в Arduino. Sine_data трябва да постави в горната част на кода, за да го декларира като глобална променлива.

Освен sine_data, масив, наречен f_peaks , деклариран като глобална променлива. След всяко изпълнение на функцията FFT този масив се актуализира. Където f_peaks [0] е най -доминиращата честота и допълнителни стойности в низходящ ред.

байт 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];

Тъй като имаме запазена стойност на синус за 0 до 90 градуса, всяка стойност на синус или косинус може да бъде изчислена. По -долу функционира първият кръг на числото до нулева десетична точка и връщаната стойност от съхранените данни. този метод се нуждае само от едно плаващо разделение. Това може да бъде намалено допълнително чрез директно съхраняване на синусови стойности (не 255 кратни). но това изяжда много памет на Arduino.

Използването на горната процедура намалява точността, но подобрява скоростта. За 64 точки дава предимство от 8 мс, а за 128 точки дава предимство от 20 мс.

Стъпка 4: Обяснение на кода: FFT функция

FFT може да се извърши само за размер на извадката 2, 4, 8, 16, 32, 64 и така нататък. ако стойността не е 2^n, тогава тя ще вземе долната страна на стойността. Например, ако изберем размер на извадката от 70, тя ще вземе предвид само първите 64 проби и ще пропусне останалата част.

Винаги се препоръчва размерът на извадката да е 2^n. което може да бъде:

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

Два поплавъка out_r и out_im ще заемат голямо количество памет. за Arduino nano няма да работи за проби по -високи от 128 (а в някои случаи 128) поради липса на налична памет.

беззнакови int данни [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 ++) // изчисляване на нивата {if (data <= a) {o = i;}} int in_ps [data [o] = {}; // вход за последователност float out_r [data [o] = {}; // реална част от преобразуване float out_im [данни [o] = {}; // въображаема част от трансформацията

По -нататъшният поток е както следва:

1. Кодът генерира малко обърнат ред за дадения размер на извадката (подробности за обръщане на бита при препратки: стъпка 2)

2. Въведете данни, подредени според генерираната поръчка, 3. Извършен FFT

4. Амплитудата на комплексното число, изчислена, 5. Пиковете се откриват и подреждат в низходящ ред

6. резултатите могат да бъдат достъпни от f_peaks.

[за достъп до други данни (с изключение на пикова честота) кодът трябва да бъде променен, така че локалната променлива да може да бъде копирана в някоя предварително дефинирана глобална променлива]

Стъпка 5: Тестване на кода

Тестване на кода
Тестване на кода
Тестване на кода
Тестване на кода

Примерна триъгълна вълна е дадена като вход. за тази вълна честотата на вземане на проби е 10 Hz, а самата честота на вълната е 1,25 Hz.

Както може да се покаже от необработената продукция, стойността съвпада с FFT, изчислена от Scilab. тези стойности обаче не са точно същите като ниската точност, но по -бърза синусоида.

В изходната честота честотните масиви са 1,25 и 3,75. не е необходимо всеки път да получавате точната стойност. обикновено тези числа се наричат честотни кутии. така че изходната стойност може да бъде навсякъде в рамките на определени контейнери.

Скорост:

за Arduino nano е необходимо:

16 точки: 4ms32 точки: 10ms 64 точки: 26ms 128 точки: 53ms

Стъпка 6: Заключение

Този FFT код може да се използва в приложения в реално време. Тъй като са необходими около 30 ms, за да завършите изчислението. Резолюцията му обаче е ограничена от редица проби. Броят на извадката е ограничен от паметта на Arduino. Чрез използване на Arduino Mega или друга по -висока производителност точността може да бъде подобрена.

ако имате въпроси, предложения или корекции, не се колебайте да коментирате.

Актуализация (2/5/21)

Актуализации: // ----------------------------- FFT функция --------------- ------------------------------- // плаващ FFT (int в , int N, плаваща честота)

Типът данни от N е променен на Integer (съществуващ байт), за да поддържа> 255 размер на извадката. Ако размерът на извадката е <= 128, трябва да се използва байтов тип данни.

Препоръчано: