技术文章和通讯

将MATLAB代码转换为定点的最佳实践

由Harshita Bhurat汤姆•布莱恩和茱莉亚的墙上,MathWorks


转换浮点实现定点时,工程师必须确定最佳的定点数据类型,满足嵌入式硬件的限制,数值精度满足系统要求。定点设计师™帮助您开发定点算法和浮点算法转换为定点通过自动提出数据类型和定点属性和启用bit-true定点和浮点仿真结果的比较基准。

本文概述了MATLAB做准备的最佳实践®代码转换,将MATLAB代码转换为定点,和优化算法的效率和性能。无论你是设计定点算法在MATLAB在准备手动或转换为代码生成定点,这些最佳实践将帮助您将通用的MATLAB代码转化成一种有效的定点实现。

准备定点转换代码

有三个步骤可以确保顺利转换过程:

  • 你的核心算法与其他代码分离。
  • 准备你的代码插装和加速度。
  • 检查你使用定点支持功能。金宝app

核心算法与其他MATLAB代码分离

通常,一个算法是伴随着代码,设置输入数据和代码创建的情节来验证结果。因为只有算法代码需要转换成固定的点,它是更高效的代码结构,以便创建一个测试文件输入,调用的核心算法,和情节结果和算法的文件执行核心处理(表1)。

原始代码
%测试输入x = randn (100 1);%的算法y = 0(大小(x));y = x (1) (1);n = 2:长度(x) (n) = y (n - 1) + x (n);结束%验证结果yExpected = cumsum (x);情节(y-yExpected)标题(“错误”)
修改后的代码

测试文件。

%测试输入x = randn (100 1);%的算法y = cumulative_sum (x);%验证结果yExpected = cumsum (x);情节(y-yExpected)标题(“错误”)

算法文件。

函数y = cumulative_sum (x) y = 0(大小(x));y = x (1) (1);n = 2:长度(x) (n) = y (n - 1) + x (n);结束结束

准备仪器和加速算法的代码

仪表和加速度帮助简化转换过程。您可以使用定点设计师仪器代码和日志的最大和最小值和中间变量命名。该工具可以使用这些记录值提出数据类型用于定点代码。

与定点设计师还可以加速你的定点算法通过创建一个墨西哥人文件,和加快模拟验证定点实现所需的原始版本。

仪表和加速度都依赖代码生成技术,所以您可以使用它们之前你必须准备你的算法代码生成,即使你不打算使用MATLAB编码器™或高密度脂蛋白编码器™生成C或HDL代码。首先,在MATLAB代码识别功能或结构不支持代码生成(见金宝app语言支持金宝app支持函数和对象的列表)。金宝app

有两种方法来自动化这一步骤:

  • 添加% # codegen编译指示的MATLAB文件包含你的核心算法代码。这个编译指示指示代码分析器标记功能和结构不包括MATLAB语言子集的支持代码生成。金宝app
  • 使用代码生成工具准备产生一个报告,该报告将调用函数和数据类型不受支持的使用代码生成。金宝app

一旦你已经准备好你的代码生成算法,您可以使用定点设计师仪器和加速。使用buildInstrumentedMex使仪器日志最大和最小值的命名和中间变量,和使用showInstrumentationResults查看代码生成报告提出数据类型用于定点代码。调用fiaccel翻译你的MATLAB算法到墨西哥人文件并加速你的定点仿真。

检查定点支持函数用于算法代码金宝app

如果你确定一个函数不支持固定的点,你有三个选择:金宝app

  • 换上一定点的函数等价的。
  • 编写自己的等效功能。
  • 隔离的不支持的功能与双输入,和金宝app演员回到定点类型输出。

你可以继续将代码转换为定点,并返回到不支持的功能,当你有一个合适的替代(表2)。金宝app

原始代码
y = 1 / exp (x);
修改后的代码
y = 1 / exp(双(x));

管理数据类型和控制增长

