|
Оптимизация дискретного преобразования Фурье, Как уменьшить время вычисления ДПФ? |
|
|
|
Sep 26 2016, 11:25
|
Группа: Участник
Сообщений: 5
Регистрация: 28-11-15
Пользователь №: 89 496

|
Всем доброго времени суток! Для реализации распознавания отдельных слов потребовалось вычисление дискретного преобразования Фурье. Быстрое преобразование применить нельзя, поскольку число отсчётов не является степенью двойки (в противном случае ухудшаются результаты работы основного алгоритма). Восстановление сигнала после преобразования не требуется, всё, что нужно от ДПФ - амплитуда и частота. Сейчас вычисляю ДПФ формулами по определению (формулы ниже, плюс ещё вычисление амплитуды). При обработке одного слова требуется выполнить 30 преобразований Фурье. Число отсчётов лежит в пределах 200 - 500 (конкретное значение заранее неизвестно), но одинаковое для всех тридцати преобразований.  В результате при реализации такого алгоритма на stm32f417 при частоте 168 МГц и арифметике с 32-битными float эти 30 преобразований (анализ одного произнесённого слова) вычисляются четыре-пять секунд, что составляет большую часть времени всех вычислений (80%). Для вычисления коэффициентов ДПФ и квадратных корней использую функции DSP-ядра этого микроконтроллера (синус, косинус, квадратный корень). И большую часть времени (68%) занимает как раз вычисление этих самых коэффициентов. Как ещё можно ускорить вычисление ДПФ?
|
|
|
|
|
Sep 26 2016, 11:34
|
Местный
  
Группа: Участник
Сообщений: 453
Регистрация: 23-07-08
Пользователь №: 39 163

|
Цитата(Olegas @ Sep 26 2016, 14:25)  В результате при реализации такого алгоритма на stm32f417 при частоте 168 МГц и арифметике с 32-битными float эти 30 преобразований (анализ одного произнесённого слова) вычисляются четыре-пять секунд, что составляет большую часть времени всех вычислений (80%).
Для вычисления коэффициентов ДПФ и квадратных корней использую функции DSP-ядра этого микроконтроллера (синус, косинус, квадратный корень). И большую часть времени (68%) занимает как раз вычисление этих самых коэффициентов.
Как ещё можно ускорить вычисление ДПФ? Для вычисления sin и cos можно использовать тот же подход, что используется в DDFS - небольшая таблица для фаз (pi/2/N, N - размер таблицы) + линейная аппроксимация между отсчетами из таблицы.
|
|
|
|
|
Sep 26 2016, 13:49
|
Гуру
     
Группа: Свой
Сообщений: 2 563
Регистрация: 8-04-05
Из: Nsk
Пользователь №: 3 954

|
FFT требует ~100 тактов на отсчёт, соответственно не жалко потратить ещё десяток тактов на отсчёт и сделать resampling, чтобы точек было всегда 512, ну или хотя бы просто нулями буфер дозабить по длине до 512 точек. соответственно для 30 FFT * 512 точек * 100 тактов надо 1.5-2МГц, или 10мс при 168МГц. если же надо именно ДПФ только для определённых частот, а для не всего спектра, можно Герцелем посчитать, почти без вычисления тригонометрии (там надо только один раз косинус посчитать для каждой частоты, а не для каждого отсчёта). будет несколько тысяч тактов на отсчёт, но если надо только несколько частот, а не весь спектр, может быть быстрее чем через FFT Код float SpecPowerGoertzel(float * y, int num, float dt, float w){ const float K = 2.0 * cos(w * dt / num); float s1 = 0, s2 = 0; for (int i = 0; i < num; i++){ float s0 = y[i] + K * s1 - s2; s2 = s1; s1 = s0; } return (s2*s2 + s1*s1 - K * s1 * s2) / ((float)num * num); } только корень еще навеное взять надо и почему оно на длину выборки делилось, причём дважды, уже не вспомню.
|
|
|
|
|
Sep 27 2016, 06:29
|
Группа: Участник
Сообщений: 5
Регистрация: 28-11-15
Пользователь №: 89 496

