Arduino бібліотеки

Щоб використовувати бібліотеку, скачайте ZIP-файл, розпакуйте його, а потім помістіть в папку для бібліотек IDE Arduino.

Бібліотека FFT складається з декількох функцій - для того, щоб користувач міг пристосувати її під власні потреби. Тобто, якщо вам не потрібні якісь фрагменти бібліотеки, їх можна просто видалити.

Всього в бібліотеці сім функцій: дві попередні fft_reorder () і fft_window (). одна головна fft_run () і чотири амплітудні, що відповідають за різні формати вихідних даних: для 16-бітного лінійного, 8-бітного лінійного, 8-бітного логарифмічного і 8-бітного октавного.

Функція fft_run () - головна функція бібліотеки FFT. Їй не потрібні ніякі аргументи, і вона нічого не повертає. Якщо ви запускаєте цю функцію, то передбачається, що потрібні дані вже реорганізовані і знаходяться в SRAM-пам'яті. Ці дані зберігаються в архіві під назвою fft_input []. який містить два 16-бітних значення - дійсне і комплексне. Якщо ви заповнюєте цей масив самостійно, то дійсні значення зберігайте в парні вихідні відліки, а комплексні - непарні.

Таким чином, fft_input [0] - це перше дійсне значення, fft_input [1] - це перше комплексне значення, fft_input [2] - це друге дійсне значення, fft_input [3] - це друге комплексне значення і т.д.

Отже, виходить подвоєння, тому кількість відліків в масиві буде в два рази більше, ніж, власне, реальних ПБФ -отсчетов. Якщо ви використовуєте тільки дійсні числа (тобто значення, отримані від АЦП), то зберігайте їх у парні відліки, а в непарні відліки вписуйте «0».

Результат зберігається в fft_input []. де парні відліки відповідають за дійсні амплітуди, а непарні - за комплексні. Самі відліки є діапазонами частоти (за збільшенням).

Таким чином, fft_input [0] і fft_input [1] - це амплітуда для першого відліку (0hz -> Fs / N), fft_input [2] і fft_input [3] - це амплітуда для другого відліку (Fs / N -> 2Fs / N) і т.д.

Щоб отримати з цих відліків будь-які корисні дані, знадобиться запустити одну з чотирьох амплітудних функцій (про них нижче).

fft_reorder ()

Функція fft_reorder () реорганізовує вхідні дані, готуючи їх до обробки алгоритмом ШПФ. Можливо, це функція не знадобиться, тому що ця реорганізація може бути виконана вручну. Функція fft_reorder () запускається перед fft_run (). Їй не потрібні ніякі аргументи, і вона нічого не повертає. Крім того, перед викликом цієї функції потрібно заповнити масив fft_input []. тому вона бере вихідні дані саме звідти.

fft_window ()

Функція fft_window () примножує вхідні дані за допомогою функції-вікна, щоб збільшити частотне дозвіл даних для ПБФ. Їй не потрібні ніякі аргументи, і вона нічого не повертає. Крім того, перед викликом цієї функції потрібно заповнити масив fft_input []. тому вона бере вихідні дані саме звідти. Функція fft_reorder () запускається перед fft_run () і fft_reorder ().

fft_mag_lin8 ()

Функція fft_mag_lin8 () дає амплітуду для кожного відліку БПФ. Вона підсумовує дійсні і комплексні значення, зведені в квадрат, а потім витягує квадратний корінь, округляючи результат до 8-бітного значення (вона використовує таблицю пошуку, підганяючи ці значення до повного 8-бітного діапазону). Їй не потрібні ніякі аргументи, і вона нічого не повертає. Вихідними даними для неї є дані з масиву fft_input []. а результат зберігається в масив fft_lin_out8 []. після чого ці дані можна використовувати для інших цілей. Амплітуда розраховується тільки для першої половини вихідних відліків (N / 2), оскільки друга половина БПФ ідентична першої для всього діапазону вихідних значень. Отже, кількість 8-бітних значень в масиві fft_lin_out8 [] становитиме N / 2. де кожен індекс буде відповідати номеру вихідного відліку (мінус «1»).

Тобто fft_lin_out8 [0] - це амплітуда для першого відліку (0hz -> Fs / N), fft_lin_out8 [1] - це амплітуда для другого відліку (Fs / N -> 2Fs / N) і т.д.

fft_mag_lin ()

Функція fft_mag_lin () дає амплітуду для кожного відліку БПФ. Вона підсумовує дійсні і комплексні значення, зведені в квадрат, а потім витягує квадратний корінь. Для вилучення квадратного кореня використовується таблиця пошуку, тому точність має деякі обмеження. Функція охоплює повний 16-бітний діапазон, але в будь-якої окремої точці цього діапазону дозвіл все ж із 8-бітовим.

Це 8-бітове значення, де 4 біта відведено під порядок (тобто під експоненту). Вихідними даними для неї є дані з масиву fft_input []. а результат зберігається в масив fft_lin_out []. Підсумкові дані розташовані в послідовному порядку, а їх загальна кількість становить N / 2. оскільки друга половина БПФ ідентична першої для всього діапазону вихідних значень.