在定点实现中,定点变量必须保持不动点,而不是无意中变成双打。它也是很重要的防止一些增长。例如,考虑下面的代码:

y = y + x (n)

这个语句覆盖y的值y + x (n)。当你引入定点数据类型代码,y可能会改变数据类型覆盖时,有可能导致一些增长。

保存的数据类型y使用(,)=语法(表3)。这个语法,被称为下标赋值,指示MATLAB保留覆盖现有的数据类型和数组大小的变量。该声明(,)= y + x (n)会把眼睛水平的价值y的原始数据类型和防止一些增长。

原始代码
y = 0;n = 1:长度(x) y = y + x (n);结束
修改后的代码
y = 0;n = 1:长度(x) y (:) = y + x (n);结束

创建一个类型表分离数据类型定义算法代码

从算法分离数据类型定义代码使其更容易比较定点实现和gdp8 %你的算法不同的设备。

应用此最佳实践,请执行以下操作:

  1. 使用铸造(x,“喜欢”,y)0 (m, n,“喜欢”,y)把一个变量所需的数据类型时,第一个定义。
  2. 开始,创建一个表的数据类型定义中使用的原始数据类型code-typically,在MATLAB中双精度浮点,默认数据类型(表4)。
  3. 之前转换为定点,添加数据类型的类型表找到类型不匹配和其他问题(表4 b)。
  4. 验证连接通过运行代码连接到每个表有不同的数据类型和比较结果。
原始代码
%的算法n = 128;y = 0(大小(x));
修改后的代码
%的算法T = mytypes (“双”);n =投(128“喜欢”,T.n);y = 0(大小(x),“喜欢”,T.y);%类型表函数T = mytypes (dt)开关(dt)情况下“双”T。双(n = []);T。y= double([]);结束结束
原始代码
%类型表函数T = mytypes (dt)开关(dt)情况下“双”T。双(n = []);T。y= double([]);结束结束
修改后的代码
函数T = mytypes (dt)开关(dt)情况下“双”T。双(n = []);T。y= double([]);情况下“单一”T。n =单([]);T。y= single([]);结束结束

定点条目添加到类型表

一旦您创建了一个表的数据类型定义,您可以添加定点类型基于你的目标转换成固定的点。例如,如果你计划来实现算法在C语言中,这个词的长度为定点类型将限制16的倍数。另一方面,如果你计划在高密度脂蛋白,实现单词长度没有限制。

得到一组定点类型的代码,建议使用定点设计师命令buildInstrumentedMexshowInstrumentationResults(表5)。你需要一组测试向量练习定点设计师提出的所有类型的类型只是测试输入一样好。很长一段模拟运行与广泛的预期数据会产生更好的建议。选择一组初始的定点类型从代码生成的建议报告(图1)。

图1所示。代码生成的报告由showInstrumentationResults与滤波算法提出了变量的数据类型。
图1所示。代码生成的报告由showInstrumentationResults与滤波算法提出了变量的数据类型。

然后您可以调整提出必要的类型(表5和6)。

算法代码
函数[y, z] = myfilter (b, x, z) y = 0(大小(x));n = 1:长度(x) z (:) = [x (n);z (1:结束1)];y (n) = b * z;结束结束
测试文件
%测试输入0.25 b = fir1(11日);t = linspace(0, 10 *π,256);x =罪((π/ 16)* t。^ 2);%线性啁啾z = 0(大小(b));%建立buildInstrumentedMexmyfilter……args {b, x, z}直方图运行%[y, z] = myfilter_mex (b, x, z);%显示showInstrumentationResultsmyfilter_mex……-proposeFL -defaultDT numerictype (16)

表5所示。插装的滤波算法和测试脚本,执行代码,提出定点类型变量。