|
Дело в том, что для распознавания необходим весь спектр, поэтому алгоритм Гёрцеля не подходит. По поводу изменения частоты дискретизации. Для сравнения результатов в MATLAB построено два спектра: – первый (чёрный) – исходный вариант, ДПФ на 348 точки; – второй (красный) – после передискретизации, БПФ на 512 точек. Графики построены в координатах частота – амплитуда.   Вот из-за такой разницы алгоритм распознавания ухудшается (значительно увеличивается расстояние даже между одинаковыми словами (примерно в три раза)). Если возможно, применялось бы БПФ. Вот пример кода из MATLAB: Код y = audioread('1.wav'); N = length(y); T = 30; %Число кадров K = ceil(2*N/(T+1)); %Число отсчётов в кадре Fs = 8000; %Частота дискретизации
%Желаемые параметры сигнала Kwant = 512; Nwant = Kwant/2 * (T+1); %Длина всего сигнала, чтобы число отсчётов в кадре было 512 Fswant= Nwant/N * Fs;
%Интерполируем Y = interp1(1:N, y, 1:N/Nwant:N, 'linear');
frame1 = y(1:K); fft_frame1 = abs(fft(frame1));
frame1Y = Y(1:Kwant); fft_frame1Y = abs(fft(frame1Y));
fky = 1:Fs/K:Fs; fkY = 1:Fswant/Kwant:Fswant;
fft_frame1y = zeros(size(frame1Y)); fft_frame1y(1:K) = fft_frame1;
plot(fkY, fft_frame1Y,'r', fkY,fft_frame1y,'k'); xlabel 'частота, Гц'
|
|
|
|
|
Sep 27 2016, 07:24
|
Группа: Участник
Сообщений: 5
Регистрация: 28-11-15
Пользователь №: 89 496

|
То, что частоты сдвинуты - не страшно. Гораздо хуже, что амплитуды для двух вариантов для частот 0..4000 Гц не совпадают.
|
|
|
|
|
Sep 27 2016, 12:02
|
Знающий
   
Группа: Свой
Сообщений: 608
Регистрация: 10-07-09
Из: Дубна, Московская область
Пользователь №: 51 111

|
Цитата(Olegas @ Sep 27 2016, 10:24)  То, что частоты сдвинуты - не страшно. Гораздо хуже, что амплитуды для двух вариантов для частот 0..4000 Гц не совпадают. Взял примерные значения пиков в районе 1 кГц, 11,5 и 16,8. Их отношение 512(Гц)*11,5/16,8~=350(Гц). Думаю у Вас более точные значения амплитуд еще больше совпадут с отношением частот дискретизации. Учитывая имеющийся доступ к оригиналу - можете для всех точек пересчитать. Еще лучше - возьмите максимальные значения в каждой реализации и относительно него пронормируйте полученные данные.
|
|
|
|
|
Sep 27 2016, 19:35
|
Группа: Участник
Сообщений: 5
Регистрация: 28-11-15
Пользователь №: 89 496

|
Цитата(Александр77 @ Sep 27 2016, 15:02)  Еще лучше - возьмите максимальные значения в каждой реализации и относительно него пронормируйте полученные данные. Это хорошая идея, если коэффициент нормировки будет константой для всех вариантов. Ну или хотя бы зависеть только от исходного числа отсчётов (которое не есть степень двойки) и желаемого (степень двойки, например 512). И вот подопытный файл для всех желающих.
Сообщение отредактировал Olegas - Sep 27 2016, 19:35
Прикрепленные файлы
1.wav ( 10.55 килобайт )
Кол-во скачиваний: 15
|
|
|
|
|
Sep 28 2016, 08:01
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Olegas @ Sep 26 2016, 11:25)  Для вычисления коэффициентов ДПФ и квадратных корней использую функции DSP-ядра этого микроконтроллера (синус, косинус, квадратный корень). И большую часть времени (68%) занимает как раз вычисление этих самых коэффициентов. Как ещё можно ускорить вычисление ДПФ? Ну так, заранее вычислите эти коэффициенты и разместите их в таблице. У меня на 100 МГц ДСП двойной МАК для преобразования Фурье вычисляется за 10 нс. Т.о., для 200-500 точек время счёта Re/Im одной палки составит порядка 2-5 мкс. Для 30 частот время счета составит 60-150 мкс. Но это прикид для 100 МГц тактовой, а у вас 168 МГц тактовая, так что о каких секундах может идти речь?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|