Ручные лучшые практики преобразования фиксированной точки

Программное обеспечение Fixed-Point Designer™ помогает вам разработать и преобразовать свои алгоритмы в фиксированную точку. Разрабатываете ли вы просто алгоритмы фиксированной точки в MATLAB® или используете Fixed-Point Designer в сочетании с продуктами генерации кода MathWorks®, эти лучшые практики помогают вам добраться от типичного кода MATLAB до эффективной реализации фиксированной точки. Эти лучшые практики также покрыты этим вебинаром: Ручной Вебинар Лучшых практик Преобразования Фиксированной точки

Создайте тестовый файл

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

Оригинальный кодЛучшая практикаМодифицированный код
% TEST INPUT
x = randn(100,1);

% ALGORITHM
y = zeros(size(x));
y(1) = x(1);
for n=2:length(x)
  y(n)=y(n-1) + x(n);
end

% VERIFY RESULTS
yExpected=cumsum(x);
plot(y-yExpected)
title('Error')

Проблема

Генерация тестового воздействия и верификация результатов смешиваются с кодом алгоритма.

Фиксация

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

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

% TEST INPUT
x = randn(100,1);

% ALGORITHM
y = cumulative_sum(x);

% VERIFY RESULTS
yExpected = cumsum(x);
plot(y-yExpected)
title('Error')

Алгоритм в его собственной функции

function y = cumulative_sum(x)
  y = zeros(size(x));
  y(1) = x(1);
  for n=2:length(x)
    y(n) = y(n-1) + x(n);
  end
end

Можно использовать тестовый файл для:

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

  • Предложите типы данных с фиксированной точкой.

  • Сравните поведение версий фиксированной точки вашего алгоритма к базовой линии с плавающей точкой.

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

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

Используя Fixed-Point Designer, вы можете:

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

    • buildInstrumentedMex, который генерирует скомпилированный код С, который включает инструментирование журналирования.

    • showInstrumentationResults, который показывает результаты, регистрируемые оснащенным, скомпилированным кодом С.

    • clearInstrumentationResults, который очищает регистрируемое инструментирование, следует из памяти.

  • Ускорьте свои алгоритмы фиксированной точки путем создания файла MEX с помощью функции fiaccel.

Любые алгоритмы MATLAB, которые вы хотите к инструменту с помощью buildInstrumentedMex и любых алгоритмов фиксированной точки, что вы хотите ускорить использование fiaccel, должны выполнить требования генерации кода и правила. Чтобы просмотреть подмножество языка MATLAB, который поддерживается для генерации кода, смотрите Функции и Объекты, Поддержанные для Генерации кода C/C++ — Алфавитный список.

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

  • Добавьте прагму %#codegen в верхнюю часть вашего файла MATLAB. Анализатор кода MATLAB отмечает функции и построения, которые не доступны в подмножестве языка MATLAB, поддержанного для генерации кода. Этот совет появляется в режиме реального времени, когда вы редактируете свой код в редакторе MATLAB.

    Для получения дополнительной информации смотрите, что Контрольный код Использует Анализатор кода MATLAB.

  • Используйте инструмент Code Generation Readiness, чтобы сгенерировать статический отчет относительно вашего кода. Отчет идентифицирует вызовы функций и использования типов данных, которые не поддержаны для генерации кода. Чтобы сгенерировать отчет для функции, myFunction1, в командной строке, вводит coder.screener('myFunction1').

    Для получения дополнительной информации смотрите, что Контрольный код Использует Инструмент Готовности Генерации кода.

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

Прежде чем вы запустите свое преобразование фиксированной точки, идентифицируете, какие функции, используемые в вашем алгоритме, не поддерживаются для фиксированной точки. Рассмотрите, как вы можете заменить их или в противном случае изменить вашу реализацию, которая будет более оптимизирована для целевых процессоров. Например, вы можете должны быть найти (или записать ваше собственное) замены для функций как log2, fft и exp. Другие функции как sin, cos и sqrt могут поддержать фиксированную точку, но для лучшей эффективности, можно хотеть рассмотреть альтернативную реализацию как интерполяционная таблица или основанный на CORDIC алгоритм.

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

