The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

Фильтрация с помощью БПФ

Фильтрация с помощью БПФ

Предыдущая  Содержание  Следующая  V*D*V

Фильтрация с помощью КИХ фильтра подразумевает выполнение для каждого нового отсчёта звукового сигнала двух операций: сдвиг значений в буфере линии задержки и умножение коэффициентов фильтра на значения, находящиеся в буфере.

При увеличении порядка фильтра (увеличении длины линии задержки) число умножений растёт.

Когда порядок фильтра превышает 50, становится выгоднее использовать расчёт отклика фильтра не прямым способом, а через умножение спектров в частотной области с последующим обратным БПФ.

Известны 2 метода секционированной свёртки: метод перекрытия с накоплением и метод перекрытия с суммированием.

Выходной буфер имеет размер (длина БПФ - (длина импульсной характеристики фильтра -1)).

 

С помощью данных методов можно обрабатывать сразу 2 канала. Для этого потребуется использовать комплексное БПФ.

Для этого буфер для импульсной характеристики длиной L должен иметь в 2 раза больший размер. Отбрасываться будут (L - 1) отсчётов для каждого канала, то есть всего (L - 1) * 2 отсчётов.

 

Буфер для импульсной характеристики перед комплексным БПФ

i[0], 0, i[1], 0, i[2], 0, ..., i[imp.length - 1], 0, 0, 0 ...

 

Буфер, содержащий входные данные, готовится в виде:

l[0], r[0], l[1], r[1], ..., l[n - 1], r[n - 1]

 

Выходной буфер комплексного БПФ будет иметь размер (1 << power) - 2 * (L - 1).

Выходные данные в нём расположены так же, как и во входной буфере:

l[0], r[0], l[1], r[1], ..., l[(1 << power) - 2 * (L - 1) - 1], r[(1 << power) - N * (L - 1) - 1]

 

Расчёт импульсной характеристики фильтра можно использовать из раздела КИХ фильтры.

Естественно, можно использовать и АЧХ фильтра.

Реализация метода перекрытия с накоплением

/**

* фильтрация с помощью БПФ

* алгоритм взят из

* Романюк Ю.А. Основы цифровой обработки сигналов.

* 5.4 Секционированная свёртка, Метод перекрытия с накоплением.

*/

public class FFTfilter1 {

 /**

  * импульсная характеристика после преобразования в частотную область

  */

 private double[] m_response;

 /**

  * буфер для накопления нужного числа входных данных

  */

 private short[] m_buffer;

 /**

  * указатель для сохранения входных данных в буфер

  */

 private int m_s;

 /**

  * размер буфера, степень числа 2

  */

 private byte m_power;

 /**

  * длина импульсной характеристики фильтра - 1

  */

 private int m_imp_length1;

 //

 public FFTfilter1() {}

/**

* инициализация параметров

* @param imp - импульсная характеристика фильтра

*/

 public void init(double[] imp) {

         // преобразуем импульсную характеристику в частотную область

         // подбираем размер буфера для свёртки.

         // (L - 1) отсчётов будут отбрасываться,

         // длину буфера выбираем минимум 32768.

         int i;

         m_power = 0;

         for( i = 1; i < imp.length; m_power++ ) i = i << 1;

         // если степень меньше 15, возрастают искажения

         if( ++m_power < 15 ) m_power = 15;

         // создаём буфер для преобразования и дополняем его нулями

         m_response = new double[1 << m_power];// уже обнулён

         for( i = 0; i < imp.length; i++ ) m_response[i] = imp[i];

         //for( ; i < (1 << m_power); i++ ) m_response[i] = 0.0;

         // переводим в частотную область

         FFT.realFastFourierTransform( m_response, m_power, false );

         // вспомогательный буфер для хранения входных данных

         m_buffer = new short[1 << m_power];

         m_imp_length1 = imp.length - 1;

         m_s = m_imp_length1;// компенсируем начальное смещение влево

         // обнуляем кусок буфера, в java он уже обнулён

         //for( i = 0; i < m_s; i++ ) m_buffer[i] = 0;

 }

/**

* фильтрация

* выходной сигнал имеет задержку на L/2 сэмплов

* @param sample - отсчёт звука

* @return результат фильтрации, если не null

*/

 public short[] proc(short sample) {

         m_buffer[m_s++] = sample;

         if( m_s < m_buffer.length )

                 return null;

         // переносим данные во временный буфер

         double[] buf = new double[m_buffer.length];

         for( int i = 0; i < m_buffer.length; i++ )

                 buf[i] = (double)m_buffer[i];

         // сохраняем последние (L - 1) значений для следующего преобразования

         for( int i = m_buffer.length - m_imp_length1, m = 0; i < m_buffer.length; i++ )

                 m_buffer[m++] = m_buffer[i];

         m_s = m_imp_length1;

         // выполняем БПФ

         FFT.realFastFourierTransform( buf, m_power, false );

         // перемножаем частотные характеристики

         /* постоянная составляющая

         buf[0] = buf[0] * m_response[0];

         buf[1] = buf[1] * m_response[1];

         for( int m = 2; m < buf.length; m += 2 )

         */

         for( int m = 0; m < buf.length; m += 2 ) {

                 // от способа перемножения зависит,

                 // какая часть данных будет отбрасываться

                 double a = buf[m];

                 double b = buf[m + 1];

                 // вариант для отбрасывания последних (L-1) отсчётов

                 buf[m]     = a * m_response[m] + b * m_response[m + 1];

                 buf[m + 1] = b * m_response[m] - a * m_response[m + 1];

                 /* вариант для отбрасывания первых (L-1) отсчётов

                 buf[m]     = a * m_response[m] - b * m_response[m + 1];

                 buf[m + 1] = b * m_response[m] + a * m_response[m + 1];

                 */

         }

         // преобразуем обратно во временную область

         FFT.realFastFourierTransform( buf, m_power, true );

         // переписываем часть данных в выходной буфер

         short[] out = new short[m_buffer.length - m_imp_length1];

         // отбрасываем последние (L-1) отсчётов

         for( int i = 0; i < out.length; i++ ) {

                 if( buf[i] > 32767 ) out[i] = 32767;

                 else if( buf[i] < -32768 ) out[i] = -32768;

                 else out[i] = (short)buf[i];

         }

         /* или отбрасываем первые (L-1) отсчётов

         for( int i = 0; i < out.length; i++ ) {

                 if( buf[i + m_imp_length1] > 32767 ) out[i] = 32767;

                 else if( buf[i + m_imp_length1] < -32768 ) out[i] = -32768;

                 else out[i] = (short)buf[i + m_imp_length1];

         }

         */

         return out;

 }

}

 

