ОТЧЕТ ПО ВЫПОЛНЕНИЮ ЛАБОРАТОРНЫХ РАБОТ
По дисциплине «Сигнальные процессоры»
Лабораторная работа № 3
Синтез цифровых фильтров на процессорах
с ядром ARM Cortex-M4
Выполнил студент: Мамаев С.С. Дата выполнения: 23.12.15
1. Тестовый КИХ-фильтр с непрерывной обработкой.
Примерный вид АЧХ (указать тип, порядок, обозначить названия параметров, единиц измерения)
Тип фильтра: режекторный Порядок фильтра:70
Времена обработки при использовании различных форматов данных
C фиксированной точкой | C плавающей точкой и FPU | C плавающей точкой без FPU | |
Время ввода отсчета | 0,84 | 0,84 | 0,84 |
Время обработки отсчета | 5,6 | 6,11 | 34,39 |
Время вывода отсчета | 0,55 | 0,58 | 0,58 |
Приведенное время одной итерации умножения-суммирования | 0,16 | 0,17 | 0,96 |
2. Тестовый КИХ-/БИХ-фильтр с блочной обработкой
FIR (КИХ) - фильтр
Время ввода-вывода одного отсчета: 1,85 мкс
Время обработки блока отсчетов: 3502,85 мкс
Время обработки одного отсчета: 3,42 мкс
Полное время, затрачиваемое на ввод-вывод-обработку отсчета: 5,27 мкс
Порядок фильтра: 151
Приведенное время одной итерации умножения-суммирования: 0,02 мкс
Период дискретизации: 167 мкс
Коэффициент загрузки процессора: 3,2 %
3. Синтез КИХ- и БИХ-фильтров
Discrete-Time IIR Filter (real)
% -------------------------------
% Filter Structure: Direct-Form II, Second-Order Sections
% Number of Sections: 3
% Stable: Yes
% Linear Phase: No
SOS matrix:
1 0 -1 1 -1.579725723787528 0.95295196905777169
1 0 -1 1 -1.6697431729913097 0.95809295838494668
1 0 -1 1 -1.5916986838748972 0.9128438590431841
Scale Values:
0.044515627477252032
0.044515627477252032
0.043578070478407893
Filter Structure: Direct-Form FIR
% Filter Length: 51
% Stable: Yes
% Linear Phase: Yes (Type 1)
Numerator:
-0.020610195446912189
0.0075288479873491104
0.013069144503431579
0.018814073859032294
0.020992268830162544
0.016859796985477845
0.0060945966941012373
|
-0.0087354059513403918
-0.022715777792557221
-0.0302498975800761
-0.027447470094929698
-0.013806436248764807
0.0069612327766380277
0.027843292603074072
0.041005135762151382
0.040692075260921355
0.02573329841180937
0.00035212663167955981
-0.026989722948053966
-0.046506242056566567
-0.050701818741585601
-0.037363861348875121
-0.010557855347337802
0.020582019039452594
0.045167163393082285
0.054466057834360163
0.045167163393082285
0.020582019039452594
-0.010557855347337802
-0.037363861348875121
-0.050701818741585601
-0.046506242056566567
-0.026989722948053966
0.00035212663167955981
0.02573329841180937
0.040692075260921355
0.041005135762151382
0.027843292603074072
0.0069612327766380277
-0.013806436248764807
-0.027447470094929698
-0.0302498975800761
-0.022715777792557221
-0.0087354059513403918
0.0060945966941012373
0.016859796985477845
0.020992268830162544
0.018814073859032294
0.013069144503431579
0.0075288479873491104
-0.020610195446912189
Текст задания
Вариант 2. Полоса частот входного сигнала 0…6 кГц. Полоса пропускания 1500±100 Гц при неравномерности 4 дБ. Ослабление на частотах за пределами 1500±400 Гц не менее 30 дБ
КИХ-фильтр
Response Type (тип АЧХ) | полосовой |
Design Method (метод синтеза): | FIR Equiripple |
Частота дискретизации Fs | |
Границы полосы пропускания Fpass | |
Границы полосы ослабления Fstop | |
Неравномерность в полосе пропускания Apass | |
Уровень ослабления Astop | |
Порядок фильтра (Order) |
Разностное уравнение:
Рекурсивный цифровой фильтр второго порядка описывается разностным уравнением f 2[ n ] = a 0 f 1[ n ] + a 1 f 1[ n – 1] + a 2 f 1[ n – 2] + b 1 f 2[ n – 1] + b 2 f 2[ n – 2]
нерекурсивный цифровой фильтр второго порядка описывается разностным уравнением f 2[ n ] = a 0 f 1[ n ] + a 1 f 1[ n – 1] + a 2 f 1[ n – 2]
БИХ-фильтр
Response Type (тип АЧХ) | Bandpass |
Design Method (метод синтеза): | IIR Least Pth-norm |
Частота дискретизации Fs | |
Границы полосы пропускания Fpass | |
Границы полосы ослабления Fstop | |
Неравномерность в полосе пропускания Apass | |
Уровень ослабления Astop | |
Порядок фильтра (Order) | |
Число биквадратных звеньев (Sections) | |
Признак стабильности фильтра (Stable) | Yes |
|
Разностные уравнения для первого и последнего звеньев:
yk =
yk =
4. Практическая реализация КИХ- и БИХ-фильтра
Таблица АЧХ КИХ- и БИХ-фильтров
Частота, Гц | ||||||||||||
КИХ-фильтр, коэффициент передачи, дБ | -37 | -31 | -9,6 | -2,3 | -0,3 | -2,5 | -10 | -31,2 | -32 | -33 | -35 | -37 |
БИХ-фильтр, коэффициент передачи, дБ | -36 | -31 | -14 | -2,3 | -0,3 | -2,6 | -21 | -33,4 | -34,2 | -35 | -35,6 | -36 |
Теоретические и экспериментальные АЧХ КИХ- и БИХ-фильтров
Времена блочной и непрерывной обработки для КИХ-/БИХ-фильтров и данных в форматах с фиксированной точкой (16 бит) и плавающей точкой (32 бита)
Блочная обработка | Непрерывная обработка | ||||
КИХ-фильтр | БИХ-фильтр | КИХ-фильтр | |||
Фикс. | Плав. | Плав. | Фикс. | Плав. | |
Время ввода-вывода отсчета | 1,66 | 1,85 | 1,83 | 0,84 | 0,84 |
Время обработки блока отсчетов | 1595,8 | 1938,3 | 509,24 | ||
Время обработки одного отсчета | 1,56 | 1,89 | 0,5 | ||
Приведенное время одной итерации умножения-суммирования | 0,021 | 0,025 | 0,016 | 0,16 | 0,17 |
Коэффициент загрузки процессора | 2,6% | 3% | 1,9% |
5. Синтез многополосного фильтра (по второму каналу)
Исходные данные
Тип фильтра: заграждающий
Центральные частоты полос: 697, 770, 852, 941, 1209, 1336, 1477, 1633 Гц
Полоса пропускания: 30 Гц
Полоса ослабления: 40 Гц
Исходные данные для программы Filter Design:
Частота дискретизации:4000 Гц
Вектор частот (Freq. vector):
|
Вектор амплитуд (Mag. vector):
Вектор вес. коэф. (Weight vector):
Задаваемый порядок (Specify order):600
Исходные тексты модулей проекта DspLab_fir
Модуль main.c
/******************************************************************************
*
* УЧЕБНЫЙ ПРОЕКТ
*
* Фильтр с конечной импульсной характеристикой
* Непрерывная обработка для каждого отсчета сигнала
*
* Copyright (C) 2015 МИРЭА
* Версия: 1.3
*
******************************************************************************/
/*
ОРГАНЫУПРАВЛЕНИЯ
Джойстик "вверх/вниз" - увеличение/уменьшение частоты генератора синусоидального сигнала
Джойстик "влево" - переключение между типами входного сигнала: синусоидальный / шум / нет сигнала
Джойстик "вправо" - переключение форматов входного сигнала: аналоговый (через АЦП) / цифровой код
Кнопка TAMPER - вывод меток времени обработки
*/
#include "stm32_p407.h" //Файл конфигурации отладочной платы STM32-P407
#include "adcdac.h" //Объявления функций для работы с периферийными устройствами
#include "gauge.h" //Процедуры управления и измерения
#include "values.h" //Числовые значения исходных операндов
//---------------------------------------------------------------------------
// Объявления данных
int16_t DataChannel1, DataChannel2; //Входные и выходные отсчеты в формате 1.15
int16_t DataADC; //Прямой отсчет с АЦП для системы калибровки
int32_t AmplOffset = 0; //Смещение нулевого уровня сигнала с АЦП
int32_t Modes = 0; //Режимы обработки и конфигурация системы:
// 0: аналоговый генератор -> АЦП -> обработка
// 1: цифровой генератор -> обработка
//---------------------------------------------------------------------------
// Прототипы функций в Proc.c
void DataInit(void);
void Proc(void);
//---------------------------------------------------------------------------
// ГЛАВНАЯ ФУНКЦИЯ
int main()
{
//Счетчик для реализации периода изменения тестовой индикации
volatile uint32_t i = 0;
//Инициализация цифровой обработки сигнала
DataInit();
//Задание 4-х уровней групповых приоритетов и 4-х уровней приоритетов в каждой группе
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//Инициализация индикаторов
STM_LEDInit(LED1);
//Инициализация кнопок
STM_PBInit(BUTTON_TAMPER, BUTTON_MODE_GPIO);
STM_PBInit(BUTTON_WAKEUP, BUTTON_MODE_GPIO);
//Инициализация кодека (ЦАП выходных отсчетов сигнала)
SoundCodecConfig(FS_FIR); //Аргумент - частота дискретизации, Гц
SoundCodecInterruptConfig(ENABLE);
//Инициализация АЦП
ADCConfig();
//Инициализация генератора входного сигнала
SignalGenConfig();
//Инициализация графического интерфейса, джойстика, системы измерений
GgInterfaceInit();
//ОСНОВНОЙ ЦИКЛ
while (1)
{
GgControl(); //Управление частотой и амплитудой генератора сигнала,
// вывод результатов измерений
if (i++ == 0x800) STM_LEDOff(LED1); //Тестовое управление индикатором
if (i == 0x50000) STM_LEDOn(LED1), i = 0;
if (STM_PBGetState(BUTTON_WAKEUP)) break; //Выход из основного цикла, если нажата WAKEUP
}
//ОКОНЧАНИЕ ОСНОВНОГО ЦИКЛА
//Сброс процессора - завершение выполнения данной программы, запуск начального загрузчика
NVIC_SystemReset();
while (1) {}
}
//---------------------------------------------------------------------------
// ОБСЛУЖИВАНИЕ ПРЕРЫВАНИЯ С ЧАСТОТОЙ ДИСКРЕТИЗАЦИИ
// Данная подпрограмма вызывается из обработчика прерывания..._IRQHandler(),
// реализованного в adcdac.c
// Частота дискретизации формируется модулем процессора SPI/I2S,
// посредством которого по интерфейсу I2S отсчеты сигнала выводятся на внешний звуковой кодек.
// Этот модуль также генерирует прерывания с частотой дискретизации. В обработчике
// прерывания, размещенном здесь, производятся следующие операции:
// - считываются отсчеты входного сигнала с АЦП или цифрового входа;
// - АЦП запускается на следующий цикл преобразования;
// - вызывается процедура обработки Proc(), возвращающая выходные отсчеты;
// - выходные отсчеты передаются кодеку.
void Sample_Handler(void)
{
extern int16_t GeneratorSamples; //Цифровой выход генератора сигналов (в доп. коде)
// параметр объявлен в adcdac.c
if (Modes == 0)
{ //Получение данных с АЦП, преобразование смещенного кода в дополнительный,
// коррекция нулевого уровня
DataADC = ADC_GetConversionValue(ADC1) ^ 0x8000;
DataChannel2 = DataChannel1 = DataADC - AmplOffset;
}
//Получение цифрового отсчета входного сигнала (минуя АЦП)
else DataChannel2 = DataChannel1 = GeneratorSamples;
//Перезапуск АЦП
ADC_SoftwareStartConv(ADC1);
//Вызов подпрограммы цифровой обработки сигнала (реализована в proc.c)
TimeMarker2(); //Временная метка № 2
Proc();
TimeMarker3(); //Временная метка № 3
//Обработанные значения - в DataChannel1, DataChannel2
}
Модуль proc.c
/******************************************************************************
*
* ПОДПРОГРАММЫЦИФРОВОЙ ОБРАБОТКИ СИГНАЛА
*
* Фильтр с конечной импульсной характеристикой
* Непрерывная обработка для каждого отсчета сигнала
*
******************************************************************************/
/* Подключаемые заголовочные файлы */
#include "mathfunc.h" //Прототипы математических функций
#include "coef.h" //Значения коэффициентов
//#define FLOAT_PROC //Определение для использования при обработке сигнала
// данных с плавающей точкой
/* Константы */
// numTaps //Число отсчетов/коэффициентов - задано в coef.h
// float FIR_coef[numTaps] //Массив коэффициентов в формате float - задан в coef.h
/* Текущие переменные */
extern int16_t DataChannel1, //Входные и выходные отсчеты в формате 1.15
DataChannel2; // (объявлены в main.c)
#ifndef FLOAT_PROC //В а р и а н т обработки с фиксированной точкой
int16_t Samples[numTaps]; //Буфер 16-разрядных отсчетов (циклический) в формате 1.15
int32_t Coeffs[numTaps]; //Буфер 32-разрядных коэффициентов в дробном формате 1.31
int16_t* pSamples; //Указатель на отсчеты
int16_t* pSamplesEnd; //Указатель на конец буфера отсчетов
int32_t* pCoeffs; //Указатель на коэффициенты
#else //В а р и а н т обработки с плавающей точкой
float Samples[numTaps]; //Буфер отсчетов
float* pSamples; //Указатель на отсчеты
float* pSamplesEnd; //Указатель на конец буфера отсчетов
float* pCoeffs; //Указатель на коэффициенты
#endif
/******************************************************************************
ПОДПРОГРАММА ИНИЦИАЛИЗАЦИИ ФИЛЬТРА
Вызывается однократно при старте программы
*/
void DataInit(void)
{
#ifndef FLOAT_PROC
int32_t i; //Для варианта обработки с фиксированной точкой:
for (i = 0; i < numTaps; i++) // преобразование формата коэффициентов из float в дробный 1.31
Coeffs[i] = float_to_q31(FIR_coef[i]);
#endif
pSamples = Samples; //Установка указателя отсчетов на начало буфера
pSamplesEnd = Samples + numTaps; //Задание указателя конца буфера отсчетов
}
/******************************************************************************
ПОДПРОГРАММА ОБРАБОТКИ
Вызывается с частотой дискретизации при получении новых отсчетов.
Отсчеты входного сигнала для первого и второго каналов
размещены в глобальных переменных DataChannel1, DataChannel2. В эти же
переменные записываются обработанные отсчеты по соответствующим каналам.
В исходном варианте производится обработка данных только первого канала.
*/
void Proc(void)
{
#ifndef FLOAT_PROC //------- В а р и а н т обработки с фиксированной точкой -------
int32_t x, b; //Текущие значения отсчета и коэффициента
int32_t i = numTaps; //Счетчик циклов умножений-накоплений
int64_t acc = 0; //Очистка 64-разрядного аккумулятора (накопителя)
pCoeffs = &Coeffs[numTaps-1]; //Установка указателя на последний коэффициент bN
*pSamples++ = DataChannel1; //Сохранение входного отсчета в памяти
if (pSamples >= pSamplesEnd) pSamples = Samples; //Проверка перехода на начало циклического буфера
do //Организация цикла с счетчиком i, изменяющимся от numTaps до 1
{
x = *pSamples++; //Выборка отсчета, продвижение указателя на следующий отсчет
b = *pCoeffs--; //Выборка коэффициента, продвижение указателя на предыдущий коэффициент
acc += (int64_t)b * x; //Умножение коэффициента и отсчета с накоплением
if (pSamples >= pSamplesEnd) pSamples = Samples; //Проверка перехода на начало циклического буфера
} while (--i!= 0); //Декремент счетчика i, проверка его на обнуление
DataChannel1 = (int16_t)(acc >> 31u); //Преобразование формата 2.62 в формат 1.31 с усечением до 1.15
#else //------- В а р и а н т обработки с плавающей точкой -------
float x, b; //Текущие значения отсчета и коэффициента
int32_t i = numTaps; //Счетчик циклов умножений-накоплений
float acc = 0; //Очистка аккумулятора (накопителя)
pCoeffs = &FIR_coef[numTaps-1]; //Установка указателя на последний коэффициент bN
*pSamples++ = q15_to_float(DataChannel1); //Преобразование входного отсчета в формат float,
// сохранение его в памяти
if (pSamples >= pSamplesEnd) pSamples = Samples; //Проверка перехода на начало циклического буфера
do //Организация цикла с счетчиком i, изменяющимся от numTaps до 1
{
x = *pSamples++; //Выборка отсчета, продвижение указателя на следующий отсчет
b = *pCoeffs--; //Выборка коэффициента, продвижение указателя на предыдущий коэффициент
acc += b * x; //Умножение коэффициента и отсчета с накоплением
if (pSamples >= pSamplesEnd) pSamples = Samples; //Проверка перехода на начало циклического буфера
} while (--i!= 0); //Декремент счетчика i, проверка его на обнуление
DataChannel1 = float_to_q15(acc); //Преобразование формата float в формат 1.15
#endif
DataChannel2 = DataChannel1;
}
Пример заголовочного модуля coef.h (fir_coef.h)
#define numTaps 34 //Число коэффициентов
float FIR_coef[numTaps] =
{
0.0214619597717033f, 0.0307411336820300f, 0.0038734707706876f, -0.0082041254073283f,
-0.0381282158344837f, -0.0378178633033697f, -0.0198560236913657f, 0.0217448788296480f,
0.0539662691353649f, 0.0594653676995162f, 0.0257788446908599f, -0.0276575170129635f,
-0.0704352004893433f, -0.0728329271355395f, -0.0310751415250206f, 0.0317280678231007f,
0.0771282967388960f, 0.0771282967388960f, 0.0317280678231007f, -0.0310751415250206f,
-0.0728329271355395f, -0.0704352004893433f, -0.0276575170129635f, 0.0257788446908599f,
0.0594653676995162f, 0.0539662691353649f, 0.0217448788296480f, -0.0198560236913657f,
-0.0378178633033697f, -0.0381282158344837f, -0.0082041254073283f, 0.0038734707706876f,
0.0307411336820300f, 0.0214619597717033f
};