реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> формат *.h от fdaTool для IIR, не совсем понятно, почему так хитро, или ломка в открытую дверь, может
IhorOs
сообщение Aug 3 2011, 18:29
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 15
Регистрация: 17-12-07
Из: Украина, Тернополь...
Пользователь №: 33 360



Здравствуйте.
Задача - синтизировать фильтр, а затем реализовать его в железяке. Реализация должна быть ориентированная на поточную обработку, а не пакетную.
при анализе, оказалось что желательно IIR фильтр.

Более - менее осилил fdaTool в чассти синтеза... Даже более менее понятно куда сунуть SOS matrix и Scale Values, из файла кооефициентов, полученных при експорте...
Но как человек ленивый даю предпочтение пользоваться продуктом от "Target/Generate C header..."

после изучения полученного хидера возникает подозрение, что массивы из него есть некая комбинация чисел из SOS matrix и Scale Values с некоторой степенью разрежения (из 6 елементов используется 4, два - нулевые)...

Так вот вопрос - зачем так хитро? я предполагаю, что есть некие реализации кода фильров, заточенные под эти декларации. Но в упрор я нигде не смог их обнаружить... и даже не помогло отсутсвие бана в гугле...
Я предполагаю, что эти нулевые ячейки можна использовать как хранилище задержаных значений в какой то оптимальной реализации кода... Конечно, можно попытатся реализовать этот код самому.. но зачем изобретать велосипед... Одним словом вторая часть вопроса - где можно посмотреть на этот велосипед... То есть реализацию IIR фильтра, которая напрямую использует хедер файл, генерируемый fdaTool для IIR.

Спасибо за внимание.


Go to the top of the page
 
+Quote Post
IhorOs
сообщение Aug 6 2011, 12:34
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 15
Регистрация: 17-12-07
Из: Украина, Тернополь...
Пользователь №: 33 360



Продолжу "тихо сам с собою"... с надеждой, что может старейшины подправят, если что не то...

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

В конечном итоге один шаг фильтра уменшил с 349 проц. такта до 189. Причем в 349 уже было учтено, что нумераторы вида 1 0 -1, то есть вместо двух умножений и двух сложений біло использовано только одно вычитание.

Да, может кому сходится, заброшу сорцы сюда. Не сочтите за спам :-).

Итак, IIR, Direct-Form II, Second-Order Sections, Чебышева тип 1, 8-й порядок. Частота семплирования 400000, частоты среза среза 89000, 111000, неравномерность в полосе пропускания - 0.1 дБ.

с помощью fdaTool получены следующие коофициенты:

Код
% Generated by MATLAB(R) 7.12 and the Signal Processing Toolbox 6.15.
%
% Generated on: 04-Aug-2011 09:30:20
%

% Coefficient Format: Hexadecimal

% Discrete-Time IIR Filter (real)                            
% -------------------------------                            
% Filter Structure    : Direct-Form II, Second-Order Sections
% Number of Sections  : 4                                    
% Stable              : Yes                                  
% Linear Phase        : No                                  
% Arithmetic          : fixed
% Numerator           : s16,15 -> [-1 1)                    
% Denominator         : s16,15 -> [-1 1)                    
% Scale Values        : s16,15 -> [-1 1)                    
% Input               : s16,15 -> [-1 1)                    
% Section Input       : s16,14 -> [-2 2)                    
% Section Output      : s16,15 -> [-1 1)                    
% Output              : s16,15 -> [-1 1)                    
% State               : s16,15 -> [-1 1)                    
% Numerator Prod      : s32,31 -> [-1 1)
% Denominator Prod    : s32,31 -> [-1 1)
% Numerator Accum     : s32,31 -> [-1 1)
% Denominator Accum   : s32,31 -> [-1 1)
% Round Mode          : convergent
% Overflow Mode       : wrap
% Cast Before Sum     : true


SOS matrix:
7fff  0000  8000  7fff  2f2d  751e
7fff  0000  8000  7fff  d0d3  751e
7fff  0000  8000  7fff  12c3  6683
7fff  0000  8000  7fff  ed3d  6683

Scale Values:
1835
1835
0fd3
0fd3
7e89


для справки, если делать для плавающей точки, то будет нижеследующее (как то проще представлять при просмотре, что единичный коэф. передачи это 1, а не 0x8000, а тем более 0xFFFF)

Код


SOS matrix:                                                                      
0.999969482421875  0  -1  0.999969482421875   0.368560791015625  0.91497802734375
0.999969482421875  0  -1  0.999969482421875  -0.368560791015625  0.91497802734375
0.999969482421875  0  -1  0.999969482421875   0.146575927734375  0.800872802734375
0.999969482421875  0  -1  0.999969482421875  -0.146575927734375  0.800872802734375
                                                                                  
Scale Values:                                                                    
0.189117431640625                                                                
0.189117431640625                                                                
0.123626708984375                                                                
0.123626708984375                                                                
0.988555908203125



Ну и упомянутый хидер от fdaTool
Код