Реализация метода перекрытия с суммированием

/**

* фильтрация с помощью БПФ

* алгоритм взят из

* Романюк Ю.А. Основы цифровой обработки сигналов.

* 5.4 Секционированная свёртка, Метод перекрытия с суммированием.

*/

public class FFTfilter2 {

 /**

  * импульсная характеристика после преобразования в частотную область

  */

 private double[] m_response;

 /**

  * буфер для накопления нужного числа входных данных

  */

 private short[] m_buffer;

 /**

  * указатель для сохранения входных данных в буфер

  */

 private int m_s;

 /**

  * размер буфера, степень числа 2

  */

 private byte m_power;

 /**

  * длина импульсной характеристики фильтра - 1

  */

 private int m_imp_length1;

 /**

  * буфер для хранения выходных данных для последующего суммирования

  */

 private double[] m_out;

 //

 public FFTfilter2() {}

/**

* инициализация параметров

* @param imp - импульсная характеристика фильтра

*/

 public void init(double[] imp) {

         // преобразуем импульсную характеристику в частотную область

         // подбираем размер буфера для свёртки.

         // (L - 1) отсчётов будут использоваться для суммирования,

         // длину буфера выбираем минимум 32768.

         int i;

         m_power = 0;

         for( i = 1; i < imp.length; m_power++ ) i = i << 1;

         // если степень меньше 15, возрастают искажения

         if( ++m_power < 15 ) m_power = 15;

         // создаём буфер для преобразования и дополняем его нулями

         m_response = new double[1 << m_power];// уже обнулён

         for( i = 0; i < imp.length; i++ ) m_response[i] = imp[i];

         //for( ; i < (1 << m_power); i++ ) m_response[i] = 0.0;

         // переводим в частотную область

         FFT.realFastFourierTransform( m_response, m_power, false );

         // вспомогательный буфер для хранения входных данных

         m_imp_length1 = imp.length - 1;

         m_buffer = new short[(1 << m_power) - m_imp_length1];

         m_s = 0;

         m_out = new double[m_imp_length1];// заполнен нулями

 }

/**

* фильтрация

* выходной сигнал имеет задержку,

* зависящую от длины импульсной характеристики фильтра

* @param sample - отсчёт звука

* @return результат фильтрации, если не null

*/

 public short[] proc(short sample) {

         m_buffer[m_s++] = sample;

         if( m_s < m_buffer.length )

                 return null;

         m_s = 0;

         // переносим данные во временный буфер

         double[] buf = new double[1 << m_power];

         int i = 0;

         do{ buf[i] = (double)m_buffer[i]; } while( ++i < m_buffer.length );

         // обнуляем последние (L-1) значений

         do{ buf[i] = 0; } while( ++i < buf.length );// в java это не требуется

         // выполняем БПФ

         FFT.realFastFourierTransform( buf, m_power, false );

         // перемножаем частотные характеристики

         /* постоянная составляющая

         buf[0] = buf[0] * m_response[0];

         buf[1] = buf[1] * m_response[1];

         for( i = 2; i < buf.length; i += 2 )

         */

         for( i = 0; i < buf.length; i += 2 ) {

                 double a = buf[i];

                 double b = buf[i + 1];

                 buf[i]     = a * m_response[i] - b * m_response[i + 1];

                 buf[i + 1] = a * m_response[i + 1] + b * m_response[i];

         }

         // преобразуем обратно во временную область

         FFT.realFastFourierTransform( buf, m_power, true );

         // переписываем часть данных в выходной буфер

         // суммируем последние (L-1) отсчётов старого буфера

         // и первые (L-1) отсчётов нового буфера

         short[] out = new short[buf.length - m_imp_length1];

         for( i = 0; i < m_imp_length1; i++ ) {

                 double v = m_out[i] + buf[i];

                 if( v > 32767 ) out[i] = 32767;

                 else if( v < -32768 ) out[i] = -32768;

                 else out[i] = (short)v;

         }

         for( ; i < out.length; i++ ) {

                 if( buf[i] > 32767 ) out[i] = 32767;

                 else if( buf[i] < -32768 ) out[i] = -32768;

                 else out[i] = (short)buf[i];

         }

         // сохраняем последние (L-1) значений для следующего суммирования

         for( ; i < buf.length; i++ ) { m_out[i - out.length] = buf[i]; }

         return out;

 }

}

 

Предыдущая  Содержание  Следующая