Реализуйте КИХ-Алгоритм Фильтра для С плавающей точкой и броска использования Фиксированных точек и нулей

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

Разделение спецификации типа данных от кода алгоритма позволяет вам:

  • Снова используйте свой код алгоритма с различными типами данных

  • Сохраните свой алгоритм ненарушенным операторами описания типа данных и операторами switch для различных типов данных

  • Сохраните свой код алгоритма более читаемым

  • Переключитесь между фиксированной точкой и плавающей точкой, чтобы сравнить базовые линии

  • Переключитесь между изменениями настроек фиксированной точки, не изменяя код алгоритма

Исходный алгоритм

Этот пример преобразует код MATLAB® для фильтра конечной импульсной характеристики (FIR) к фиксированной точке.

Формула для энного выхода y (n) (КИХ) фильтр, данный коэффициенты фильтра b и вход x:

y(n) = b(1)*x(n) + b(2)*x(n-1) + ... + b(end)*x(n-length(b)+1)

Линейная буферная реализация

Существует несколько различных способов записать КИХ-фильтр. Один путь с линейным буфером как в следующей функции, где b является вектором-строкой, и z является вектор-столбцом та же длина как b.

function [y,z] = fir_filt_linear_buff(b,x,z)
    y = zeros(size(x));
    for n=1:length(x)
        z = [x(n); z(1:end-1)];
        y(n) = b * z;
    end
end

Вектор z составлен из текущих и предыдущих выборок x:

z = [x(n); x(n-1); .. ; x(n-length(b)+1)]

Вектор z называется вектором состояния. Это используется и в качестве входа и в качестве выхода. Когда это - вход, это - начальное состояние фильтра. Когда это - выход, это - конечное состояние фильтра. Определение вектора состояния вне функции позволяет вам постоянно потоковым данным через фильтр в системе реального времени, и снова использовать алгоритм фильтра в рамках того же проекта. Вектор состояния часто называют z, потому что это синонимично с задержками$z^{-1}$, сопоставленными с Z-преобразованием. Z-преобразование назвали в честь Lotfi Zadeh для его оригинальной работы в этой области [1].

Линейная буферная реализация использует в своих интересах удобный матричный синтаксис MATLAB и легка читать и понять. Однако это вводит полную копию буфера состояния для каждой выборки входа.

Реализация кольцевого буфера

Чтобы реализовать КИХ-фильтр более эффективно, можно сохранить состояния в кольцевом буфере, z, чьими элементами является z (p) = x (n), где p=mod (n-1, длина (b)) +1, для n=1, 2, 3....

Например, позвольте длине (b) = 3 и инициализируйте p и z к:

p = 0, z = [ 0    0    0  ]

Начните с первой выборки и заполните буфер состояния z круговым способом.

n = 1, p = 1, z(1) = x(1), z = [x(1)  0    0  ]
y(1) = b(1)*z(1) + b(2)*z(3) + b(3)*z(2)
n = 2, p = 2, z(2) = x(2), z = [x(1) x(2)  0  ]
y(2) = b(1)*z(2) + b(2)*z(1) + b(3)*z(3)
n = 3, p = 3, z(3) = x(3), z = [x(1) x(2) x(3)]
y(3) = b(1)*z(3) + b(2)*z(2) + b(3)*z(1)
n = 4, p = 1, z(1) = x(4), z = [x(4) x(2) x(3)]
y(4) = b(1)*z(1) + b(2)*z(3) + b(3)*z(2)
n = 5, p = 2, z(2) = x(5), z = [x(4) x(5) x(3)]
y(5) = b(1)*z(2) + b(2)*z(1) + b(3)*z(3)
n = 6, p = 3, z(3) = x(6), z = [x(4) x(5) x(6)]
y(6) = b(1)*z(3) + b(2)*z(2) + b(3)*z(1)
...

Можно реализовать КИХ-фильтр с помощью кольцевого буфера как следующая функция MATLAB.