General type conversion for MATLAB generated C-code   * /
#include "tmwtypes.h"
/ *
* Expected path to tmwtypes.h
* C:\Program Files\MATLAB\R2011a\extern\include\tmwtypes.h
* /
#define MWSPT_NSEC 9
const int NL[MWSPT_NSEC] = { 1,3,1,3,1,3,1,3,1 };
const int16_T NUM[MWSPT_NSEC][3] = {
  {
     6197,      0,      0
  },
  {
    32767,      0, -32768
  },
  {
     6197,      0,      0
  },
  {
    32767,      0, -32768
  },
  {
     4051,      0,      0
  },
  {
    32767,      0, -32768
  },
  {
     4051,      0,      0
  },
  {
    32767,      0, -32768
  },
  {
    32393,      0,      0
  }
};
const int DL[MWSPT_NSEC] = { 1,3,1,3,1,3,1,3,1 };
const int16_T DEN[MWSPT_NSEC][3] = {
  {
    32767,      0,      0
  },
  {
    32767,  12077,  29982
  },
  {
    32767,      0,      0
  },
  {
    32767, -12077,  29982
  },
  {
    32767,      0,      0
  },
  {
    32767,   4803,  26243
  },
  {
    32767,      0,      0
  },
  {
    32767,  -4803,  26243
  },
  {
    32767,      0,      0
  }
};




Теперь моя реализация (сори за кривость идентификаторов, делалось второпях и пока без выработки оконечной идеологии наименований для проекта)

первым делом декларация коэфициентов

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

Код
// Number of Sections;
#define NOS_IIR_Che1_89_1110_08  4

// Scale Values:
const int arrSV_IIR_Che1_89_1110_08[NOS_IIR_Che1_89_1110_08 + 1] =
{
   0x1835, 0x1835, 0x0fd3, 0x0fd3, 0x7e89
};


// деномінатори:
//arrDen_IIR_Che1_89_1110_08array
const int  arrDen_IIR_Che1_89_1110_08[NOS_IIR_Che1_89_1110_08][2] =
{
    {  12077,  29982},
    { -12077,  29982},
    {   4803,  26243},
    {  -4803,  26243}
};


// робочі масиви
// декларую три окремих масиви, а не один двомірний дял того,
// щоби поиім можна було використати Copy і не думати про порядок обробки індексів


int  arrW_IIR_Che1_89_1110_08[NOS_IIR_Che1_89_1110_08];
int  arrW_old1_IIR_Che1_89_1110_08[NOS_IIR_Che1_89_1110_08];
int  arrW_old2_IIR_Che1_89_1110_08[NOS_IIR_Che1_89_1110_08];


Обратите внимание, что номинаторов не дакларирую - они все вида 1 0 -1, посему будем долбить их гардкодингом


Далее цикловая реализация:
Код

//working, 558051/1599 = 349 циклів  
//          
inline InpF_IIR_Che1_89_1110_08_Step(int aInp)
{

int ns;
long int w0;


  w0 = aInp; // тут aInp є в режимі s16, 15
  

  //for ns := 0 to NOS_IIR_Che1_89_1110_08 - 1 do
  for (ns =0; ns <  NOS_IIR_Che1_89_1110_08; ns++ )
  {

      // тут w0 в s16, 15
      w0 = w0 *  (long int)(arrSV_IIR_Che1_89_1110_08[ns]);
      // тут w0 в режимі  s32, s30



     // коеф. в реж.  в s16, 15
     // далі w[n] = x[n] - a1*w[n-1] - a2*w[n-2]
     // a0 = 1.0, w0 пітримується в режимі, який допускає
     // "пряме" використання w0

      w0 = w0  // a0 = 1.0
      - (long int)(arrW_old1_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][0])
      - (long int)(arrW_old2_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][1]);
    // !!  використання тут функцій виду _smas виграшу не дає, напевно накладні витрати..


    // готуємо до передачі в масиви затримки

      arrW_IIR_Che1_89_1110_08[ns] = (w0 >> 15);

    // далі y[n] = w[n] +  b1*w[n-1] + b2*w[n-2]
    // але тут b1 = 0 і b2 = -1
    // тому взагалі далі робимо математику в варіанті s16, 15

     w0 = (w0 >> 15) - arrW_old2_IIR_Che1_89_1110_08[ns];
    // w0 = (arrW_IIR_Che1_89_1110_08[ns] = (w0 >> 15)) - arrW_old2_IIR_Che1_89_1110_08[ns];
  }

  // здійснюємо затримку
  memcpy(&arrW_old2_IIR_Che1_89_1110_08, &arrW_old1_IIR_Che1_89_1110_08, sizeof(arrW_old2_IIR_Che1_89_1110_08));
  memcpy(&arrW_old1_IIR_Che1_89_1110_08, &arrW_IIR_Che1_89_1110_08, sizeof(arrW_old1_IIR_Che1_89_1110_08));

  return (w0 * (long int)arrSV_IIR_Che1_89_1110_08[NOS_IIR_Che1_89_1110_08]) >> 15;
}


как уже писал - 349 машинных циклов (тактов, вернее).
И для полноті инфо - безцикловая, которая дала 189