fft_mag_log ()

Функція fft_mag_log () дає амплітуду для кожного відліку БПФ. Вона підсумовує дійсні і комплексні значення, зведені в квадрат, потім витягує квадратний корінь. Далі функція розраховує логарифм отриманого числа по відношенню до двох. Результат буде представлений в логарифмічному форматі - фактично, в децибелах. Функції fft_mag_log () не потрібні ніякі аргументи, і вона нічого не повертає.

Для вилучення квадратного кореня використовується таблиця пошуку, а результат підганяється під повний 8-бітний діапазон. Тобто рівняння функції буде наступним: 16 * (log2 ((комплексн2 + действ2) 1/2)). Вихідними даними для функції служать дані з масиву fft_input []. а результат зберігається в масив fft_log_out []. Підсумкові значення мають той же порядок, що і вихідні відліки БПФ. а загальна кількість відліків складає N / 2. оскільки друга половина БПФ ідентична першої для всього діапазону вихідних значень.

fft_mag_octave ()

Функція fft_mag_octave () дає середнє квадратичне значення всіх вихідних відліків, представляючи це все в октавному (подвоєння частоти) форматі. Цей формат, як правило, більш корисний, тому що близький до того, як люди сприймають звук. Їй не потрібні ніякі аргументи, і вона нічого не повертає. Вихідними даними для функції служать дані з масиву fft_input []. а результат зберігається в масив fft_oct_out []. Підсумкові дані представляють собою 8-бітове значення, розраховане за формулою 16 * log2 (квадр (Ампл)). Кількість вихідних відліків розраховується наступним чином:

Тут, наприклад, 5: 8 - це сума всіх відліків, розташованих з 5-го по 8-ий. Дані в кожному відліку зводяться в квадрат (і дійсні, і комплексні значення), а потім сумуються з усіма амплітудами (теж зведеними в квадрат), що знаходяться в цьому діапазоні. Потім береться кількість вихідних відліків і ділиться на отримане число (це, втім, можна відключити - дивіться наступний розділ) після чого витягується квадратний корінь і розраховується логарифм.

Хочете «заглянути під капот». Окей, спробую пояснити, за якими принципами це все працює. За прискорення обчислень в бібліотеці FFT відповідають дві речі.

По-перше, в кожному БПФ вам потрібно множити безліч вихідних значень на синусні і косинусні константи. На ATmega це вимагає великих обчислювальних ресурсів, оскільки множення 16 біт на 16 біт вимагає 18 тактових циклів. З іншого боку, додавання 16 біт і 16 біт вимагає тільки 2 тактових циклу. Звідси висновок, що краще складати, ніж множити. Справа в тому, що синусні і косинусні константи, що використовуються в БПФ - це просто «0» і «1». тому вам не обов'язково використовувати операцію множення, тому що досить і складання. Наприклад, якщо БПФ має 256 вихідних відліків. то в ньому потрібно виконати 1 024 складних множення, з яких 382 - це «0» або «1». Майже половина!

Бібліотека FFT для Arduino шукає умови, де використовуються ці «0» і «1». і просто робить там додавання. Справа в тому, що ці константи з'являються з регулярними інтервалами, тому шукати їх досить просто. Втім, зі збільшенням кількості вихідних відліків переваги цього методу знижуються. Якщо за кількість вихідних відліків в БПФ уявити N. то економія часу буде становити (1.5 * N - 2), а загальною кількістю множень буде (N / 2) * log2 (N). Таким чином, формулою, за якою розраховуються економія, буде 3 / log2 (N). і чим вище N. тим менше часу можна заощадити.

Другий метод, спрямований на прискорення роботи БПФ - це таблиці пошуку, за допомогою яких розраховуються квадратні корені амплітуд. Складність цього методу в тому, що вихідні дані набагато більше, ніж вміст таблиці пошуку. Таким чином, щоб не витрачати даремно програмну пам'ять, вихідні дані потрібно стиснути. Наприклад, якщо витягти квадратний корінь з 16-бітного значення. ми отримаємо 64 тисячі вхідних значень. які потрібно якось підігнати до 256 вихідним значенням. У програмній пам'яті Arduino неможливо провести такий обсяг обчислень, тому в бібліотеці до всього масиву вхідних даних застосовується лінійна інтерполяція, в результаті якої для різних ділянок будуть розраховані різні лінії. Наприклад, для лінійного 8-бітного формату буде досить 3-4 лінійних секцій. причому без втрати дозволу.

Таким чином, бібліотека обчислює дійсне значення однієї з цих лінійних секцій, потім витягує квадратний корінь, і це займає приблизно 12 тактових циклів. Це набагато менше тих 150 циклів. які потрібні в стандартній бібліотеці для добування квадратного кореня.

