Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Фурье с учетом предыдущих отсчетов
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Математика и Физика
alexPec
Добрый день всем! Необходимо было вычислять преобразование фурье, зная предыдущие отсчеты во временной и частотной областях. То есть поступает новый отсчет в буфер на 1024 элемента, последний отсчет выходит. Вычисляем разницу между входящим и выходящим, пересчитываем фазы. Вот код:
Код
// Функция вычисления Фурье-преобразования последовательности {X1, X2,...,Xn} через заранее известное // Фурье последовательности {X0,X1,...,Xn-1}
// Re_prev, Im_prev   ---  действительная и мнимая части  Фурье предыдущего такта
// delta1 = (Re(Xn)-Re(X0)), delta2 = (Im(Xn)-Im(X0)), где Xn - следующий за последним, а X0 - начальный отсчеты предыдущего такта

void fourierShiftReduced( double *Re, double *Im, double delta ) {
        // вычитание спектра дельта-импульса
        for( int k = 0; k < fourierLength/2; k++ )
          Re[k] += delta1;
      Im[k] += delta2;

        // сдвиг спектра на 1/N
        double shift = 2 * PI / fourierLength;

        for( int k = 0; k < fourierLength/2; k++ )
        {
          phaseShift( Re[k], Im[k], shift * k );
        }
}

void phaseShift( double &re, double &im, double shift) {
        double a = cos( shift );
        double b = sin( shift );
        double x = a * re - b * im;
        im = b * re + a * im;
        re = x;
}


Проблема: когда используем арифметику с плавающей точкой, даже single, через 50х1024 входных отсчетов картина модуля спектра (fft_float). Когда все переводим на фиксированную точку, и именно синус, косинус умножаем на 65535 (получаем оцифровку 17 бит) и оставляем только целую часть, входной сигнал оцифровываем до 14 бит, то после 1024 отсчетов картина еще нормальная (fft_1), а через те же 50x1024 отсчета получаем это (fft_int). По ходу вычислений гармоники плывут какие-то вверх, какие-то вниз. С плавающей точкой движения никакого не наблюдается вообще. Похоже что по ходу в буфере накапливается ошибка округления - и результат нехороший. Пробовал синус, косинус оцифровывать до 19 бит - чуть медленее плывут.
Вопрос: можно ли в принципе реализовать таку схему с целочисленной арифметикой, или никак?
AndeyP
может помочь
- округление: вместо (x * y) >> 15 попробовать (x * y + 0х4000) >> 15
- повышение точности данных (например использовать умножения 32х16 вместо 16х16)

Еще можно попробовать не поворачивать спектр, чтобы избежать накопления ошибок при поворотах. Т.е. поворачивать вход (дельту) и выход, при выдаче результата, но это конечно удвоит вычисления.
alex_os
Цитата(alexPec @ Sep 1 2010, 09:56) *
...
Вопрос: можно ли в принципе реализовать таку схему с целочисленной арифметикой, или никак?


Можно попробовать сделать так, чтобы старые данные (и ошибка с ними вместе) "забывались".
т.е.
Код
      
          Re[k] += delta1;
      Im[k] += delta2;

заменить на
Код
      
          Re[k] = Re[k]  *аlpha + delta1;
      Im[k] = Im[k] *аlpha + delta2;

где alpha - число близкое к 1, но меньшее 1, например 0.9999.

Конечно это будет не совсем честное фурье, а что-то вроде фурье от сигнала на который наложено экспоненциальное окно
w = alpha^n , n=0...1023.
alexPec
Цитата
- округление: вместо (x * y) >> 15 попробовать (x * y + 0х4000) >> 15


Пробовал, не помогает...


Цитата
Можно попробовать сделать так, чтобы старые данные (и ошибка с ними вместе) "забывались".
т.е.
Код
      
          Re[k] += delta1;
      Im[k] += delta2;

заменить на
Код
      
          Re[k] = Re[k]  *аlpha + delta1;
      Im[k] = Im[k] *аlpha + delta2;

где alpha - число близкое к 1, но меньшее 1, например 0.9999.

Конечно это будет не совсем честное фурье, а что-то вроде фурье от сигнала на который наложено экспоненциальное окно
w = alpha^n , n=0...1023.


А я пробовал делать так: до умножения синус чтоб перевести в целочисленный вид умножал на 65535, а после умножения делил уже на 65536. Если это одно и то же - то тоже не помогает.

Я тут думаю что вся прелесть флоат-вычислений по сравнению с интеджер в том что динамический диапазон у флоат выше при одной и той же точности мантиссы. А у интеджера получается что чем меньше число, тем меньше точность. Похоже не победить это. Но если ошибся - посоветуйте что-нибудь. Спасибо !!!
alex_os
Цитата(alexPec @ Sep 4 2010, 19:09) *
Пробовал, не помогает...




А я пробовал делать так: до умножения синус чтоб перевести в целочисленный вид умножал на 65535, а после умножения делил уже на 65536. Если это одно и то же - то тоже не помогает.

Я тут думаю что вся прелесть флоат-вычислений по сравнению с интеджер в том что динамический диапазон у флоат выше при одной и той же точности мантиссы. А у интеджера получается что чем меньше число, тем меньше точность. Похоже не победить это. Но если ошибся - посоветуйте что-нибудь. Спасибо !!!


А какая разрядность массива в котором результат ффт аккумулируется ? Может ее увеличить раза в 2 (правда и умножителей вдвое больше потребуется) ? Вообще этот алгоритм ни что иное как набор рекурсивных фильтров 1го порядка, все должно в fixed point работать. Может быть уменьшить величину аlpha ?



alexPec
Цитата(alex_os @ Sep 4 2010, 22:33) *
А какая разрядность массива в котором результат ффт аккумулируется ? Может ее увеличить раза в 2 (правда и умножителей вдвое больше потребуется) ? Вообще этот алгоритм ни что иное как набор рекурсивных фильтров 1го порядка, все должно в fixed point работать. Может быть уменьшить величину аlpha ?

Разрядность результата 18 бит. В два раза увеличивать уже нельзя - ресурсов не хватает. Уменьшал альфу, потихоньку ВСЕ гармоники убывают. Пробовал при малой альфе подать на вход отсчеты синуса - получается так: и шум, и основная гармоника уходят до нуля плавно, но как только меняешь частоту синуса - палка синуса на новой частоте начинает расти, а на старой частоте (если дождаться когда на старой частоте палка до нуля упадет) резко появляется палка и плавно (по скорости одинаково с шумом) убывает. Такая вот загадочная штука... А с синусом/косинусом *65535/65536 это ведь эквивалентно той самой альфе?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.