Оригинальный кодЛучшая практикаМодифицированный код
y = 1/exp(x);

Проблема

Функция exp() не задана для входных параметров фиксированной точки.

Фиксация

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

y = 1/exp(double(x));

Справьтесь с ростом бита управления и типами данных

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

Оригинальный кодЛучшая практика Модифицированный код
acc = 0;
for n = 1:numel(x)
  acc = acc + x(n);
end

Проблема

acc = acc + x(n) перезаписывает acc с acc + x(n). Когда вы используете все двойные типы, это поведение прекрасно. Однако, когда вы вводите типы данных с фиксированной точкой в своем коде, если acc перезаписывается, тип данных acc может измениться.

Фиксация

Чтобы сохранить исходный тип данных acc, присвойте в acc с помощью acc(:)=. Используя преобразованное в нижний индекс присвоение бросает значение правой стороны в совпадающий тип данных как acc и предотвращает рост разрядности.

acc = 0;
for n = 1:numel(x)
  acc(:) = acc + x(n);
end

Для получения дополнительной информации смотрите Рост разрядности Управления.

Отдельные определения типов из алгоритма

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

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

Разделить определения типов от вашего алгоритма:

  1. Когда переменная будет сначала задана, используйте cast(x,'like',y) или zeros(m,n,'like',y), чтобы бросить ее к вашему желаемому типу данных.

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

  3. Запустите свой код, соединенный с каждой таблицей, и посмотрите на результаты проверить связь.

Оригинальный кодЛучшая практикаМодифицированный код
% Algorithm
n = 128;
y = zeros(size(n));

Проблема

Тип данных по умолчанию в MATLAB является двойной точностью, с плавающей точкой.

Фиксация

  1. Используйте cast(...,'like',...) и zeros(...'like',...), чтобы программно задать типы, которые заданы в отдельной таблице.

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

  3. Добавьте один типы данных в свою таблицу, чтобы помочь проверить связь с вашим кодом.

% Algorithm
T = mytypes('double');
n = cast(128,'like',T.n);
y = zeros(size(n),'like',T.y);
function T = mytypes(dt)
  switch(dt)
    case 'double'
      T.n = double([]);
      T.y = double([]);
      
    case 'single'
      T.n = single([]);
      T.y = single([]);
  end
end

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

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

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

  • Улучшите удобочитаемость своего кода алгоритма.

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

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

Преобразуйте в фиксированную точку

Каковы ваши цели по преобразованию в фиксированную точку?

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

Создание и запуск оснащенной MEX-функции

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