算法代码
函数[y, z] = myfilter (b, x, z, T) y = 0(大小(x),“喜欢”,T.y);n = 1:长度(x) z (:) = [x (n);z (1:结束1)];y (n) = b * z;结束结束
测试文件
%测试输入0.25 b = fir1(11日);t = linspace(0, 10 *π,256);x =罪((π/ 16)* t。^ 2);%线性啁啾%将输入T = mytypes (“fixed16”);b =投(b,“喜欢”、肺结核);x =投(x,“喜欢”,T.x);z = 0(大小(b),“喜欢”,T.x);运行%[y, z] = myfilter (b, x, z, T);
类型表
函数T = mytypes (dt)开关dt情况下“双”T。b =双([]);T。双(x = []);T。y= double([]);情况下“fixed16”T。b = fi(15)[],真的,16日;T。x = fi([],真的,16日15);T。y= fi([],true,16,14);结束结束

表6所示。表4的测试脚本和滤波算法更新定点数据类型。

与新定点类型和运行您的算法比较其输出与基线算法的输出。

优化数据类型

无论你选择你自己的定点数据类型或使用这些提出的定点设计师,寻找机会来优化这个词长度,长度比例,signedness,甚至数学模式(fimath)。你可以通过使用扩展双打,查看变量值的直方图,或测试不同类型数据类型表。

使用缩放双打来检测潜在的溢出

按比例缩小的双打混合动力车的浮点和定点数字。定点设计师商店扩展双打双打与扩展,标志和字长信息保留。使用缩放双打,设置数据类型覆盖(DTO)属性(表7)。

DTO设置 例子
DTO设置本地使用numerictype
数据类型的属性
> > T。= fi([], 1, 16日13日“数据类型”,“ScaledDouble”);> > =投(π,“喜欢”T.a) = 3.1416 DataTypeMode:扩展双:二进制扩展Signedness:签了字:16 FractionLength: 13
DTO设置在全球范围内使用fipref
“DataTypeOverride”属性
> > fipref (“DataTypeOverride”,“ScaledDoubles”);> > T。一个= fi(13)[], 16日;> > =投(π,“喜欢”T.a) = 3.1416 DataTypeMode:扩展双:二进制扩展Signedness:签了字:16 FractionLength: 13

表7所示。设置数据类型的方法在本地和全球覆盖属性。

使用buildInstrumentedMex你的代码和运行showInstrumentationResults查看结果。代码生成报告,价值观就会溢出用红色突出显示(图2)。

图2。代码生成报告显示使用了双打时溢出类型和直方图图标。
图2。代码生成报告显示溢出时使用了双打类型(左)和直方图图标(右)。

检查变量值的分布

您可以使用直方图来确定数据类型的值范围内,外范围,或低于精度。单击直方图图标来启动NumericTypeScope和视图观察值的分布仿真为选定的变量(图3)。

图3。直方图显示变量值的分布。
图3。柱状图显示分布的变量值,溢出条件(“外部范围”)用红色表示。

测试不同类型数据类型表

您可以添加自己的定点类型变化类型表(表8)。