Код
// безциклова реалізація - з метою зменшення накладних витрат - цикл крутимо лише 4 рази, тому копи-паст...
// 307008/1599 -> 192
// 302211/1599 -> 189
inline InpF_IIR_Che1_89_1110_08_Step(int aInp)
{
int i16;
long int w0;
w0 = aInp; // тут aInp є в режимі s16, 15

//  ---- "типу початок " циклу

// ns = 0  ****************************************************
#undef ns
#define ns  0


// тут w0 в s16, 15

// насамперед слід врахувати вхідний коеф. секції, а
// потім обробити деномінатори
//  деномінатори обробляються за виразом
//  w[n] = x[n] - a1*w[n-1] - a2*w[n-2], тут враховано що a0 = 1, і w0 підтримується в режимі,
//  який допускаэ пряме використання w0 (незважаючи на те, що 1 відповідає 0x8000)
//
//  вище сказане зводиться до двох наступних (закоментованих)операторів
//
//  w0 = w0 *  (long int)(arrSV_IIR_Che1_89_1110_08[ns]);  // тут w0 вже в режимі  s32, s30
//  w0 = w0  // a0 = 1.0
//     - (long int)(arrW_old1_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][0])
//     - (long int)(arrW_old2_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][1]);
//  але оптимізуючий компілятор дає кращий код, коли їх звести в один.
//  Тому робимо це, незважаючи на деяку нечитабельність :-)


w0 = w0 *  (long int)(arrSV_IIR_Che1_89_1110_08[ns])  // a0 = 1.0
   - (long int)(arrW_old1_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][0])
   - (long int)(arrW_old2_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][1]);


// далі готуємо до передачі в масиви затримки і обробляємо номінатори.
// це можна було би зробити наступними двома закоментованими операторами
//  arrW_IIR_Che1_89_1110_08[ns] = (w0 >> 15);
// w0 = (w0 >> 15) - arrW_old2_IIR_Che1_89_1110_08[ns];
// але враховуючи особливості оптимізації зробимо це одлим, "нечитабельним":

w0 =  (arrW_IIR_Che1_89_1110_08[ns]  = ( w0 >> 15) )- arrW_old2_IIR_Che1_89_1110_08[ns];


// ns = 1  ****************************************************
#undef ns
#define ns  1
// коментарі див. в  ns  0
w0 = w0 *  (long int)(arrSV_IIR_Che1_89_1110_08[ns])  
   - (long int)(arrW_old1_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][0])
   - (long int)(arrW_old2_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][1]);

w0 =  (arrW_IIR_Che1_89_1110_08[ns]  = ( w0 >> 15) ) - arrW_old2_IIR_Che1_89_1110_08[ns];

// ns = 2  ****************************************************
#undef ns
#define ns  2

// коментарі див. в  ns  0
w0 = w0 *  (long int)(arrSV_IIR_Che1_89_1110_08[ns])  
   - (long int)(arrW_old1_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][0])
   - (long int)(arrW_old2_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][1]);

w0 =  (arrW_IIR_Che1_89_1110_08[ns]  = ( w0 >> 15) ) - arrW_old2_IIR_Che1_89_1110_08[ns];

// ns = 3  ****************************************************
#undef ns
#define ns  3

// коментарі див. в  ns  0
w0 = w0 *  (long int)(arrSV_IIR_Che1_89_1110_08[ns])  
   - (long int)(arrW_old1_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][0])
   - (long int)(arrW_old2_IIR_Che1_89_1110_08[ns]) * (long int)(arrDen_IIR_Che1_89_1110_08[ns][1]);

w0 =  (arrW_IIR_Che1_89_1110_08[ns]  = ( w0 >> 15) ) - arrW_old2_IIR_Che1_89_1110_08[ns];

//  ---- "типу кінець " циклу

// використання тут 16 бітної зміннох заміть 32 бітної w0 дозволяє зекономити декілька циклів (точно не задокоментував)
i16 = (w0 * (long int)arrSV_IIR_Che1_89_1110_08[NOS_IIR_Che1_89_1110_08]) >> 15;

  memcpy(&arrW_old2_IIR_Che1_89_1110_08, &arrW_old1_IIR_Che1_89_1110_08, sizeof(arrW_old2_IIR_Che1_89_1110_08));
  memcpy(&arrW_old1_IIR_Che1_89_1110_08, &arrW_IIR_Che1_89_1110_08, sizeof(arrW_old1_IIR_Che1_89_1110_08));

  //return (w0 * (long int)arrSV_IIR_Che1_89_1110_08[NOS_IIR_Che1_89_1110_08]) >> 15;

  return i16;
}



Фсе... Может кому сгодится. Но больше приветсвуются комментарии, в тч лехкое мордобитие...

пс. копи паст на дефайн менять как то влом было, тем болеее что тогда с читабельностью совсем тяжело...


Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 28th July 2025 - 21:06
Рейтинг@Mail.ru


Страница сгенерированна за 0.01421 секунд с 7
ELECTRONIX ©2004-2016