function [y,z,p] = fir_filt_circ_buff_original(b,x,z,p)
    y = zeros(size(x));
    nx = length(x);
    nb = length(b);
    for n=1:nx
        p=p+1; if p>nb, p=1; end
        z(p) = x(n);
        acc = 0;
        k = p;
        for j=1:nb
            acc = acc + b(j)*z(k);
            k=k-1; if k<1, k=nb; end
        end
        y(n) = acc;
    end
end

Тестовый файл

Создайте тестовый файл, чтобы подтвердить это, алгоритм с плавающей точкой работает как ожидалось прежде, чем преобразовать его в фиксированную точку. Можно использовать тот же тестовый файл, чтобы предложить типы данных с фиксированной точкой и сравнить результаты фиксированной точки с базовой линией с плавающей точкой после преобразования.

Тестовые векторы должны представлять реалистические входные параметры, которые осуществляют полный спектр значений, ожидаемых вашей системой. Реалистические входные параметры являются импульсами, суммами синусоид и сигналами щебета, для которых можно проверить, что выходные параметры являются правильной использующей линейной теорией. Сигналы, которые производят максимальный выход, полезны для проверки, что ваша система не переполняется.

Настройка

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

resetglobalfimath;
FIPREF_STATE = get(fipref);
resetfipref;

Запустите следующий код, чтобы скопировать тестовые функции во временную папку, таким образом, этот пример не вмешивается в вашу собственную работу.

tempdirObj = fidemo.fiTempdir('fir_filt_circ_buff_fixed_point_conversion_example');
copyfile(fullfile(matlabroot,'toolbox','fixedpoint','fidemos','+fidemo',...
                  'fir_filt_*.m'),'.','f');

Отфильтруйте коэффициенты

Используйте следующие коэффициенты фильтра lowpass, которые были вычислены с помощью функции fir1 из Signal Processing Toolbox.

b = fir1(11,0.25);
b = [-0.004465461051254
    -0.004324228005260
    +0.012676739550326
    +0.074351188907780
    +0.172173206073645
    +0.249588554524763
    +0.249588554524763
    +0.172173206073645
    +0.074351188907780
    +0.012676739550326
    -0.004324228005260
    -0.004465461051254]';

Временной вектор

Используйте этот временной вектор, чтобы создать тестовые сигналы.

nx = 256;
t = linspace(0,10*pi,nx)';

Вход Impulse

Ответ КИХ-фильтра к импульсному входу является самими коэффициентами фильтра.

x_impulse = zeros(nx,1); x_impulse(1) = 1;

Сигнал, который производит максимальный выход

Максимальный выход фильтра происходит, когда знаки входных параметров выстраиваются в линию со знаками импульсной характеристики фильтра.

x_max_output = sign(fliplr(b))';
x_max_output = repmat(x_max_output,ceil(nx/length(b)),1);
x_max_output = x_max_output(1:nx);

Максимальная величина выхода является 1 нормой своей импульсной характеристики, которая является нормой (b, 1) = сумма (abs (b)).

maximum_output_magnitude = norm(b,1) %#ok<*NOPTS>
maximum_output_magnitude =

    1.0352

Сумма синусов

Сумма синусов является типичным входом для фильтра, и можно легко видеть высокие частоты, отфильтрованные в графике.

f0=0.1; f1=2;
x_sines = sin(2*pi*t*f0) + 0.1*sin(2*pi*t*f1);

Щебет

Щебет дает пользу, визуальную из действия фильтра lowpass передачи низких частот и ослабления высоких частот.

f_chirp = 1/16;                  % Target frequency
x_chirp = sin(pi*f_chirp*t.^2);  % Linear chirp

titles = {'Impulse', 'Max output', 'Sum of sines', 'Chirp'};
x = [x_impulse, x_max_output, x_sines, x_chirp];

Вызовите исходную функцию

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

y0 = zeros(size(x));
for i=1:size(x,2)
    % Initialize the states for each column of input
    p = 0;
    z = zeros(size(b));
    y0(:,i) = fir_filt_circ_buff_original(b,x(:,i),z,p);
end

Базовый Выход

fir_filt_circ_buff_plot(1,titles,t,x,y0)

Подготовьтесь к инструментированию и генерации кода

