Программное обеспечение 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».
Используйте инструмент Генерации кода Readiness, чтобы сгенерировать статический отчет по коду. Отчет определяет вызовы функций и использование типов данных, которые не поддерживаются для генерации кода. Чтобы сгенерировать отчет для функции, myFunction1
, в командной строке введите coder.screener('myFunction1')
.
Для получения дополнительной информации смотрите Проверить код Используя Инструмент готовности Генерации кода.
Прежде чем вы начнете преобразование с фиксированной точкой, идентифицируете, какие функции, используемые в вашем алгоритме, не поддерживаются для фиксированной точки. Рассмотрим, как вы можете заменить их или иным образом изменить свою реализацию, чтобы быть более оптимизированной для целевых процессоров. Например, вам может потребоваться найти (или написать свои собственные) замены для таких функций, как log2
, fft
, и exp
. Другие функции, такие как sin
, cos
, и sqrt
может поддерживать фиксированную точку, но для большей эффективности, вы можете захотеть рассмотреть альтернативную реализацию, такую как интерполяционная таблица или основанный на CORDIC алгоритм.
Если вы не можете найти замену немедленно, можно продолжить преобразование остальной части алгоритма в фиксированную точку, просто изолировав любые функции, которые не поддерживают фиксированную точку с помощью приведения к двойному значению на входе и приведения к типу фиксированной точки на выходе.
Оригинальный код | Лучшие практики | Модифицированный код |
---|---|---|
y = 1/exp(x); | Проблема Зафиксировать Приведите вход к удвоению, пока у вас не будет замены. В этом случае |
y = 1/exp(double(x)); |
Синтаксис (:) = известен как назначение под индексом. При использовании этого синтаксиса MATLAB перезаписывает значение левостороннего аргумента, но сохраняет существующий тип данных и размер массива. Это особенно важно для сохранения фиксированной точки переменных с фиксированной точкой (в отличие от непреднамеренного превращения их в двойные значения) и для предотвращения роста разрядности, когда вы хотите поддерживать конкретный тип данных для выхода.
Оригинальный код | Лучшие практики | Модифицированный код |
---|---|---|
acc = 0; for n = 1:numel(x) acc = acc + x(n); end | Проблема
Зафиксировать Чтобы сохранить исходный тип данных |
acc = 0; for n = 1:numel(x) acc(:) = acc + x(n); end |
Для получения дополнительной информации смотрите Управление Ростом разрядности.
Для инструментирования и генерации кода создайте функцию точки входа, которая вызывает функцию, которую вы хотите преобразовать в фиксированную точку. Затем можно привести входные параметры функции к различным типам данных. Для сравнения можно добавить вызовы в различные изменения функции. При помощи функции точки входа можно запустить как варианты алгоритма с фиксированной точкой, так и с плавающей точкой. Можно также запустить различные варианты фиксированной точки. Этот подход позволяет вам итерировать на коде быстрее, чтобы прийти к оптимальному проекту с фиксированной точкой.
Этот метод преобразования с фиксированной точкой облегчает для вас сравнение нескольких различных реализаций с фиксированной точкой, а также позволяет вам легко перенастроить алгоритм на другое устройство.
Чтобы отделить определения типов данных от вашего алгоритма:
Когда переменная впервые задана, используйте cast(x,'like',y)
или zeros(m,n,'like',y)
чтобы привести его к требуемому типу данных.
Составьте таблицу определений типов данных, начиная с исходных типов данных, используемых в вашем коде. Перед преобразованием в фиксированную точку создайте таблицу типов данных, которая использует все отдельные типы данных для поиска несоответствий типов и других проблем.
Запустите код, подключенный к каждой таблице, и проверьте результаты, чтобы проверить подключение.
Оригинальный код | Лучшие практики | Модифицированный код |
---|---|---|
% Algorithm
n = 128;
y = zeros(size(n));
| Проблема Тип данных по умолчанию в MATLAB является с двойной точностью с плавающей точностью. Зафиксировать
|
% 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-функцию, чтобы получить предложения по фиксированным точкам с помощью buildInstrumentedMex
и showInstrumentationResults
функций. Тестовые файлы должны использовать ваш алгоритм в полной рабочей области значений. Качество предлагаемых типов данных с фиксированной точкой зависит от того, насколько хорошо тестовый файл покрывает рабочую область значений алгоритма с точностью, которую вы хотите. Простой набор тестовых векторов может не использовать всюсь область значений типов, поэтому используйте предложения как руководство для выбора начального набора фиксированных точек и используйте свое лучшее суждение и опыт в корректировке типов. Если индексы цикла используются только в качестве индексных переменных, они автоматически преобразуются в целые типы, поэтому вы не должны явно преобразовывать их в фиксированную точку.
Код алгоритма | Тестовый файл |
---|---|
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 сохраняет их как двойные с сохраненной информацией о масштабировании, знаке и размере слова. Чтобы использовать масштабированные двойки, можно использовать свойство override типа данных (DTO) или можно задать 'DataType'
свойство к 'ScaledDouble'
в fi
или numerictype
конструктор.
Кому... | Использовать... | Пример |
---|---|---|
Локально переопределите тип данных |
|
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','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
свойства определяют правила для выполнения арифметических операций над fi
объекты, включая математические, округляющие и переполненные свойства. Можно использовать fimath
ProductMode
и SumMode
свойства для сохранения естественных типов данных для C и HDL. The KeepLSB
настройка для ProductMode
и SumMode
моделирует поведение целочисленных операций в языке C, в то время как KeepMSB
моделирует поведение многих устройств DSP. Различные методы округления требуют различных объемов служебного кода. Установка RoundingMethod
свойство к Floor
, что эквивалентно усечению двух комплементов, обеспечивает наиболее эффективную реализацию округления. Точно так же стандартным методом для обработки переполнений является обертывание с использованием арифметики по модулю. Другие методы обработки переполнения создают дорогостоящую логику. По возможности установите 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 i; int i1; int i2; int i3; i = a; i1 = b; if ((i & 65536) != 0) { i2 = i | -65536; } else { i2 = i & 65535; } if ((i1 & 65536) != 0) { i3 = i1 | -65536; } else { i3 = i1 & 65535; } i = i2 + i3; if ((i & 65536) != 0) { y = i | -65536; } else { y = i & 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
.
Для более эффективного кода устраните переменные с плавающей точкой. Единственным исключением для этого являются индексы цикла, потому что они обычно становятся целыми типами.