算法代码
函数[y, z] = myfilter (b, x, z, T) y = 0(大小(x),“喜欢”,T.y);n = 1:长度(x) z (:) = [x (n);z (1:结束1)];y (n) = b * z;结束结束
测试文件
函数mytest%测试输入0.25 b = fir1(11日);t = linspace(0, 10 *π,256);x =罪((π/ 16)* t。^ 2);%线性啁啾运行%y0 =入口点(“双”x、b);日元=入口点(“fixed8”x、b);造成=入口点(“fixed16”x、b);%的阴谋次要情节(1,1);情节(t, x,“c”t y0,“k”);传奇(“输入”,“基准输出”)标题(“基线”)次要情节(3 2 3);情节(t,日元,“k”);标题(“8位定点输出”)次要情节(3、2、4);情节(t, y0-double(日元)“r”);标题(“8位定点误差”次要情节(3 2 5);情节(t,造成,“k”);标题(的16位定点输出)包含(“时间(s)”次要情节(3 2 6);情节(t, y0-double(造成),“r”);标题(的16位定点误差)包含(“时间(s)”)结束函数[y, z] =入口点(dt, b, x) T = mytypes (dt);b =投(b,“喜欢”、肺结核);x =投(x,“喜欢”,T.x);z = 0(大小(b),“喜欢”,T.x);[y, z] = myfilter (b, x, z, T);结束
类型表
函数T = mytypes (dt)开关dt情况下“双”T。b =双([]);T。双(x = []);T。y= double([]);情况下“fixed8”T。b = fi([],真的,8,7);T。x = fi([],真的,8,7);T。y= fi([],true,8,6);情况下“fixed16”T。b = fi(15)[],真的,16日;T。x = fi([],真的,16日15);T。y= fi([],true,16,14);结束结束

表8所示。测试脚本用于检查的效果使用不同的定点数据类型的类型表的过滤功能。

比较结果跨迭代每个变更后验证算法的准确性(图4)。

图4。情节的测试脚本在表8显示输出和错误转换成8位和16位定点类型。
图4。情节的测试脚本在表8显示输出和错误转换成8位和16位定点类型。

优化算法

有三种常见的方法来优化你的算法来提高性能和生成更高效的C代码。您可以:

  • 使用fimath属性来提高生成的代码的效率
  • 用更有效的定点实现替换内置函数
  • 重新实现部门操作

使用fimath属性来提高生成的代码的效率

当你使用默认fimath设置,生成额外的代码来实现饱和溢出,最近的舍入以及不能算术(表9)。

MATLAB代码
代码被编译:函数y =加法器(a, b) y = a + b;结束定义与类型默认fimath设置:T。= fi([], 1, 16日0);T。b = fi ([], 1, 0);=投(0,“喜欢”,T.a);b =投(0,“喜欢”、肺结核);
生成的C代码
整数加法器(短,短b) {int y;int钱数;int i1;int i2;int i3;i0 =一个;i1 = b;如果((i0 & 65536) ! = 0) {i2 = i0 | -65536;}其他的{i2 = i0 & 65535;}如果((i1 & 65536) ! = 0) {i3 = i1 | -65536;}其他的{i3 = i1 & 65535;}i0 = i2和i3;如果((i0 & 65536) ! = 0) {y = i0 | -65536;}其他的{y = i0 & 65535;}返回y;}

表9。原始的MATLAB代码和生成C代码默认fimath设置。

使生成的代码更高效,选择定点数学设置匹配您的处理器的类型。选择fimath属性数学,四舍五入,溢出定义的规则来执行算术运算fi对象(表9 b)。

MATLAB代码
代码被编译:函数y =加法器(a, b) y = a + b;结束fimath设置定义与类型相匹配的处理器类型:F = fimath (…“RoundingMethod”,“地板”,……“OverflowAction”,“包装”,……“ProductMode”,“KeepLSB”,……“ProductWordLength”32岁的……“SumMode”,“KeepLSB”,……“SumWordLength”、32);T。= fi([], 1, 16日0时,F);T。b = fi ([], 1, 16 0 F);=投(0,“喜欢”,T.a);b =投(0,“喜欢”、肺结核);
生成的C代码
整数加法器(短,短b) {返回a + b;}

表9 b。原始的MATLAB代码和生成C代码fimath设置处理器类型相匹配。

用定点实现替换内置函数

一些MATLAB函数可以实现更高效的定点实现所取代。例如,你可以换一个查找表实现或内置函数CORDIC实现,只需要迭代shift-add操作。

重新实现部门操作

部门业务往往不能完全由硬件支持,并可能导致缓慢的处理。金宝app当你的算法需要操作一个部门,考虑代之以一个更快的选择。如果分母是两个孩子的权力,使用移位;例如,使用bitsra (x, 3)而不是x / 8。如果分母是常数,乘以逆;例如,使用x * 0.2而不是x / 5

下一个步骤

将浮点代码转换为定点后通过应用这些最佳实践与定点设计师,花时间去彻底地测试您的定点实现使用一组可行的测试输入和比较bit-true仿真结果与浮点基线。

2014 - 92226 v00出版