Первый шаг после алгоритма работает в MATLAB, должен подготовить его к инструментированию, которое требует генерации кода. Перед преобразованием можно использовать функцию coder.screener, чтобы анализировать код и идентифицировать неподдерживаемые функции и функции языка.

Функция точки входа

При выполнении инструментирования и генерации кода, удобно иметь функцию точки входа, которая вызывает функцию, которая будет преобразована в фиксированную точку. Можно бросить КИХ-входные параметры фильтра к различным типам данных и добавить вызовы различных изменений фильтра для сравнения. При помощи функции точки входа можно запустить и фиксированную точку и варианты с плавающей точкой фильтра, и также различные варианты фиксированной точки. Это позволяет вам выполнять итерации на вашем коде более быстро, чтобы прибыть в оптимальный проект фиксированной точки.

function y = fir_filt_circ_buff_original_entry_point(b,x,reset)
    if nargin<3, reset = true; end
    % Define the circular buffer z and buffer position index p.
    % They are declared persistent so the filter can be called in a streaming
    % loop, each section picking up where the last section left off.
    persistent z p
    if isempty(z) || reset
        p = 0;
        z = zeros(size(b));
    end
    [y,z,p] = fir_filt_circ_buff_original(b,x,z,p);
end

Тестовый файл

Ваш тестовый файл вызывает скомпилированную функцию точки входа.

function y = fir_filt_circ_buff_test(b,x)
     y = zeros(size(x));
     for i=1:size(x,2)
         reset = true;
         y(:,i) = fir_filt_circ_buff_original_entry_point_mex(b,x(:,i),reset);
     end
end

Создайте исходную функцию

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

reset = true;
buildInstrumentedMex fir_filt_circ_buff_original_entry_point -args {b, x(:,1), reset}

Запустите исходную функцию

Запустите свои входные параметры тестового файла через алгоритм, чтобы регистрировать минимальные и максимальные значения.

y1 = fir_filt_circ_buff_test(b,x);

Покажите типы

Используйте showInstrumentationResults, чтобы просмотреть типы данных всех ваших переменных и минимальных и максимальных значений, которые регистрировались во время запущенного тестового файла. Посмотрите на максимальное значение, регистрируемое для выходной переменной y и переменной аккумулятора acc, и обратите внимание, что они достигли теоретического максимального выходного значения, которое вы вычислили ранее.

showInstrumentationResults fir_filt_circ_buff_original_entry_point_mex

Видеть эти результаты в оснащенном Отчете Генерации кода:

  • Выберите функцию fir_filt_circ_buff_original

  • Выберите вкладку Variables

Подтвердите исходную функцию

Каждый раз, когда вы изменяете свою функцию, подтверждаете это, результаты все еще совпадают с вашей базовой линией.

fir_filt_circ_buff_plot2(2,titles,t,x,y0,y1)

Преобразуйте Функции, чтобы использовать Таблицы типов

Разделить типы данных от алгоритма, вас:

  1. Составьте таблицу определений типов.

  2. Измените код алгоритма, чтобы использовать типы данных из той таблицы.

Этот пример показывает итеративные шаги путем создания различных файлов. На практике можно внести итеративные изменения в тот же файл.

Исходная таблица типов

Создайте таблицу типов с помощью структуры с прототипами для набора переменных к их исходным типам. Используйте базовые типы, чтобы подтвердить это, вы сделали начальное преобразование правильно, и также используйте его, чтобы программно переключить вашу функцию между с плавающей точкой и фиксированными точками. Индексные переменные j, k, n, nb, nx автоматически преобразованы в целые числа MATLAB Coder™, таким образом, вы не должны задавать их типы в таблице.

Задайте прототипные значения как пустые ([]), поскольку типы данных используются, но не значения.

function T = fir_filt_circ_buff_original_types()
    T.acc=double([]);
    T.b=double([]);
    T.p=double([]);
    T.x=double([]);
    T.y=double([]);
    T.z=double([]);
end

Осведомленная о типе функция filter

Подготовьте функцию filter и функцию точки входа, чтобы быть осведомленными о типе при помощи броска и нулевых функций и таблицы типов.

