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

由Harshita Bhurat, Tom Bryan和Julia Wall, MathWorks完成

当一个浮点执行转换为固定点,工程师必须找出满足嵌入式硬件的限制,同时满足对数值精度的系统要求最佳定点数据类型。定点设计师™可以帮助您通过自动提出数据类型和定点属性和启用位真定点仿真结果的比较与浮点基线开发定点算法和转换的浮点算法到定点。

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

准备规范定点转换

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

  • 从其他代码分离的核心算法。
  • 为插装和加速准备代码。
  • 检查你使用的定点配套功能。万博1manbetx

将核心算法与其他MATLAB代码分开

典型地,一种算法是伴随着代码,设置了输入数据和代码,创建图来验证结果。由于只有算法代码需要被转换为固定的点,它是更有效的,从而使测试文件创建输入,调用核心算法,和绘图的结果来构造码,和算法文件执行核心处理(表1)。

原始代码
%测试输入X = randn(100,1);%的算法Y =零(大小(X));Y(1)= X(1);对于N = 2:长度(X)Y(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 =零(大小(X));Y(1)= X(1);对于N = 2:长度(X)Y(N)= Y(N-1)+ X(N);年底结束

为插装和加速准备你的算法代码

仪表和加速有助于简化转换过程。可以使用定点设计器记录代码,并记录所有已命名变量和中间变量的最小值和最大值。该工具可以使用这些记录的值来建议在定点代码中使用的数据类型。

随着定点设计,您还可以通过创建一个MEX文件加速您的定点算法,并加快验证与原始版本的定点实现所需的模拟。

插装和加速都依赖于代码生成技术,因此在使用它们之前,您必须准备好用于代码生成的算法,即使您不打算使用MATLAB编码器™或HDL编码器™来生成C或HDL代码。首先,识别MATLAB代码中不支持代码生成的函数或构造(请参阅万博1manbetx语言支持万博1manbetx获取受支持的函数和对象列表)万博1manbetx。

有两种方法来自动此步骤:

  • 添加% # codegen杂注到MATLAB文件的顶部,包含您的核心算法代码。这个编译指示指示代码分析器标记代码生成支持的MATLAB语言子集中不包含的函数和构造。万博1manbetx
  • 使用代码生成准备工具生成一个报告,该报告标识对函数的调用和对代码生成不支持的数据类型的使用。万博1manbetx

一旦你已经准备好算法的代码生成,可以采用定点设计仪器和加速它。使用buildInstrumentedMex启用日志记录的最小和所有命名和中间变量的最大值,并使用仪器showInstrumentationResults查看与提出的数据类型在定点代码中使用的代码生成报告。调用fiaccel您的MATLAB算法转换成一个MEX文件,加快您的定点仿真。

检查算法代码中使用的函数的定点支持万博1manbetx

如果您发现不支持固定点的功能,你有三种选择:万博1manbetx

  • 将函数替换为定点等效函数。
  • 写出你自己的等价函数。
  • 将不受支持的函数与在输入处强制万博1manbetx转换为两倍,并在输出处强制转换回定点类型隔离。

然后,您可以继续你的代码到定点,并返回转换为不支持的功能,当你有一个合适的替代者(表2)。万博1manbetx

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

管理数据类型和控制位增长

在固定点实施方案,定点变量必须保持固定的点,而不是无意中变成了双打。这也是很重要防止一些增长。例如,考虑以下代码行:

Y = Y + X(N)

这个语句覆盖ÿ与价值y + x (n)。当你介绍的定点数据类型到你的代码,ÿ当它被覆盖,从而可能导致比特增长可能会改变的数据类型。

要保留的数据类型ÿ使用(,)=语法(表3)。这句法,被称为下标赋值,指示MATLAB保留已覆盖变量的现有数据类型和数组大小。该声明Y(:) = Y + X(N)将右侧的值转换为ÿ的原始数据类型和防止位成长。

原始代码
Y = 0;对于N = 1:长度(X)Y = Y + X(N);结束
修改代码
Y = 0;对于n=1:长度(x) y(:) = y + x(n);结束

创建一个类型表,将数据类型定义与算法代码分开

从算法的代码中分离数据类型定义可以更容易地比较定点实现和重新定位你的算法到不同的设备。

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

  1. 使用铸造(x,“喜欢”,y)0 (m, n,“喜欢”,y)将变量在首次定义时强制转换为所需的数据类型。
  2. 创建的数据类型定义表,从在代码 - 通常,双精度浮点,在MATLAB默认的数据类型(表4a)所用的原始数据类型。
  3. 在转换到定点之前,添加数据类型的类型表来查找类型不匹配和其他的问题(表4b)。
  4. 通过运行连接到具有不同数据类型的每个表的代码并比较结果来验证连接。
原始代码
%的算法N = 128;Y =零(大小(X));
修改代码
%的算法T = mytypes (“双”);n =投(128'喜欢',T.n);y = 0(大小(x),'喜欢',T.y);%类型表函数T = mytypes (dt)开关(DT)案件“双”T.N =双([]);T.y =双([]);结束结束
原始代码
%类型表函数T = mytypes (dt)开关(DT)案件“双”T.N =双([]);T.y =双([]);结束结束
修改代码
函数T = mytypes (dt)开关(DT)案件“双”T.N =双([]);T.y =双([]);案件'单'T。n =单([]);T。ÿ= single([]);结束结束

将定点条目添加到类型表

一旦你创建的数据类型定义的表格,你可以添加一个基于你的目标定点类型转换为固定点。例如,如果您计划实现用C你的算法,为您的定点类型的字长将被限制为16的倍数。另一方面,如果你计划在HDL来实现,字长度不受限。

为了得到一组为您的代码定点式的建议,使用定点设计师命令buildInstrumentedMexshowInstrumentationResults(表5)。您需要一组测试向量的是行使齐全的种类,通过对定点设计师提出的类型的好坏作为测试输入。长模拟运行具有广泛预期的数据会产生更好的建议。选择从所述码生成报告中的建议(图1)的初始集合定点类型的。

图1所示。由showInstrumentationResults生成的代码生成报告,该报告为过滤算法中的变量提供了建议的数据类型。

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

算法代码
函数[y,z] = myfilter(b,x,z) y = 0 (size(x));对于N = 1:长度(X)Z(:) = [X(N);Z(1:结束1)];y(n) = b * z;结束结束
测试文件
%测试输入B = FIR1(11,0.25);T = linspace(0,10 * PI,256)';X = SIN((PI / 16)* T ^ 2);%线性啁啾z = 0(大小(b));%建立buildInstrumentedMexmyfilter ... -args {B,X,Z} -histogram运行%[y, z] = myfilter_mex (b, x, z);% 表演showInstrumentationResultsmyfilter_mex ... -defaultDT numerictype(1,16)-proposeFL

表5所示。一种过滤算法和测试脚本,用于插装和执行代码,并为变量显示建议的定点类型。

算法代码
函数[Y,Z] = myfilter(B,X,Z,T)Y =零(大小(x)的'喜欢',T.y);对于N = 1:长度(X)Z(:) = [X(N);Z(1:结束1)];y(n) = b * z;结束结束
测试文件
%测试输入B = FIR1(11,0.25);T = linspace(0,10 * PI,256)';X = SIN((PI / 16)* T ^ 2);%线性啁啾%将输入T = mytypes ('fixed16');B =流延(B,'喜欢',T.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 =双([]);案件'fixed16'T。b = fi(15)[],真的,16日;T。x = fi([],真的,16日15);T。ÿ= fi([],true,16,14);结束结束

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

运行与新的定点类型的算法,其输出比较基准算法的输出。

优化数据类型

无论您是选择自己的定点数据类型,还是使用定点设计人员提出的数据类型,都要寻找机会优化单词长度、分数长度、符号性,甚至可能优化数学模式(fimath)。可以通过使用缩放双精度数、查看变量值的直方图或测试数据类型表中的不同类型来实现这一点。

使用缩放的加倍来检测潜在的溢出

按比例缩小的双打是浮点的杂交体和定点数。定点设计师商店缩放兼作与缩放,符号,和字长的信息双打保留。使用经缩放双打中,数据类型设置倍率(DTO)属性(表7)。

DTO设置 例子
DTO设置本地使用numerictype
数据类型的属性
>> T.A =音响([],1,16,13,'数据类型''ScaledDouble');>> A =铸造(PI,'喜欢',T.A)A = 3.1416 DataTypeMode:扩展的双:二进制点缩放符号性:签字字长:16 FractionLength:13
DTO全局设置使用fipref
“DataTypeOverride”属性
> > fipref ('DataTypeOverride''ScaledDoubles');> > T。a = fi([], 1, 16, 13);>> A =铸造(PI,'喜欢',T.A)A = 3.1416 DataTypeMode:扩展的双:二进制点缩放符号性:签字字长:16 FractionLength:13

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

使用buildInstrumentedMex运行你的代码,并showInstrumentationResults以查看结果。在代码生成报告,这将已经溢出值以红色突出显示(图2)。

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

检查变量值的分布

可以使用直方图来识别与有效范围内的值,范围之外,或低于精度数据类型。点击直方图图标启动NumericTypeScope并查看在你的模拟观察到所选择的变量(图3)的值的分布。

图3.直方图显示变量值的分布,具有一个溢出条件(“外范围”)以红色表示。

测试不同类型的数据中的类型表

您可以将您自己的定点类型变体添加到您的类型表(表8)中。

算法代码
函数[Y,Z] = myfilter(B,X,Z,T)Y =零(大小(x)的'喜欢',T.y);对于N = 1:长度(X)Z(:) = [X(N);Z(1:结束1)];y(n) = b * z;结束结束
测试文件
函数mytest%测试输入B = FIR1(11,0.25);T = linspace(0,10 * PI,256)';X = SIN((PI / 16)* T ^ 2);%线性啁啾运行%y0 =入口点(“双”x、b);日元=入口点('fixed8'x、b);Y16 =入口点('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-);图(吨,Y16,“k”);标题(的16位定点输出)包含(“时间(s)”次要情节(3 2 6);情节(t, y0-double(造成),'R');标题(的16位定点误差)包含(“时间(s)”结束函数[Y,Z] =入口点(DT,B,X)T = mytypes(DT);B =流延(B,'喜欢',T.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 =双([]);案件'fixed8'T。b = fi([],真的,8,7);T。x = fi([],真的,8,7);T。ÿ= fi([],true,8,6);案件'fixed16'T。b = fi(15)[],真的,16日;T。x = fi([],真的,16日15);T。ÿ= fi([],true,16,14);结束结束

表8试验脚本用于检查在用于过滤函数的类型的表使用不同的定点数据类型的影响。

比较迭代之间的结果,以验证每次更改后算法的准确性(图4)。

图4。表8中的测试脚本中的图显示了转换为8位和16位定点类型后的输出和错误。

优化算法

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

  • 使用fimath属性来提高生成代码的效率
  • 用更高效的定点实现替换内置函数
  • 重新实现除法运算

使用fimath性能,提高生成代码的效率

使用默认设置时fimath设置时,产生额外的代码来实现饱和度溢出,最近的舍入,和全精度算术(表9A)。

MATLAB代码
代码被编译:函数Y =加法器(A,B)Y = A + B;结束用默认设置fimath定义的类型:T。= fi([], 1, 16日0);T。b = fi ([], 1, 0);=投(0,'喜欢',T.a);b =投(0,'喜欢',T.b);
生成的C代码
INT加法器(短,短B){INTÿ;INT I0;INT I1;INT I2;INT I3;I 0 = A;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;}返回Ÿ;}

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

为了使生成的代码更有效,选择符合你的处理器的类型的定点运算的设置。选择fimath数学、舍入和溢出的属性,以定义在您的科幻对象(表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,'喜欢',T.b);
生成的C代码
INT加法器(短,短B){返回a + b;}

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

与定点实现更换内置函数

一些MATLAB函数可以被替换以实现更高效的定点实现。例如,您可以替换内置函数查找表实现或CORDIC实现,它只需要迭代的移位-添加操作。

重新实现除法运算

分区操作通常没有得到硬件的完全支持,并可能导致处理速度缓慢。万博1manbetx当你的算法需要除法运算时,考虑用更快的替代方法来代替它。如果分母是2的幂,就用移位;例如,使用bitsra(X,3)代替X / 8。如果分母是常数,乘以它的倒数;例如,使用X * 0.2代替X / 5

下一个步骤

通过应用这些最佳实践与定点设计的浮点代码转换为定点后,花时间去使用一套现实的测试输入彻底测试你的定点实现和位真模拟结果与你的浮动比较- 点基线。

发布时间2014 - 92226v00