Код алгоритма Тестовый файл
function [y,z] = myfilter(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
% Test inputs
b = fir1(11,0.25);
t = linspace(0,10*pi,256)';
x = sin((pi/16)*t.^2);  % Linear chirp
z = zeros(size(b'));

% Build
buildInstrumentedMex myfilter ...
  -args {b,x,z} -histogram

% Run
[y,z] = myfilter_mex(b,x,z);

% Show
showInstrumentationResults myfilter_mex ...
  -defaultDT numerictype(1,16) -proposeFL

Создайте таблицу типов

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

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

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

Код алгоритмаТаблицы типовТестовый файл
function [y,z]=myfilter(b,x,z,T)
  y = zeros(size(x),'like',T.y);
  for n = 1:length(x)
    z(:) = [x(n); z(1:end-1)];
    y(n) = b * z;
  end
end
function T = mytypes(dt)
  switch dt
    case 'double'
      T.b = double([]);
      T.x = double([]);
      T.y = double([]);

     case 'fixed16'
      T.b = fi([],true,16,15);
      T.x = fi([],true,16,15);
      T.y = fi([],true,16,14);
  end
end
% Test inputs
b = fir1(11,0.25);
t = linspace(0,10*pi,256)';
x = sin((pi/16)*t.^2); 
% Linear chirp

% Cast inputs
T=mytypes('fixed16');
b=cast(b,'like',T.b);
x=cast(x,'like',T.x);
z=zeros(size(b'),'like',T.x);

% Run
[y,z] = myfilter(b,x,z,T);

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

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

Оптимизируйте типы данных

Используйте масштабированный, удваивается

Используйте масштабируемый, удваивается, чтобы обнаружить потенциальное переполнение. Масштабируемый удваивается, гибрид между числами и фиксированной точки с плавающей точкой. Fixed-Point Designer хранит их, как удваивается с масштабированием, знаком и сохраненной информацией о размере слова. Использовать масштабируемый удваивается, можно использовать свойство переопределения типа данных (DTO), или можно установить свойство 'DataType' на 'ScaledDouble' в конструкторе numerictype или fi.

К...Использование...Пример

Установите переопределение типа данных локально

Свойство numerictype DataType

T.a = fi([],1,16,13,'DataType', 'ScaledDouble');
a = cast(pi, 'like', T.a)
a =
    3.1416

   DataTypeMode: Scaled double: binary point scaling
           Signedness: Signed
         WordLength: 16
     FractionLength: 13

Установите переопределение типа данных глобально

Свойство fipref DataTypeOverride

fipref('DataTypeOverride','ScaledDoubles')
T.a = fi([],1,16,13);
a =
  3.1416

  DataTypeMode:Scaled double: binary point scaling
    Signedness: Signed
    WordLength:16
FractionLength:13

Для получения дополнительной информации смотрите Масштабированный, Удваивается.

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

Чтобы подстроить настройки фиксированной точки, запустите функцию buildInstrumentedMex с флагом –histogram и затем запустите сгенерированную MEX-функцию с вашими желаемыми тестовыми воздействиями. Когда вы используете showInstrumentationResults, чтобы отобразить отчет генерации кода, отчет отображает Иконку гистограммы. Кликните по значку, чтобы открыть NumericTypeScope и просмотреть распределение значений, наблюдаемых в вашей симуляции для выбранной переменной.

Переполнение, обозначенное в красном в Отчете Генерации кода, показывает во "вне области значений" интервал в NumericTypeScope. Запустите NumericTypeScope для связанной переменной или выражения путем нажатия на значок представления гистограммы.

Исследуйте компромиссы проекта

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

Код алгоритмаТаблицы типовТестовый файл
function [y,z] = myfilter(b,x,z,T)
  y = zeros(size(x),'like',T.y);
  for n = 1:length(x)
    z(:) = [x(n); z(1:end-1)];
    y(n) = b * z;
  end
end
function T = mytypes(dt)
  switch dt
    case 'double'
      T.b = double([]);
      T.x = double([]);
      T.y = double([]);

    case 'fixed8'
      T.b = fi([],true,8,7);
      T.x = fi([],true,8,7);
      T.y = fi([],true,8,6);

    case 'fixed16'
      T.b = fi([],true,16,15);
      T.x = fi([],true,16,15);
      T.y = fi([],true,16,14);
  end
end
function mytest
  % Test inputs
  b = fir1(11,0.25);
  t = linspace(0,10*pi,256)';
  x = sin((pi/16)*t.^2);  % Linear chirp
  
  % Run
  y0  = entrypoint('double',b,x);
  y8  = entrypoint('fixed8',b,x);
  y16 = entrypoint('fixed16',b,x);
  
  % Plot
  subplot(3,1,1)
  plot(t,x,'c',t,y0,'k')
  legend('Input','Baseline output')
  title('Baseline')
         
  subplot(3,2,3)
  plot(t,y8,'k')
  title('8-bit fixed-point output')
  subplot(3,2,4)
  plot(t,y0-double(y8),'r')
  title('8-bit fixed-point error')

  subplot(3,2,5)
  plot(t,y16,'k')
  title('16-bit fixed-point output')
  xlabel('Time (s)')
  subplot(3,2,6)
  plot(t,y0-double(y16),'r')
  title('16-bit fixed-point error')
  xlabel('Time (s)')
end

function [y,z] = entrypoint(dt,b,x)
  T = mytypes(dt);
  b = cast(b,'like',T.b);
  x = cast(x,'like',T.x);
  z = zeros(size(b'),'like',T.x);
  [y,z] = myfilter(b,x,z,T);
end

Оптимизируйте свой алгоритм

Используйте fimath, чтобы Получить Естественные Типы для C или HDL

Свойства fimath задают правила для выполнения арифметических операций на объектах fi, включая математику, округление и свойства переполнения. Можно использовать свойства fimath ProductMode и SumMode сохранить естественные типы данных для C и HDL. Установка KeepLSB для моделей ProductMode и SumMode поведение целочисленных операций на языке C, в то время как модели KeepMSB поведение многих устройств DSP. Различные методы округления требуют различных сумм служебного кода. Установка свойства RoundingMethod к Floor, который эквивалентен дополнительному усечению two, обеспечивает самую эффективную реализацию округления. Точно так же стандартный метод для обработки переполнения состоит в том, чтобы перенести использование арифметика по модулю. Другие методы обработки переполнения создают дорогостоящую логику. Каждый раз, когда возможно, устанавливает OverflowAction на Wrap.

КОД MATLABЛучшая практикаСгенерированный код C
% Code being compiled

function y = adder(a,b)
  y = a + b;
end

With types defined with
default fimath settings:

T.a = fi([],1,16,0);
T.b = fi([],1,16,0);

a = cast(0,'like',T.a);
b = cast(0,'like',T.b);

Проблема

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

int adder(short a, short b)
{
  int y;
  int i0;
  int i1;
  int i2;
  int i3;
  i0 = a;
  i1 = b;
  if ((i0 & 65536) != 0) {
    i2 = i0 | -65536;
  } else {
    i2 = i0 & 65535;
  }

  if ((i1 & 65536) != 0) {
    i3 = i1 | -65536;
  } else {
    i3 = i1 & 65535;
  }

  i0 = i2 + i3;
  if ((i0 & 65536) != 0) {
    y = i0 | -65536;
  } else {
    y = i0 & 65535;
  }

  return y;
}

Код скомпилирован

function y = adder(a,b)
  y = a + b;
end

С типами, заданными с fimath настройками, которые совпадают с вашими типами процессора:

F = fimath(...
 'RoundingMethod','Floor', ...
 'OverflowAction','Wrap', ...
 'ProductMode','KeepLSB', ...
 'ProductWordLength',32, ...
 'SumMode','KeepLSB', ...
 'SumWordLength',32);

T.a = fi([],1,16,0,F);
T.b = fi([],1,16,0,F);
a = cast(0,'like',T.a);
b = cast(0,'like',T.b);

Фиксация

Чтобы сделать сгенерированный код более эффективным, выберите математические настройки фиксированной точки, которые совпадают с вашими типами процессора.

int adder(short a, short b)
{
  return a + b;
}

Замените встроенные функции на более эффективные реализации фиксированной точки

Некоторые встроенные функции MATLAB могут быть сделаны более эффективными для реализации фиксированной точки. Например, можно заменить встроенную функцию на реализацию Интерполяционной таблицы или реализацию CORDIC, которая требует только итеративных операций shift-add.

Повторно реализуйте операции деления, где возможно

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

  • Используйте перемену бита, когда знаменатель будет степенью двойки. Например, bitsra(x,3) вместо x/8.

  • Умножьтесь инверсией, когда знаменатель будет постоянным. Например, x*0.2 вместо x/5.

Устраните переменные с плавающей точкой

Для более эффективного кода устраните переменные с плавающей точкой. Одним исключением к этому являются индексы цикла, потому что они обычно становятся целочисленными типами.