Используйте преобразованное в нижний индекс присвоение acc (:) =..., p (:) =1, и k (:) =nb, чтобы сохранить типы данных во время присвоения. Смотрите раздел "Cast fi Objects" в документации Fixed-Point Designer для получения дополнительной информации о преобразованном в нижний индекс присвоении и типах данных сохранения.

Вызов функции y = нули (размер (x), 'как', T.y) создает массив нулей тот же размер как x со свойствами переменной T.y. Первоначально, T.y является двойным, заданным в функции fir_filt_circ_buff_original_types, но это переопределено как фиксированная точка позже в этом примере.

Вызов функции acc = бросок (0, 'как', T.acc) бросает значение 0 с теми же свойствами как переменная T.acc. Первоначально, T.acc является двойным, заданным в функции fir_filt_circ_buff_original_types, но это переопределено как фиксированная точка позже в этом примере.

function [y,z,p] = fir_filt_circ_buff_typed(b,x,z,p,T)
    y = zeros(size(x),'like',T.y);
    nx = length(x);
    nb = length(b);
    for n=1:nx
        p(:)=p+1; if p>nb, p(:)=1; end
        z(p) = x(n);
        acc = cast(0,'like',T.acc);
        k = p;
        for j=1:nb
            acc(:) = acc + b(j)*z(k);
            k(:)=k-1; if k<1, k(:)=nb; end
        end
        y(n) = acc;
    end
end

Осведомленная о типе функция точки входа

Вызов функции p1 = бросок (0, 'как', T1.p) бросает значение 0 с теми же свойствами как переменная T1.p. Первоначально, T1.p является двойным, заданным в функции fir_filt_circ_buff_original_types, но это переопределено как целочисленный тип позже в этом примере.

Вызов функции z1 = нули (размер (b), 'как', T1.z) создает массив нулей тот же размер как b со свойствами переменной T1.z. Первоначально, T1.z является двойным, заданным в функции fir_filt_circ_buff_original_types, но это переопределено как фиксированная точка позже в этом примере.

function y1 = fir_filt_circ_buff_typed_entry_point(b,x,reset)
   if nargin<3, reset = true; end
   %
   % Baseline types
   %
   T1 = fir_filt_circ_buff_original_types();
   % Each call to the filter needs to maintain its own states.
   persistent z1 p1
   if isempty(z1) || reset
       p1 = cast(0,'like',T1.p);
       z1 = zeros(size(b),'like',T1.z);
   end
   b1 = cast(b,'like',T1.b);
   x1 = cast(x,'like',T1.x);
   [y1,z1,p1] = fir_filt_circ_buff_typed(b1,x1,z1,p1,T1);
end

Подтвердите измененную функцию

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

buildInstrumentedMex fir_filt_circ_buff_typed_entry_point -args {b, x(:,1), reset}

y1 = fir_filt_circ_buff_typed_test(b,x);
fir_filt_circ_buff_plot2(3,titles,t,x,y0,y1)

Предложите типы данных от журналов min симуляции / макс. журналов

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

showInstrumentationResults fir_filt_circ_buff_original_entry_point_mex ...
    -defaultDT numerictype(1,16) -proposeFL

В оснащенном Отчете Генерации кода выберите функцию fir_filt_circ_buff_original и вкладка Variables, чтобы видеть эти результаты.

Составьте таблицу фиксированных точек

Используйте предложенные типы из Отчета Генерации кода вести вас в выборе фиксированных точек и составить таблицу фиксированных точек с помощью структуры с прототипами для переменных.

Используйте свое знание алгоритма, чтобы изменить к лучшему предложения. Например, вы используете acc переменную в качестве аккумулятора, поэтому сделайте ее 32 битами. Из Отчета Генерации кода вы видите, что acc нужны по крайней мере 2 целочисленных бита, чтобы предотвратить переполнение, таким образом, устанавливает дробную длину на 30.

Переменная p используется в качестве индекса, таким образом, можно сделать ее встроенным 16-битным целым числом.

Задайте прототипные значения как пустые ([]), поскольку типы данных используются, но не значения.

function T = fir_filt_circ_buff_fixed_point_types()
    T.acc=fi([],true,32,30);
    T.b=fi([],true,16,17);
    T.p=int16([]);
    T.x=fi([],true,16,14);
    T.y=fi([],true,16,14);
    T.z=fi([],true,16,14);
end

Добавьте фиксированную точку в функцию точки входа

Добавьте вызов таблицы фиксированных точек в функции точки входа:

T2 = fir_filt_circ_buff_fixed_point_types();
persistent z2 p2
if isempty(z2) || reset
    p2 = cast(0,'like',T2.p);
    z2 = zeros(size(b),'like',T2.z);
end
b2 = cast(b,'like',T2.b);
x2 = cast(x,'like',T2.x);
[y2,z2,p2] = fir_filt_circ_buff_typed(b2,x2,z2,p2,T2);

Создайте и запустите алгоритм с типами данных с фиксированной точкой

buildInstrumentedMex fir_filt_circ_buff_typed_entry_point -args {b, x(:,1), reset}

[y1,y2] = fir_filt_circ_buff_typed_test(b,x);

showInstrumentationResults fir_filt_circ_buff_typed_entry_point_mex

Видеть эти результаты в оснащенном Отчете Генерации кода:

  • Выберите функцию точки входа, fir_filt_circ_buff_typed_entry_point

  • Выберите fir_filt_circ_buff_typed в следующей строке кода:

[y2,z2,p2] = fir_filt_circ_buff_typed(b2,x2,z2,p2,T2);
  • Выберите вкладку Variables

16-битный размер слова, математика полной точности

Подтвердите это, результаты в приемлемом допуске вашей базовой линии.

fir_filt_circ_buff_plot2(4,titles,t,x,y1,y2);

Ваш алгоритм был теперь преобразован в фиксированную точку код MATLAB. Если вы также хотите преобразовать в код С, затем перейти к следующему разделу.

Сгенерируйте код С

В этом разделе описывается сгенерировать эффективный код С от фиксированной точки код MATLAB от предыдущего раздела.

Необходимые продукты

Вам нужен MATLAB Coder™, чтобы сгенерировать код С, и вам нужен Embedded Coder® для настроек аппаратной реализации, используемых в этом примере.

Алгоритм настраивается для самого эффективного кода С

Выходная переменная y инициализируется к нулям, и затем полностью перезаписывается, прежде чем она будет использоваться. Поэтому заполнение y со всеми нулями является ненужным. Можно использовать функцию coder.nullcopy, чтобы объявить переменную, на самом деле не заполняя его значениями, который делает код в этом случае более эффективным. Однако необходимо быть очень осторожными при использовании coder.nullcopy, потому что, если вы получаете доступ к элементу переменной, прежде чем он будет присвоен, затем вы получаете доступ к неинициализированной памяти, и ее содержимое непредсказуемо.

Эмпирическое правило для того, когда использовать coder.nullcopy, - когда инициализация занимает время по сравнению с остальной частью алгоритма. Если вы не уверены, то самая безопасная вещь сделать не состоит в том, чтобы использовать его.

function [y,z,p] = fir_filt_circ_buff_typed_codegen(b,x,z,p,T)
    % Use coder.nullcopy only when you are certain that every value of
    % the variable is overwritten before it is used.
    y = coder.nullcopy(zeros(size(x),'like',T.y));
    nx = length(x);
    nb = length(b);
    for n=1:nx
        p(:)=p+1; if p>nb, p(:)=1; end
        z(p) = x(n);
        acc = cast(0,'like',T.acc);
        k = p;
        for j=1:nb
            acc(:) = acc + b(j)*z(k);
            k(:)=k-1; if k<1, k(:)=nb; end
        end
        y(n) = acc;
    end
end

Нативные типы кода С

Можно установить математические свойства фиксированной точки совпадать с нативными действиями C. Это генерирует самый эффективный код С, но этот пример показывает, что это может создать проблемы с переполнением и привести к менее точным результатам, которые корректируются в следующем разделе. Это не всегда создает проблемы, тем не менее, таким образом, стоит попытаться сначала видеть, можно ли получить самый чистый код С.

Установите математические свойства фиксированной точки использовать округление пола и перенести переполнение, потому что те - действия по умолчанию в C.

Установите математические свойства фиксированной точки продуктов и сумм совпадать с собственным компонентом К 32-битные целочисленные типы и сохранять младшие значащие биты (LSBs) математических операций.

Добавьте эти настройки в таблицу фиксированных точек.

function T = fir_filt_circ_buff_dsp_types()
    F = fimath('RoundingMethod','Floor',...
               'OverflowAction','Wrap',...
               'ProductMode','KeepLSB',...
               'ProductWordLength',32,...
               'SumMode','KeepLSB',...
               'SumWordLength',32);
    T.acc=fi([],true,32,30,F);
    T.p=int16([]);
    T.b=fi([],true,16,17,F);
    T.x=fi([],true,16,14,F);
    T.y=fi([],true,16,14,F);
    T.z=fi([],true,16,14,F);
end

Протестируйте нативные типы кода С

Добавьте вызов таблицы типов в функции точки входа и запустите тестовый файл.

[y1,y2,y3] = fir_filt_circ_buff_typed_test(b,x); %#ok<*ASGLU>

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

fir_filt_circ_buff_plot2(5,titles,t,x,y1,y3);

Масштабируемый Дважды вводит, чтобы найти переполнение

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

Измените типы данных в двойной масштабированный, и добавьте эти настройки в масштабированную дважды таблицу типов.

function T = fir_filt_circ_buff_scaled_double_types()
    F = fimath('RoundingMethod','Floor',...
               'OverflowAction','Wrap',...
               'ProductMode','KeepLSB',...
               'ProductWordLength',32,...
               'SumMode','KeepLSB',...
               'SumWordLength',32);
    DT = 'ScaledDouble';
    T.acc=fi([],true,32,30,F,'DataType',DT);
    T.p=int16([]);
    T.b=fi([],true,16,17,F,'DataType',DT);
    T.x=fi([],true,16,14,F,'DataType',DT);
    T.y=fi([],true,16,14,F,'DataType',DT);
    T.z=fi([],true,16,14,F,'DataType',DT);
end

Добавьте вызов масштабированной дважды таблицы типов к функции точки входа и запустите тестовый файл.

[y1,y2,y3,y4] = fir_filt_circ_buff_typed_test(b,x); %#ok<*NASGU>

Покажите результаты инструментирования с масштабированными дважды типами.

showInstrumentationResults fir_filt_circ_buff_typed_entry_point_mex

Видеть эти результаты в оснащенном Отчете Генерации кода:

  • Выберите функцию точки входа, fir_filt_circ_buff_typed_entry_point

  • Выберите fir_filt_circ_buff_typed_codegen в следующей строке кода:

[y4,z4,p4] = fir_filt_circ_buff_typed_codegen(b4,x4,z4,p4,T4);
  • Выберите вкладку Variables.

  • Посмотрите на переменные в таблице. Ни одна из переменных не переполнилась, который указывает, что переполнение произошло как результат операции.

  • Наведите на операторы в отчете (+, - *, =).

  • Наведите на "+" в этой линии кода MATLAB в оснащенном Отчете Генерации кода:

acc(:) = acc + b(j)*z(k);

Отчет показывает что переполненная сумма:

Причина, которая переполненная сумма - то, что продукт полной точности для b (j) *z (k) производит numerictype (верный, 32,31), потому что b имеет numerictype (верный, 16,17) и z, имеет numerictype (верный, 16,14). Тип суммы собирается "сохранить младшие значащие биты" (KeepLSB), таким образом, сумма имеет numerictype (верный, 32,31). Однако 2 целочисленных бита необходимы, чтобы сохранить минимальные и максимальные симулированные значения-1.0045 и +1.035, соответственно.

Настройте, чтобы избежать переполнения

Установите дробную длину b к 16 вместо 17 так, чтобы b (j) *z (k) был numerictype (верный, 32,30), и таким образом, сумма также numerictype (верна, 32,30) после правила KeepLSB за суммы.

Оставьте все другие настройки тем же самым и установите

T.b=fi([],true,16,16,F);

Затем сумма в этой линии кода MATLAB больше не переполняется:

acc(:) = acc + b(j)*z(k);

Запустите тестовый файл с новыми настройками и постройте результаты.

[y1,y2,y3,y4,y5] = fir_filt_circ_buff_typed_test(b,x);

Вы видите, что переполнения избежали. Однако графики показывают смещение и большую ошибку из-за использования естественного округления пола К. Если это смещение приемлемо для вас, то можно остановиться здесь, и сгенерированный код C является очень чистым.

fir_filt_circ_buff_plot2(6,titles,t,x,y1,y5);

Устраните смещение

Если смещение не приемлемо в вашем приложении, то измените метод округления в 'Самый близкий', чтобы устранить смещение. Округление к самому близкому генерирует немного более сложный код С, но может быть необходимо для вас, если вы хотите устранить смещение и иметь меньшую ошибку.

Итоговая таблица фиксированных точек с самым близким округлением и настроенной содействующей длиной части:

function T = fir_filt_circ_buff_dsp_nearest_types()
    F = fimath('RoundingMethod','Nearest',...
               'OverflowAction','Wrap',...
               'ProductMode','KeepLSB',...
               'ProductWordLength',32,...
               'SumMode','KeepLSB',...
               'SumWordLength',32);
    T.acc=fi([],true,32,30,F);
    T.p=int16([]);
    T.b=fi([],true,16,16,F);
    T.x=fi([],true,16,14,F);
    T.y=fi([],true,16,14,F);
    T.z=fi([],true,16,14,F);
end

Вызовите эту таблицу типов от функции точки входа и запустите и постройте выход.

[y1,y2,y3,y4,y5,y6] = fir_filt_circ_buff_typed_test(b,x);
fir_filt_circ_buff_plot2(7,titles,t,x,y1,y6);

Команда генерации кода

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

function fir_filt_circ_buff_build_function()
    %
    % Declare input arguments
    %
    T = fir_filt_circ_buff_dsp_nearest_types();
    b = zeros(1,12,'like',T.b);
    x = zeros(256,1,'like',T.x);
    z = zeros(size(b),'like',T.z);
    p = cast(0,'like',T.p);
    %
    % Code generation configuration
    %
    h = coder.config('lib');
    h.PurelyIntegerCode = true;
    h.SaturateOnIntegerOverflow = false;
    h.SupportNonFinite = false;
    h.HardwareImplementation.ProdBitPerShort = 8;
    h.HardwareImplementation.ProdBitPerInt = 16;
    h.HardwareImplementation.ProdBitPerLong = 32;
    %
    % Generate C-code
    %
    codegen fir_filt_circ_buff_typed_codegen -args {b,x,z,p,T} -config h -launchreport
end

Сгенерированный код C

Используя эти настройки, MATLAB Coder генерирует следующий код С:

void fir_filt_circ_buff_typed_codegen(const int16_T b[12], const int16_T x[256],
  int16_T z[12], int16_T *p, int16_T y[256])
{
  int16_T n;
  int32_T acc;
  int16_T k;
  int16_T j;
  for (n = 0; n < 256; n++) {
    (*p)++;
    if (*p > 12) {
      *p = 1;
    }
    z[*p - 1] = x[n];
    acc = 0L;
    k = *p;
    for (j = 0; j < 12; j++) {
      acc += (int32_T)b[j] * z[k - 1];
      k--;
      if (k < 1) {
        k = 12;
      }
    }
    y[n] = (int16_T)((acc >> 16) + ((acc & 32768L) != 0L));
  }
}

Запустите следующий код, чтобы восстановить глобальные состояния.

fipref(FIPREF_STATE);
clearInstrumentationResults fir_filt_circ_buff_original_entry_point_mex
clearInstrumentationResults fir_filt_circ_buff_typed_entry_point_mex
clear fir_filt_circ_buff_original_entry_point_mex
clear fir_filt_circ_buff_typed_entry_point_mex

Запустите следующий код, чтобы удалить временную папку.

tempdirObj.cleanUp;

Ссылки:

[1] Й. Р. Рагаццини и Л. А. Зэдех. "Анализ систем выборочных данных". \in: Транзакции американского Института Инженеров-электриков 71 (II) (1952), стр 225–234.

Для просмотра документации необходимо авторизоваться на сайте