Версія з 32-бітними вхідними даними трохи складніше, тому що тепер вихідні дані потрібно підігнати до 16 бітам. а лінійна інтерполяція тут не допоможе, тому що не вміє стискати значення, вирішення яких більше 16 біт. Тому тут застосовується гібридний підхід, при якому вхідний значення конвертується в 16-бітове значення з 8-бітовим порядком. Це можна зробити дуже швидко з підставою «2». що дозволяє використовувати таблицю пошуку квадратного кореня і для значень з дозволом вище 16 біт. Якщо при стисненні вхідного значення виконаний зрушення на 2 біти вправо. то вихідне значення може бути реконструйовано із зсувом на 1 біт вліво. Як правило, після створення порядок (тобто експоненту) округлюють до парного числа, в результаті чого квадратний корінь може повернути цілочисельне значення.

Зрозуміло, 32-бітна версія не зовсім точний, як бібліотека для обчислення квадратного кореня, але вимагає всього 40 циклів. тоді як ця бібліотека вимагає 500. Таблиця пошуку повертає значення, де точними є тільки перші 8 біт. але для цього БПФ такої точності цілком достатньо. Загальна бітова глибина БПФ не сильно поступається 12 бітам. оскільки в ньому використовується фіксована точка (щоб уникнути переповнення перед складанням кожне значення має бути поділено на 2; якщо БПФ має 256 вихідних відліків. це врешті-решт дає поділ на 256). Точність залежить від дозволу вихідних даних. Якщо це 8-бітове значення. то точність буде максимальною. Якщо це 9-бітове значення. то один молодший біт, можливо, буде неправильним. Якщо це 10-бітове значення. то два молодших біта, можливо, будуть неправильними і т.д. Тобто найгірший сценарій - це 16-бітове значення з точністю +/- 0,5%.

Ці значення дозволяють вам модифікувати код FFT під власні потреби. Більшість з них включають і вимикають певні функції бібліотеки. За замовчуванням більшість функцій вимкнені, тому щоб використовувати, їх потрібно спочатку включити. Ці директиви вписуються за допомогою конструкції #define і робити це потрібно перед підключенням бібліотек, що робиться конструкцією #include.

  • Директива FFT_N задає розмір БПФ. Можливі варіанти: 16. 32. 64. 128 і 256. За замовчуванням виставлений варіант 256.
  • Директива SCALE відповідає за масштабування в функції fft_mag_lin8 (). Оскільки 8 біт - це досить слабке дозвіл, користувач, можливо, захоче масштабувати дані, щоб максимізувати їх до повного діапазону.
  • Директива SCALE примножує вихідні дані на константу перед витяганням квадратного кореня, в результаті чого на виході виходить максимізувати дозвіл. Це зажадає трохи більше ресурсів, ніж зазвичай, але зайвий витрата буде дуже невеликий. У директиві SCALE можна вказати будь-яке число в діапазоні від 1 до 255. За замовчуванням виставлено 1. Найменша кількість ресурсів витрачається при використанні 1. 2. 4. 128 і 256.
  • Директива WINDOW вмикає і вимикає функцію-вікно. Якщо ви не використовуєте fft_window (). то потрібно вписати WINDOW 0 (викл). За замовчуванням варто WINDOW 1 (вкл).
  • Директива REORDER вмикає і вимикає функцію реорганізації. Якщо ви не використовуєте fft_reorder (). то потрібно вписати REORDER 0 (викл). За замовчуванням варто REORDER 1 (вкл).
  • Директива LOG_OUT вмикає і вимикає функцію для логарифмічного формату. Якщо ви використовуєте fft_mag_log (). то потрібно вписати LOG_OUT 1 (вкл). За замовчуванням варто LOG_OUT 0 (викл).
  • Директива LIN_OUT вмикає і вимикає функцію для лінійного (16 біт) формату. Якщо ви використовуєте fft_mag_lin (). то потрібно вписати LIN_OUT 1 (вкл). За замовчуванням варто LIN_OUT 0 (викл).
  • Директива LIN_OUT8 вмикає і вимикає функцію для лінійного (8 біт) формату. Якщо ви використовуєте fft_mag_lin8 (). то потрібно вписати LIN_OUT8 1 (вкл). За замовчуванням варто LIN_OUT8 0 (викл).
  • Директива OCTAVE вмикає і вимикає функцію для октавного формату. Якщо ви використовуєте fft_mag_octave (). то потрібно вписати OCTAVE 1 (вкл). За замовчуванням варто OCTAVE 0 (викл).
  • Директива OCT_NORM вмикає і вимикає у октавного формату функцію нормалізації. Вона є частиною функції fft_mag_octave (). яка ділить кожен згрупований відлік на середня кількість відліків. Оскільки багато джерел звуку видають так званий «рожевий шум» (це падіння амплітуди при збільшенні частоти), це призводить і до зменшення масштабу. Будучи виключеною (OCT_NORM 0), ця директива штучно підвищує амплітуду на високих частотах. За замовчуванням нормалізація включена (OCT_NORM 1).
  • fft adc - Застосування БПФ на даних від АЦП і відправка результату за допомогою write ()
  • fft adc serial - Застосування БПФ на даних від АЦП і відправка результату за допомогою println ()
  • fft codec - Застосування БПФ на даних від модуля Codec Shield

Схожі статті