Оглавление:

EasyFFT: быстрое преобразование Фурье (БПФ) для Arduino: 6 шагов
EasyFFT: быстрое преобразование Фурье (БПФ) для Arduino: 6 шагов

Видео: EasyFFT: быстрое преобразование Фурье (БПФ) для Arduino: 6 шагов

Видео: EasyFFT: быстрое преобразование Фурье (БПФ) для Arduino: 6 шагов
Видео: Основы ЦОС: 18. Преобразование Фурье (ссылки на скачивание скриптов в описании) 2024, Ноябрь
Anonim
Image
Image

Измерение частоты по захваченному сигналу может быть сложной задачей, особенно для Arduino, поскольку он имеет меньшую вычислительную мощность. Существуют методы, позволяющие зафиксировать переход через нуль, при котором частота фиксируется путем проверки того, сколько раз сигнал пересекает нулевую линию за заданное время. Такой метод может не работать, если сигнал представляет собой комбинацию различных частот.

Это как-то сложно закодировать, если у вас нет такого опыта. Но будучи мастером, этот код может быть очень полезен для различных проектов, связанных с музыкой, анализом сигналов. Мотив этого проекта состоял в том, чтобы подготовить код, который легко реализовать на Arduino, не вдаваясь в его предысторию.

Этот проект не объясняет работу БПФ, но объясняет применение функции БПФ. Тот же процесс также объясняется в прилагаемом видео.

Если вас интересует только применение кода, а не его объяснение. Вы можете сразу перейти к шагу 3.

Шаг 1. Введение в преобразование частоты

Введение в преобразование частоты
Введение в преобразование частоты
Введение в преобразование частоты
Введение в преобразование частоты

Любой сигнал может состоять из комбинации различных синусоидальных волн. Таким образом, любой сигнал, основанный на времени, также может быть показан как комбинация различных синусов разной амплитуды.

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

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

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

Таким образом, если наш сигнал умножается на f1, сумма умножения будет равна нулю (близка к нулю для реального приложения). Аналогично обстоит дело с f3, f4. Однако для значения выходные значения f2 и f5 не будут равны нулю, а будут значительно выше остальных значений.

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

Шаг 2: быстрое преобразование Фурье

Чтобы сделать вычисления ДПФ более быстрыми, Джеймс Кули и Джон Тьюки разработали алгоритм БПФ. Этот алгоритм также считается одним из важнейших алгоритмов 20 века. Он разделяет сигнал на нечетную и четную упорядоченную часть, что сокращает количество требуемых вычислений. С его помощью общее требуемое комплексное умножение может быть уменьшено до NlogN. что является значительным улучшением.

Вы можете обратиться к нижеприведенным ссылкам, на которые я ссылался при написании кода, для подробного понимания математики, лежащей в основе БПФ:

1.

2.

3.

4.

Шаг 3: объяснение кода

1. Быстрый синус и косинус:

Расчет БПФ принимает значения различных синусов и косинусов несколько раз. Встроенная функция Arduino работает недостаточно быстро и требует много времени, чтобы обеспечить необходимое значение. Что делает код значительно медленнее (удваивает время для 64 образцов). Чтобы решить эту проблему, значение синуса от 0 до 90 градусов сохраняется как кратное 255. Это избавит от необходимости хранить числа в виде числа с плавающей запятой, и мы можем сохранить его как байт, который занимает 1/4 пространство на Arduino. Sine_data необходимо вставить в начало кода, чтобы объявить его как глобальную переменную.

Помимо sine_data, массив с именем f_peaks объявлен как глобальная переменная. После каждого запуска функции БПФ этот массив обновляется. Где 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: Объяснение кода: функция БПФ

БПФ может выполняться только для размера выборки 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; а = 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 [data [o] = {}; // воображаемая часть преобразования

Дальнейший поток выглядит следующим образом:

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

2. Введите данные, упорядоченные в соответствии с созданным заказом, 3. Выполнено БПФ.

4. Рассчитанная амплитуда комплексного числа, 5. Пики обнаруживаются и упорядочиваются в порядке убывания.

6. Результаты можно получить из f_peaks.

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

Шаг 5: Тестирование кода

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

В качестве входных данных используется образец треугольной волны. для этой волны частота дискретизации составляет 10 Гц, а частота самой волны составляет 1,25 Гц.

Как видно из необработанных выходных данных, значение совпадает с БПФ, вычисленным Scilab. однако эти значения не совсем такие же, как у нас с низкой точностью, но с более быстрой синусоидой.

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

Скорость:

для Arduino nano требуется:

16 точек: 4 мс 32 точки: 10 мс 64 точки: 26 мс 128 точек: 53 мс

Шаг 6: Заключение

Этот код БПФ можно использовать в приложениях реального времени. Поскольку для завершения расчета требуется около 30 мс. Однако его разрешение ограничено рядом образцов. Количество сэмплов ограничено памятью Arduino. Используя Arduino Mega или другую плату с более высокой производительностью, можно повысить точность.

если у вас есть какие-либо вопросы, предложения или исправления, не стесняйтесь комментировать.

Обновление (05.02.21)

Обновления: // ----------------------------- Функция БПФ --------------- ------------------------------- // БПФ с плавающей запятой (int in , int N, float Frequency)

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

Рекомендуемые: