• 定点设计师产品说明
  • 系统要求

教程

MATLAB工作流

在MATLAB中创建定点数据

定点基础知识

执行定点算术

“执行定点算术”

查看定点数据

示例代码中使用的fi对象显示设置

加速定点仿真

此示例说明如何使用fiaccel函数来加速定点算法。您可以从MATLAB®代码生成MEX函数,运行生成的MEX函数,并使用MATLAB代码仿真比较执行速度。

使用Min / Max Instrumentation设置数据类型

此示例显示如何通过检测最小/最大日志记录的MATLAB代码并使用工具建议数据类型来设置定点数据类型。

生成定点C代码

生成独立的定点C代码

手动将浮点MATLAB算法转换为定点

手动将浮点MATLAB算法转换为定点

Simulink工作流

开发和测试定点系统

模拟动态系统的开发周期概述

在Simulink模型和MATLAB之间传递定点数据

阅读从MATLAB定点数据®到您的Simulink ®模型,从模型和模拟登录定点信息到工作区。

配置具有定点输出的块

通过配置Simulink模块输出定点信号来创建定点模型。

从双打到固定点

提供基于该fxpdemo_dbl2fix模型的示例,该示例突出了Fixed-Point Designer™软件的许多关键功能

将浮点模型转换为不动点

详细说明将浮点模型转换为固定点所采取的步骤。

共享定点模型

使用数据类型覆盖设置来共享和编辑包含定点块的模型,而无需使用定点设计器软件。

关于定点

    • 使用定点硬件的好处

       

    • 定点数据类型

      定点数据类型

    • 精度和范围

      讨论定点设计器中算术运算背后的概念

    • 缩放

      讨论定点设计器中使用的缩放类型; 二进制仅点和[斜率偏差]

    • 算术运算

      介绍定点设计器中算术运算背后的概念

    • 物理量和测量量表

      提供测量标度和代表数字的概述

    • 词汇表
    • 精选参考书目    

                

Fixed-Point Designer 产品说明

设计、仿真和分析定点系统

Fixed-Point Designer™ 提供开发定点和单精度算法所需的数据类型和工具,以在嵌入式硬件上进行性能优化。Fixed-Point Designer 会分析您的设计并提供建议的数据类型和属性,例如字长和定标。您可以指定详细的数据属性,如舍入模式和溢出操作,以及混合单精度和定点数据。您可以执行位真仿真来观察有限范围和精度的影响,而无需在硬件上实现设计。

Fixed-Point Designer 可让您将双精度算法转换为单精度或定点。您可以创建和优化满足数值精度要求和目标硬件约束的数据类型。您可以通过数学分析或检测后的仿真来确定设计的范围要求。Fixed-Point Designer 提供的 App 和工具可指导您完成数据转换过程,并允许您将定点结果与浮点基线进行比较。

Fixed-Point Designer 支持 C、HDL 和 PLC 代码生成。

主要功能

  • MATLAB®、Simulink® 和 Stateflow® 中的定点数据类型设定

  • 定点和单精度算法的位真仿真

  • 用于探查和优化数据类型的直方图和相关工具

  • 用于从双精度转换为定点或单精度的 App

  • 用于收集仿真最小值和最大值的检测

  • 用于评估完整设计最小值和最大值的范围分析

  • 用于调试和可视化的溢出检测和精度丢失工具                       

   

教程:MATLAB工作流


在 MATLAB 中创建定点数据

以下示例说明如何使用 Fixed-Point Designer™ fi 对象创建定点数据。

例 1. 使用默认属性创建定点数

对数字调用 fi 会生成具有默认符号性、默认字长和小数长度的定点数。

 fi(pi)
ans =
 
    3.1416

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 13

 

例 2. 创建具有指定符号性、字长和小数长度的定点数

您可以指定符号性(1 表示有符号,0 表示无符号)以及字长和小数长度。

fi(pi,1,15,12)
ans =
 
    3.1416

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 15
        FractionLength: 12

 

 fi 和 numerictype 对象

例 3. 创建定点整数值

要创建定点整数值,请指定小数长度为 0。

fi(1:25,0,8,0)
ans =
 
  Columns 1 through 13
     1   2   3   4   5   6   7   8   9  10  11  12  13
  Columns 14 through 25
    14  15  16  17  18  19  20  21  22  23  24  25

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Unsigned
            WordLength: 8
        FractionLength: 0

 

例 4. 创建随机定点值的数组

 

fi(rand(4),0,12,8)
ans =
 
    0.1484    0.8125    0.1953    0.3516
    0.2578    0.2422    0.2500    0.8320
    0.8398    0.9297    0.6172    0.5859
    0.2539    0.3516    0.4727    0.5508

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Unsigned
            WordLength: 12
        FractionLength: 8

 

例 5. 创建由零组成的数组

编写代码时,您有时需要为变量测试不同数据类型。将变量的数据类型与算法分离使测试变得更加简单。通过创建数据类型定义表,您可以编程方式使函数在浮点数据类型和定点数据类型之间切换。以下示例说明如何使用此方法和创建由零组成的数组。

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

z = zeros(2,3,'like',T.z)
z = 

     0     0     0
     0     0     0

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 0

 

注意

有关说明此方法的实现的完整示例,请参阅Implement FIR Filter Algorithm for Floating-Point and Fixed-Point Types using cast and zeros。

 

 

定点算术

加减法

将两个定点数相加时,您可能需要一个进位位来正确表示结果。因此,将两个B位数(具有相同的定标)相加时,与使用两个操作数时相比,结果值有一个额外的位。

a = fi(0.234375,0,4,6);
c = a + a
c = 

    0.4688

          DataTypeMode:定点:二进制点缩放
            签名:未签名
            WordLength:5
        分数长度:6
a.bin
ans =

1111
c.bin
ans =

11110

 

。如果对具有不同精度的两个数字执行加法或减法,首先需要对齐小数点才能执行运算结果是:运算结果与操作数之间存在多于一位的差异。

a = fi(pi,1,16,13);
b = fi(0.1,1,12,14);
c = a + b
c = 

    3.2416

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:18
        分数长度:14

 

乘法

通常,全精度乘积需要的字长等于各操作数字长之和。在以下示例中,请注意,乘积c的字长等于a的字长加上b的字长。c的小数长度也。等于a的小数长度加上b的小数长度。

a = fi(pi,1,20),b = fi(exp(1),1,16)
a = 

    3.1416

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:20
        分数长度:17

b = 

    2.7183

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:16
        分数长度:13
c = a * b
c = 

    8.5397

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:36
        分数长度:30

 

与其他内置数据类型的数学运算

注意,在Ç语言中,整数数据类型和双精度数据类型之间的运算结果会提升为双精度类型。但是,在MATLAB ®中,内置的整数数据类型和双精度数据类型之间的运算结果是整数。在这方面,fi对象的行为与MATLAB中的内置整数数据类型相似。

fi状语从句:double之间进行加法运算时,双精度会转换为与原fi输入侧具有相同数值类型的fi。该运算的结果是fi。在当fi状语从句:double之间进行乘法运算时,双精度会转换为fi,其字长和符号与性原fi相同御姐具有最佳精度的小数长度。该运算的结果是fi

a = fi(pi);
a = 

    3.1416

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:16
        分数长度:13
b = 0.5 * a
b = 

    1.5708

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:32
        分数长度:28

 

内置在整数数据类型[u]int[8, 16, 32]之一与fi之间进行算术运算时,保留整数的字长和符号性。该运算的结果是fi

a = fi(pi);
b = int8(2)* a
b = 

    6.2832

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:24
        分数长度:13

 

fi与逻辑数据类型之间进行算术运算时,逻辑值被视为值为0或1且字长为1的无符号fi对象。该运算的结果是fi对象。

a = fi(pi);
b =逻辑(1);
c = a * b
c = 

    3.1416

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:17
        分数长度:13

 

fimath对象

fimath属性定义对fi对象执行算术运算的规则,包括数学,舍入和溢出属性。fi对象可以有局部fimath对象,它也。可以使用默认fimath属性。您可以使用setfimathfimath对象附加到fi对象。您也。可以在创建³³时在fi构造函数指定中fimath属性。当fi对象具有局部fimath而不是使用默认属性时,fi对象的显示中将显示fimath属性。在此示例中,a具有在构造函数中指定的ProductMode属性。

a = fi(5,1,16,4,'ProductMode''KeepMSB'
a = 


          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:16
        分数长度:4

        RoundingMethod:最近的
        溢出动作:饱和
           ProductMode:KeepMSB
     ProductWordLength:32
               SumMode:FullPrecision

aProductMode属性设置为KeepMSB,其余而的fimath属性使用默认值。

 

注意

有关fimath对象及其属性和默认值的详细信息,请参阅fimath对象属性

位增长

表下显示fi对象A状语从句:BSumMode状语从句:ProductMode属性使用默认fimathFullPrecision时的位增长。

  一个 Sum = A + B. 产品= A * B.
格式 fi(vA,s1,w1,f1) fi(vB,s2,w2,f2)
符号 s1 s2 Ssum=(|| s1s2 Sproduct=(|| s1s2
整数位 I1 = w1-f1-s1 I2= w2-f2-s2 Isum = max(w1-f1, w2-f2) + 1 - Ssum Iproduct = (w1 + w2) - (f1 + f2)
小数位 f1 f2 Fsum = max(f1, f2) Fproduct = f1 + f2
总位数 w1 w2 Ssum + Isum + Fsum w1 + w2

示例此说明在for循环中发生的位增长。

T.acc = fi([],1,32,0);
Tx = fi([],1,16,0);

x = cast(1:3,'like',Tx);
acc = zeros(1,1,'like',T.acc);

对于 n = 1:长度(x)
    acc = acc + x(n)
结束
acc = 

     1
      s33,0

acc = 

     3
      s34,0

acc = 

     6
      s35,0

随着循环的每次迭代,acc的字长也随之增加这种增加会导致两个问题:。一个是代码生成不允许在循环中更改数据类型另一个是,如果循环足够长,则会在MATLAB中耗尽内存。请参阅控制位增长了解避免此问题的一些策略。

 

控制位增长

使用fimath

指定通过fi对象的fimath属性,您可以控制在对对象执行运算时的位增长

F = fimath('SumMode''SpecifyPrecision''SumWordLength',8,...... 
 'SumFractionLength',0);
a = fi(8,1,8,0,F);
b = fi(3,1,8,0);
c = a + b
c = 

    11

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:8
        分数长度:0

        RoundingMethod:最近的
        溢出动作:饱和
           ProductMode:FullPrecision
               SumMode:SpecifyPrecision
         SumWordLength:8
     SumFractionLength:0
         CastBeforeSum:是的

fi对象a具有局部fimath对象FF指定和的字长和小数长度。在默认fimath设置下,输出c通常字长为9,小数长度为0.但是,由于a具有局部fimath对象,因此生成的fi对象的字长为8,小数长度为0。

还您可以使用fimath属性来控制for循环中的位增长。

F = fimath('SumMode''SpecifyPrecision''SumWordLength',32,...... 
'SumFractionLength',0);
T.acc = fi([],1,32,0,F);
Tx = fi([],1,16,0);

x = cast(1:3,'like',Tx);
acc = zeros(1,1,'like',T.acc);

对于 n = 1:长度(x)
    acc = acc + x(n)
结束
acc = 

     1
      s32,0

acc = 

     3
      s32,0

acc = 

     6
      s32,0

T.acc使用默认fimath属性时不同,acc的位增长现在受到限制。因此,acc的字长保持为32。

下标赋值

控制位增长的另一种方法是使用下标赋值a(I) = bb的值赋给由下标向量I指定的a的元素,保留同时anumerictype

T.acc = fi([],1,32,0);
Tx = fi([],1,16,0);

x = cast(1:3,'like',Tx);
acc = zeros(1,1,'like',T.acc);

%分配到ACC而不改变其类型
为 n = 1时:长度(X)
    acc(:) = acc + x(n)
结束

acc(:) = acc + x(n)指示下标向量(:)处的值发生更改。但是,输出accnumerictype保持不变。由于acc是标量,因此如果您使用(1)作为下标向量,则也会收到相同的输出。

  对于 n = 1:numel(x)
    acc(1)= acc + x(n);
  结束
acc = 

     1
      s32,0

acc = 

     3
      s32,0

acc = 

     6
      s32,0

 

accnumerictypefor循环的每次迭代中保持不变。

下标赋值还可以帮助您控制函数中的位增长。在函数cumulative_sum中,ynumerictype不会更改,但由n指定的元素中的值会更改。

function y = cumulative_sum(x)
 %CUMULATIVE_SUM向量元素的累积和。
%
对于向量,Y = cumulative_sum(X)是包含
X元素的累积和百分比的向量.Y的类型是X的类型 
    .y =零(size(x),'like',x) ;
    y(1)= x(1);
    对于 n = 2:长度(x)
        y(n)= y(n-1)+ x(n);
    年底
结束
y = cumulative_sum(fi([1:10],1,8,0))
y = 

     1 3 6 10 15 21 28 36 45 55

          DataTypeMode:定点:二进制点缩放
            签名:签名
            WordLength:8
        分数长度:0

 

注意

有关下标赋值的详细信息,参阅请subsasgn函数。

accumpo和accumneg

位控制的增长另一种方法的英文使用accumpos状语从句:accumneg函数来执行加法减法状语从句:运算。与使用下标赋值类似,accumpos状语从句:accumneg保留其输入侧fi对象之一的数据类型,同时允许您指定舍入方法和输入值中的溢出操作。

有关如何实现accumposaccumneg的详细信息,请参阅避免生成代码中的多字操作

溢出和舍入

在执行定点算术时,考虑溢出的可能性和后果。fimath对象指定执行算术运算时使用的溢出和舍入模式

溢出

当运算结果超过最大或最小可表示值时,可能会发生溢出。fimath对象具有OverflowAction属性,它提供两种处理溢出的方法:与饱和回绕如果将OverflowAction设置为saturate,则溢出会通过饱和方式限制为该范围内的最大值或最小值。如果将OverflowAction设置为wrap,则任何溢出都将绕回,对于无符号值,会采用模运算绕回,对于有符号值,则采用2的补码绕回。

有关如何检测溢出的详细信息,请参阅使用fipref进行下溢和溢出记录

舍入

选择舍入方法时需要考虑几个因素,包括成本,偏置以及是否存在溢出的可能性.Fixed-Point Designer™软件提供了几个不同舍入函数来满足您的设计要求。

舍入方法 说明 成本 偏差 是否可能溢出
ceil 舍入到正无穷大方向最接近的可表示数字。 大的正向偏差
convergent 舍入到最接近的可表示数字。在舍入机会均等的情况下,convergent舍入到最接近的偶数。这种方法是由工具箱提供的最小偏置舍入方法 无偏差
floor 舍入到负无穷大方向上最接近的可表示数字,相当于2的补码截断。 大的负向偏差
nearest 舍入到最接近的可表示数字。在舍入机会均等的情况下,nearest在正无穷大的方向上舍入到最接近的可表示数字。舍此入方法的英文fi对象创建³³状语从句:fi算术的默认值。 中等 小的正向偏差
round 。舍入到最接近的可表示数字在舍入机会均等的情况下round方法进行如下舍入:

  • 将正数舍入到正无穷大方向上最接近的可表示数字。

  • 将负数舍入到负无穷大方向上最接近的可表示数字。

  • 对于具有负值的样本,为小的负向偏差

  • 对于具有均匀分布的正值和负值的样本,无偏差

  • 对于具有正值的样本,为小的正向偏差

fix 舍入到零方向上最接近的可表示数字。
  • 对于具有负值的样本,为大的正向偏差

  • 对于具有均匀分布的正值和负值的样本,无偏差

  • 对于具有正值的样本,为大的负向偏差

 

查看定点数据

 

在 Fixed-Point Designer™ 软件中,fipref 对象确定 fi 对象的显示属性。对于 fi 对象,代码示例通常在它们与下列 fipref 对象属性一起使用时才显示它们:

  • NumberDisplay – 'RealWorldValue'

  • NumericTypeDisplay – 'full'

  • FimathDisplay – 'full'

通过将 'FimathDisplay' 设置为 'full',可以快速、轻松地区分具有局部 fimath 配置的 fi 对象和那些与默认 fimath 配置相关联的对象。当 'FimathDisplay' 设置为 'full' 时,MATLAB® 显示具有局部 fimath 配置的 fi 对象的 fimath 对象属性。MATLAB 不会显示与默认 fimath 配置相关联的 fi 对象的 fimath 对象属性。由于存在这种显示差异,您只需通过查看输出即可知道 fi 对象是否与默认 fimath 配置相关联。

此外,除非另有说明,否则整个 Fixed-Point Designer 文档中的示例都使用 fimath 的以下默认配置:

        RoundingMethod: Nearest
        OverflowAction: Saturate
           ProductMode: FullPrecision
               SumMode: FullPrecision

有关显示设置的详细信息,请参阅fi Object Display Preferences Using fipref。

显示 fi 对象的 fimath 属性

要查看大多数 Fixed-Point Designer 代码示例中显示的输出,请按如下所示设置 fipref 属性并创建两个 fi 对象:

p = fipref('NumberDisplay', 'RealWorldValue',... 
'NumericTypeDisplay', 'full', 'FimathDisplay', 'full');
a = fi(pi,'RoundingMethod', 'Floor', 'OverflowAction', 'Wrap')
b = fi(pi)

MATLAB 返回以下内容:

a =
    3.1415

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 13

        RoundingMethod: Floor
        OverflowAction: Wrap
           ProductMode: FullPrecision
               SumMode: FullPrecision

b =
    3.1416

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 13

MATLAB 在 fi 对象 a 的输出中显示 fimath 对象属性,因为 a 具有局部 fimath 配置。

MATLAB 在 fi 对象 b 的输出中不显示任何 fimath 对象属性,因为 b 将自身与默认 fimath 关联。

隐藏 fi 对象的 fimath 属性

如果您正在使用多个具有局部 fimath 配置的 fi 对象,则可能需要关闭 fimath 对象显示:

  • NumberDisplay – 'RealWorldValue'

  • NumericTypeDisplay – 'full'

  • FimathDisplay – 'none'

例如,

p = fipref('NumberDisplay','RealWorldValue',... 
'NumericTypeDisplay','full','FimathDisplay','none')
 
p =
 
         NumberDisplay: 'RealWorldValue'
    NumericTypeDisplay: 'full'
         FimathDisplay: 'none'
           LoggingMode: 'Off'
      DataTypeOverride: 'ForceOff'

F = fimath('RoundingMethod','Floor','OverflowAction','Wrap');
a = fi(pi, F)
 
a =
    3.1415

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 13

尽管此设置有助于减少产生的输出量,但它也导致无法根据输出判断 fi 对象是否使用默认 fimath。为此,您可以使用 isfimathlocal 函数。例如,

isfimathlocal(a)

ans =
     1

当 isfimathlocal 函数返回 1 时,fi 对象具有局部 fimath 配置。如果函数返回 0,则 fi 对象使用默认 fimath 配置。

缩短 fi 对象的数值类型显示

要进一步减少输出量,可以将 NumericTypeDisplay 设置为 'short'。例如,

p = fipref('NumberDisplay','RealWorldValue',... 
'NumericTypeDisplay','short','FimathDisplay','full');

a = fi(pi)

a =
    3.1416
      s16,13

加速定点仿真

 

此示例说明如何使用 fiaccel 函数来加速定点算法。您可以从 MATLAB® 代码生成 MEX 函数,运行生成的 MEX 函数,并使用 MATLAB 代码仿真比较执行速度。

示例说明

此示例使用一阶反馈回路。它还使用量化器来避免无限的位增长。输出信号被延迟一个采样周期并通过回馈来缓冲输入信号。

 

 

复制必需的文件

您需要此 MATLAB 文件来运行此示例。将其复制到临时目录。此步骤需要具有对系统临时目录的写入访问权限。

tempdirObj = fidemo.fiTempdir('fiaccelbasicsdemo');
fiacceldir = tempdirObj.tempDir;
fiaccelsrc = ...
    fullfile(matlabroot,'toolbox','fixedpoint','fidemos','+fidemo','fiaccelFeedback.m');
copyfile(fiaccelsrc,fiacceldir,'f');

检查 MATLAB 反馈函数代码

执行反馈回路的 MATLAB 函数位于文件 fiaccelFeedback.m 中。以下代码将量化输入,并执行反馈回路操作:

type(fullfile(fiacceldir,'fiaccelFeedback.m'))
function [y,w] = fiaccelFeedback(x,a,y,w)
%FIACCELFEEDBACK Quantizer and feedback loop used in FIACCELBASICSDEMO.

% Copyright 1984-2013 The MathWorks, Inc.
%#codegen

for n = 1:length(x)
    y(n) =  quantize(x(n) - a*w, true, 16, 12, 'floor', 'wrap');
    w    = y(n);    
end

此函数中使用以下变量:

  • x 是输入信号向量。

  • y 是输出信号向量。

  • a 是反馈增益。

  • w 是延迟一个单位时间的输出信号。

创建输入信号并初始化变量

rng('default');                      % Random number generator
x = fi(2*rand(1000,1)-1,true,16,15); % Input signal
a = fi(.9,true,16,15);               % Feedback gain
y = fi(zeros(size(x)),true,16,12);   % Initialize output. Fraction length
                                     % is chosen to prevent overflow
w = fi(0,true,16,12);                % Initialize delayed output
A = coder.Constant(a);               % Declare "a" constant for code
                                     % generation

运行 Normal 模式

tic,
y = fiaccelFeedback(x,a,y,w);
t1 = toc;

编译反馈代码的 MEX 版本

fiaccel fiaccelFeedback -args {x,A,y,w} -o fiaccelFeedback_mex

运行 MEX 版本

tic
y2 = fiaccelFeedback_mex(x,y,w);
t2 = toc;

加速比

代码加速为通过 MEX 文件生成加速定点算法提供优化。Fixed-Point Designer™ 提供了一个方便的函数 fiaccel 来将您的 MATLAB 代码转换为 MEX 函数,这可以大大加快定点算法的执行速度。

r = t1/t2
r =

   12.7097

清理临时文件

clear fiaccelFeedback_mex;
tempdirObj.cleanUp;

使用Min / Max Instrumentation设置数据类型

 

此示例显示如何通过检测用于最小/最大日志记录的MATLAB®代码并使用工具建议数据类型来设置定点数据类型。

您将使用的功能是:

 

  • buildInstrumentedMex – 在启用检测的情况下构建MEX功能

  • showInstrumentationResults – 显示检测结果

  • clearInstrumentationResults – 清除仪器结果

 

被测单位

在此示例中转换为定点的函数是二阶直接形式2转置过滤器。您可以用自己的功能代替这个功能,在您自己的工作中重现这些步骤。

函数 [Y,Z] = fi_2nd_order_df2t_filter(B,A,X,Y,Z)
      I = 1:长度(X)
        y(i)= b(1)* x(i)+ z(1);
        z(1)= b(2)* x(i)+ z(2)-a(2)* y(i);
        z(2)= b(3)* x(i) -  a(3)* y(i);
    年底
结束

对于要检测的MATLAB®函数,它必须适合代码生成。有关代码生成的信息,请参阅参考页面buildInstrumentedMex不需要使用MATLAB®Coder™许可证buildInstrumentedMex

在此函数中的变量yz用作输入和输出。这是一个重要的模式,因为:

  • 您可以设置的数据类型yz外设功能,从而使您可以重复使用的功能,两个定点和浮点类型。

  • 生成的C代码将在函数参数列表中创建yz作为引用。有关此模式的更多信息,请参阅MATLAB®代码生成下的文档>用户指南>生成高效且可重用的代码>生成高效代码>消除函数输入的冗余副本。

运行以下代码将测试函数复制到临时目录中,因此此示例不会干扰您自己的工作。

tempdirObj = fidemo.fiTempdir('fi_instrumentation_fixed_point_filter_demo');
copyfile(fullfile(matlabroot,'toolbox'' fixedpoint ''fidemos''+ fidemo'... 
                  'fi_2nd_order_df2t_filter.m'),'。''f');

运行以下代码以捕获当前状态,并重置全局状态。

FIPREF_STATE = get(fipref);
复位(fipref)

数据类型由设计要求决定

在此示例中,设计要求确定输入的数据类型x这些要求是有符号的,16位和小数。

N = 256;
x = fi(零(N,1),1,16,15);

设计要求还决定了具有40位累加器的DSP目标的定点数学运算。此示例使用地板舍入和换行溢出来生成高效的生成代码。

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

以下系数对应于由2创建的二阶低通滤波器

[num,den] =黄油(2,0.125)

系数的值会影响将分配给滤波器输出和状态的值的范围。

num = [0.0299545822080925 0.0599091644161849 0.0299545822080925];
den = [1 -1.4542435862515900 0.5740619150839550];

由设计要求确定的系数的数据类型被指定为16位字长并且被缩放到最佳精度。fi从常系数创建对象的模式是:

1. fi使用默认的舍入到最近和饱和溢出设置将系数投射到对象,这使得系数更精确。

2.附加fimath地板舍入和包装溢出设置以控制算术,从而产生更高效的C代码。

b = fi(num,1,16); b.fimath = F;
a = fi(den,1,16); a.fimath = F;

通过将滤波器系数作为常量传递给buildInstrumentedMex命令,将滤波器系数硬编码到此滤波器的实现中

B = coder.Constant(b);
A = coder.Constant(a);

数据类型由系数和输入的值决定

输入的系数和值的值确定输出y和状态向量的数据类型z使用缩放的双数据类型创建它们,以便它们的值达到全范围,您可以识别潜在的溢出并建议数据类型。

yisd = fi(零(N,1),1,16,15,'DataType''ScaledDouble''fimath',F);
zisd = fi(零(2,1),1,16,15,'DataType''ScaledDouble''fimath',F);

将MATLAB®功能用作缩放双MEX功能

要检测MATLAB®代码,可以使用buildInstrumentedMex命令从MATLAB®函数创建MEX函数输入与输入buildInstrumentedMex相同fiaccel,但buildInstrumentedMex没有对象fi限制。输出buildInstrumentedMex是带有仪器插入的MEX功能,因此在运行MEX功能时,将记录所有命名变量和中间值的模拟最小值和最大值。

使用该'-o'选项命名生成的MEX函数。如果不使用该'-o'选项,则MEX函数是'_mex'附加的MATLAB®函数的名称您也可以将MEX功能命名为与MATLAB®功能相同,但您需要记住MEX功能优先于MATLAB®功能,因此在重新生成MEX功能之前,MATLAB®功能的更改不会运行,或者删除并清除MEX功能。

buildInstrumentedMex fi_2nd_order_df2t_filter  ... 
    -o  filter_scaled_double  ... 
    -args  {B,A,X,yisd,zisd}

带有啁啾输入的测试台

该系统的测试台设置为运行啁啾和步进信号。通常,系统的测试台应覆盖各种输入信号。

第一个测试平台使用啁啾输入。啁啾信号是很好的代表性输入,因为它涵盖了很宽的频率范围。

t = linspace(0,1,N);       %时间矢量从0到1秒 
f1 = N / 2;                  %啁啾的目标频率设置为Nyquist 
xchirp = sin(pi * f1 * t。^ 2);  %线性啁啾从0到Fs / 2 Hz,1秒 
x(:) = xchirp;             %将啁啾投射到定点

运行Instrumented MEX功能以记录最小值/最大值

必须运行检测的MEX功能以记录该模拟运行的最小值和最大值。后续运行会累积检测结果,直到清除它们为止clearInstrumentationResults

请注意,分子和分母系数被编译为常量,因此它们不作为生成的MEX函数的输入提供。

ychirp = filter_scaled_double(x,yisd,zisd);

滤波的线性调频信号的曲线图示出了具有这些特定系数的滤波器的低通行为。低频通过,较高频率衰减。

CLF
情节(t,x,'c',t,ychirp,'bo-'
标题('唧唧'
图例('输入''缩放双输出'
图(GCF); 的DrawNow;

显示Chirp的建议分数长度的仪器结果

showInstrumentationResults命令显示带有检测值的代码生成报告。输入to showInstrumentationResults是您希望显示结果的已检测MEX函数的名称。

这是showInstrumentationResults命令的选项列表

  • -defaultDT T建议用于双精度的默认数据类型,其中Tnumerictype对象或其中一个字符串{remainFloat, double, single, int8, int16, int32, int64, uint8, uint16, uint32, uint64}默认是remainFloat

  • -nocode不要在可打印报告中显示MATLAB代码。仅显示已记录的变量表。此选项仅与-printable选项结合使用。

  • -optimizeWholeNumbers 优化变量的字长,其模拟最小/最大日志表明它们始终是整数。

  • -percentSafetyMargin N 模拟最小值/最大值的安全裕度,其中N表示百分比值。

  • -printable 创建可打印的报告并在系统浏览器中打开。

  • -proposeFL 建议指定字长的分数长度。

  • -proposeWL 建议指定分数长度的字长。

仅对fi具有Scaled Double数据类型的对象显示潜在溢出

这种特殊设计适用于DSP,其中字长是固定的,因此使用proposeFL标志来建议分数长度。

showInstrumentationResults filter_scaled_double  -proposeFL

将鼠标悬停在检测代码生成报告中的表达式或变量上,以查看模拟的最小值和最大值。在此设计中,输入介于-1和+1之间,所有变量和中间结果的值也介于-1和+1之间。这表明数据类型都可以是分数的(分数长度比字长小一点)。但是,对于其他类型的输入,此功能并不总是如此,在设置最终定点数据类型之前测试多种类型的输入非常重要。

 

 

带步进输入的试验台

下一个测试台是通过步进输入运行的。步进输入是良好的代表性输入,因为它通常用于表征系统的行为。

xstep = [ones(N / 2,1);  -  ones(N / 2,1)];
x(:) = xstep;

使用步进输入运行Instrumented MEX功能

仪器结果将被累积,直到它们被清除clearInstrumentationResults

ystep = filter_scaled_double(x,yisd,zisd);

CLF
情节(t,x,'c',t,ystep,'bo-'
标题('步骤'
图例('输入''缩放双输出'
图(GCF); 的DrawNow;

显示累计仪器结果

即使步进和啁啾输入的输入都是全范围,如x仪表代码生成报告中的100%电流范围所示,步进输入也会导致溢出,而​​啁啾输入则不会。这说明了为测试平台提供许多不同输入的必要性。出于本示例的目的,仅使用了两个输入,但真正的测试平台应该更彻底。

showInstrumentationResults filter_scaled_double  -proposeFL

 

 

应用建议的定点属性

为了防止基于的14位用于所提出的分数长度溢出,建议设置定点特性yz从所述仪表化代码生成报告。

在工作流程的这一点上,您使用了真正的定点类型(而不是在确定数据类型的早期步骤中使用的缩放双重类型)。

yi = fi(零(N,1),1,16,14,'fimath',F);
zi = fi(零(2,1),1,16,14,'fimath',F);

将MATLAB®功能用作定点MEX功能

使用定点输入和buildInstrumentedMex命令创建仪表化定点MEX功能

buildInstrumentedMex fi_2nd_order_df2t_filter  ... 
    -o  filter_fixed_point  ... 
    -args  {B,A,x,yi,zi}

验证定点算法

转换到定点后,再次使用定点输入运行测试台以验证设计。

使用Chirp输入验证

使用啁啾输入运行定点算法以验证设计。

x(:) = xchirp;
[y,z] = filter_fixed_point(x,yi,zi);
[ysd,zsd] = filter_scaled_double(x,yisd,zisd);
err = double(y) -  double(ysd);

将定点输出与按比例缩放的双输出进行比较,以验证它们是否符合您的设计标准。

CLF
subplot(211); plot(t,x,'c',t,ysd,'bo-',t,y,'mx'
xlabel('Time(s)');
ylabel('幅度'
图例('输入''缩放双输出''定点输出');
标题('定点啁啾'
subplot(212); plot(t,err,'r'); title('Error'); xlabel('t'); ylabel('err');
图(GCF); 的DrawNow;

检查变量和中间结果,以确保最小/最大值在范围内。

showInstrumentationResults filter_fixed_point

 

 

使用步骤输入进行验证

使用步进输入运行定点算法以验证设计。

运行以下代码以清除以前的检测结果,以仅查看运行步骤输入的效果。

clearInstrumentationResults filter_fixed_point

通过定点滤波器运行步进输入,并与缩放双滤波器的输出进行比较。

x(:) = xstep;
[y,z] = filter_fixed_point(x,yi,zi);
[ysd,zsd] = filter_scaled_double(x,yisd,zisd);
err = double(y) -  double(ysd);

根据比例双输出绘制定点输出,以验证它们是否符合您的设计标准。

CLF
subplot(211); plot(t,x,'c',t,ysd,'bo-',t,y,'mx'
标题('定点步骤');
图例('输入''缩放双输出''定点输出'
subplot(212); plot(t,err,'r'); title('Error'); xlabel('t'); ylabel('err');
图(GCF); 的DrawNow;

检查变量和中间结果,以确保最小/最大值在范围内。

showInstrumentationResults filter_fixed_point

 

 

运行以下代码以还原全局状态。

fipref(FIPREF_STATE);
clearInstrumentationResults filter_fixed_point 
clearInstrumentationResults filter_scaled_double 
明确fi_2nd_order_df2t_filter_fixed_instrumented 
明确fi_2nd_order_df2t_filter_float_instrumented

运行以下代码以删除临时目录。

tempdirObj.cleanUp;
%#确定<* ASGLU>

生成定点 C 代码

注意

要从 MATLAB® 生成定点代码,您必须同时拥有 Fixed-Point Designer™ 产品和 MATLAB Coder™ 产品。您还必须有 C 编译器。

此示例说明如何为简单的函数生成代码,该函数将两个输入值相乘并累加。这是可以嵌入在外部硬件中的代码的类型。函数是

function acc = mult_acc(x,a,acc)
acc = accumpos(acc,x*a); 

 

以下代码定义测试平台输入,设置必需的代码生成属性并生成代码。测试平台输入被指定为定点数。x 输入为随机数,a 为 0.9,累加器 acc 初始化为 0。coder.HardwareImplementation 对象指定影响生成代码的外部硬件的属性。这些示例指定一个 40 位累加器。coder.CodeConfig 对象具有直接影响代码生成的属性。codegen 命令将函数、配置对象作为输入参数并生成可嵌入的 C 代码。

x = fi(rand,true,16,15);
a = fi(0.9,true,16,15);
acc = fi(0,true,40,30);


%% 
hi = coder.HardwareImplementation;
hi. ProdHWDeviceType = 'Generic->Custom'
hi. TargetHWDeviceType = 'Generic->Custom'
hi.TargetBitPerLong = 40;
hi.ProdBitPerLong   = 40;

hc = coder.config('lib');
hc.HardwareImplementation = hi;
hc.GenerateReport         = true;

codegen mult_acc -config hc -args {x,a,acc}

 

生成的 C 代码是

/*
 * mult_acc.c
 *
 * Code generation for function 'mult_acc'
*/

/* Include files */
#include "rt_nonfinite.h"
#include "mult_acc.h"

/* Function Definitions */
void mult_acc(short x, short a, long *acc)
{
  *acc += x * a;
}

/* End of code generation (mult_acc.c) */

 

注意

有关支持代码生成的函数的列表,请参阅Functions and Objects Supported for C/C++ Code Generation — Alphabetical List。

 

手动将浮点 MATLAB 算法转换为定点

此示例说明如何将浮点算法转换为定点,然后为该算法生成 C 代码。该示例使用以下最佳做法:

  • 将算法与测试文件分离。

  • 为检测和代码生成准备算法。

  • 管理数据类型并控制位增长。

  • 通过创建数据定义表将数据类型定义与算法代码分离。

有关最佳做法的完整列表,请参阅Manual Fixed-Point Conversion Best Practices。

将算法与测试文件分离

编写 MATLAB® 函数 mysum,它对向量的元素求和。

function y = mysum(x)
  y = 0;
  for n = 1:length(x)
    y = y + x(n);
  end
end

 

由于您只需要将算法部分转换为定点,因此编写代码时,将执行核心处理的算法与测试文件分离,可提升效率。

编写测试脚本

在测试文件中,创建您的输入、调用算法并绘制结果。

  1. 编写 MATLAB 脚本 mysum_test,它使用双精度数据类型验证您的算法的行为。

    n = 10;
    rng default
    x = 2*rand(n,1)-1;
    
    % Algorithm
    y = mysum(x);
    
    % Verify results
    y_expected = sum(double(x));
    
    err = double(y) - y_expected

     

    rng default 使 rand 函数使用的随机数生成函数的设置采用其默认值,以便它生成的随机数与重新启动 MATLAB 后生成的随机数相同。

  2. 运行测试脚本。

    mysum_test
    err =
    
         0

     

    使用 mysum 获得的结果与使用 MATLAB sum 函数获得的结果相匹配。

有关详细信息,请参阅Create a Test File。

为检测和代码生成准备算法

在您的算法中,在函数签名后,添加 %#codegen 编译指令以指示您要将算法用于检测并为其生成 C 代码。添加此指令将指示 MATLAB 代码分析器帮助您诊断并修复在检测和代码生成过程中会导致错误的违规情况。

function y = mysum(x) %#codegen
  y = 0;  
  for n = 1:length(x)
    y = y + x(n);
  end
end

 

对于此算法,编辑器窗口右上角的代码分析器指示标记保持绿色,告诉您它没有检测到任何问题。

有关详细信息,请参阅Prepare Your Algorithm for Code Acceleration or Code Generation。

为原始算法生成 C 代码

为原始算法生成 C 代码以验证该算法适用于代码生成并查看浮点 C 代码。使用 codegen 函数(需要 MATLAB Coder™)来生成 C 库。

  1. 将以下行添加到测试脚本的末尾,为 mysum 生成 C 代码。

    codegen mysum -args {x} -config:lib -report

     

  2. 再次运行测试脚本。

    MATLAB Coder 为 mysum 函数生成 C 代码,并提供代码生成报告的链接。

  3. 点击该链接以打开代码生成报告并查看为 mysum 生成的 C 代码。

    /* Function Definitions */
    double mysum(const double x[10])
    {
      double y;
      int n;
      y = 0.0;
      for (n = 0; n < 10; n++) {
        y += x[n];
     }
     
     return y;
     }

     

    由于 C 不允许浮点索引,因此循环计数器 n 会自动声明为整数类型。您不需要将 n 转换为定点。

    输入 x 和输出 y 声明为双精度类型。

 

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

用单精度类型测试您的算法以检查类型是否匹配

  1. 修改您的测试文件,以使 x 的数据类型为单精度。

    n = 10;
    rng default
    x = single(2*rand(n,1)-1);
    
    % Algorithm
    y = mysum(x);
    
    % Verify results
    y_expected = sum(double(x));
    
    err = double(y) - y_expected
    codegen mysum -args {x} -config:lib -report

     

  2. 再次运行测试脚本。

    mysum_test
    err =
    
      -4.4703e-08
    
    ??? This assignment writes a 'single' value into a 'double' type. Code generation
    does not support changing types through assignment. Check preceding assignments or
    input type specifications for type mismatches.

     

    代码生成失败,报告 y = y + x(n); 行中的数据类型不匹配。

  3. 要查看错误,请打开报告。

    在报告中,在 y = y + x(n) 行上,报告以红色突出显示赋值的左侧的 y,表明存在错误。存在的问题是:y 声明为双精度类型,但被赋予一个单精度类型值。y + x(n) 是双精度和单精度值之和,该和为单精度值。如果将光标置于报告中的变量和表达式上,可以看到有关它们的类型的信息。在此处,您可以看到表达式 y + x(n) 是单精度类型。

     

  4. 要修复类型不匹配,请更新您的算法以对元素之和使用下标赋值。将 y = y + x(n) 更改为 y(:) = y + x(n)

    function y = mysum(x) %#codegen
      y = 0;
      for n = 1:length(x)
        y(:) = y + x(n);
      end
    end
    

     

    使用下标赋值时,您还可以防止位增长,位增长是添加定点数时的默认行为。有关详细信息,请参阅位增长。防止位增长非常重要,因为您要在整个代码中保持定点类型。有关详细信息,请参阅控制位增长。

  5. 重新生成 C 代码并打开代码生成报告。在 C 代码中,结果现在转换为双精度类型来解决类型不匹配问题。

编译检测后的 MEX

使用 buildInstrumentedMex 函数来检测算法,以记录所有命名变量和中间变量的最小值和最大值。使用 showInstrumentationResults 函数根据这些记录的值建议定点数据类型。稍后,您将使用这些建议的定点类型来测试您的算法。

  1. 更新测试脚本:

    1. 声明 n 后,添加 buildInstrumentedMex mySum —args {zeros(n,1)} -histogram

    2. 将 x 更改为双精度类型。用 x = 2*rand(n,1)-1; 替换 x = single(2*rand(n,1)-1);

    3. 调用生成的 MEX 函数,而不是调用原始算法。将 y = mysum(x) 更改为 y=mysum_mex(x)

    4. 调用 MEX 函数后,添加 showInstrumentationResults mysum_mex -defaultDT numerictype(1,16) -proposeFL-defaultDT numerictype(1,16) -proposeFL 标志表示您要为 16 位字长度建议小数长度。

      这是更新后的测试脚本。

      %% Build instrumented mex
      n = 10;
      
      buildInstrumentedMex mysum -args {zeros(n,1)} -histogram
      
      %% Test inputs
      rng default
      x = 2*rand(n,1)-1;
      
      % Algorithm
      y = mysum_mex(x);
      
      % Verify results
      
      showInstrumentationResults mysum_mex ...
        -defaultDT numerictype(1,16) -proposeFL
      y_expected = sum(double(x));
      
      err = double(y) - y_expected
      
      %% Generate C code
      
      codegen mysum -args {x} -config:lib -report
      

       

     

  2. 再次运行测试脚本。

    showInstrumentationResults 函数建议数据类型并打开报告以显示结果。

  3. 在报告中,点击 Variables 选项卡。showInstrumentationResults 对 y 建议小数长度为 13,对 x 建议小数长度为 15。

     

在报告中,您可以:

  • 查看输入 x 和输出 y 的仿真最小值和最大值。

  • 查看对 x 和 y 建议的数据类型。

  • 查看代码中所有变量、中间结果和表达式的信息。

    要查看此信息,请将光标放在报告中的变量或表达式上。

  • 查看 x 和 y 的直方图数据,以帮助您根据当前数据类型识别超出范围或低于精度的任何值。

    要查看特定变量的直方图,请点击其直方图图标 

 

将数据类型定义与算法代码分离

不要手动修改算法来检查每种数据类型的行为,而是将数据类型定义与算法分离。

修改 mysum 使其使用输入参数 T,它是一种用于定义输入和输出数据的数据类型的结构体。当首先定义 y 时,使用 cast 函数的类似于 cast(x,'like',y) 的语法将 x 转换为所需的数据类型。

function y = mysum(x,T) %#codegen
  y = cast(0,'like',T.y);
  for n = 1:length(x)
    y(:) = y + x(n);
  end
end

 

创建数据类型定义表

编写函数 mytypes,它定义您要用于测试算法的不同数据类型。在您的数据类型表中,包括双精度、单精度和定标双精度数据类型以及前面建议的定点数据类型。在将算法转换为定点之前,最好做法是:

  • 使用双精度值测试数据类型定义表和算法之间的关联。

  • 使用单精度值测试算法来查找数据类型不匹配和其他问题。

  • 使用定标双精度值运行算法来检查是否存在溢出。

 

function T = mytypes(dt)
  switch dt
    case 'double'
      T.x = double([]);
      T.y = double([]);
    case 'single'
      T.x = single([]);
      T.y = single([]);
    case 'fixed'
      T.x = fi([],true,16,15);
      T.y = fi([],true,16,13);
    case 'scaled'
      T.x = fi([],true,16,15,...
           'DataType','ScaledDouble');
      T.y = fi([],true,16,13,...
           'DataType','ScaledDouble');
  end
end

 

有关详细信息,请参阅Separate Data Type Definitions from Algorithm。

更新测试脚本以使用类型表

更新测试脚本 mysum_test 以使用类型表。

  1. 对于第一次运行,请使用双精度值检查类型表和算法之间的关联。在声明 n 之前,添加 T = mytypes('double');

  2. 更新对 buildInstrumentedMex 的调用以使用在数据类型表中指定的 T.x 的类型:buildInstrumentedMex mysum -args {zeros(n,1,'like',T.x),T} -histogram

  3. 将 x 转换为使用在表中指定的 T.x 的类型:x = cast(2*rand(n,1)-1,'like',T.x);

  4. 调用传入 T 的 MEX 函数:y = mysum_mex(x,T);

  5. 调用传入 T 的 codegencodegen mysum -args {x,T} -config:lib -report

    以下是更新后的测试脚本。

    %% Build instrumented mex
    T = mytypes('double');
    
    n = 10;
    
    buildInstrumentedMex mysum ...
        -args {zeros(n,1,'like',T.x),T} -histogram
    
    %% Test inputs
    rng default
    x = cast(2*rand(n,1)-1,'like',T.x);
    
    % Algorithm
    y = mysum_mex(x,T);
    
    % Verify results
    
    showInstrumentationResults mysum_mex ...
        -defaultDT numerictype(1,16) -proposeFL
    
    y_expected = sum(double(x));
    
    err = double(y) - y_expected
    
    %% Generate C code
    
    codegen mysum -args {x,T} -config:lib -report
    

     

  6. 运行测试脚本并点击链接以打开代码生成报告。

    生成的 C 代码与为原始算法生成的代码相同。原因是变量 T 用于指定类型,并且这些类型在代码生成时是恒定的;T 在运行时不使用,并且不会出现在生成的代码中。

生成定点代码

更新测试脚本以使用前面建议的定点类型并查看生成的 C 代码。

  1. 更新测试脚本以使用定点类型。用 T = mytypes('fixed'); 替换 T = mytypes('double');,然后保存该脚本。

  2. 运行测试脚本并查看生成的 C 代码。

    此 C 代码版本效率不是很高,它包含很多溢出处理。下一步是优化数据类型以避免溢出。

优化数据类型

使用定标双精度值来检测溢出

定标双精度值混合了浮点数和定点数。Fixed-Point Designer™ 将它们存储为保留定标、符号和字长信息的双精度值。由于所有算术都以双精度执行,因此您可以看到发生的任何溢出。

  1. 更新测试脚本以使用定标双精度值。用 T = mytypes('scaled'); 替换 T = mytypes('fixed');

  2. 再次运行测试脚本。

    使用定标双精度值运行测试并显示报告。没有检测到溢出。

    到当前为止,您只使用随机输入运行了测试脚本,这意味着测试并没有执行算法的整个运算范围。

  3. 找到输入的完整范围。

    range(T.x)
    -1.000000000000000   0.999969482421875
    
              DataTypeMode: Fixed-point: binary point scaling
                Signedness: Signed
                WordLength: 16
            FractionLength: 15

     

  4. 更新脚本以测试负边界情况。使用原始随机输入和测试整个范围的输入运行 mysum_mex 并聚合测试结果。

    %% Build instrumented mex
    T = mytypes('scaled');
    n = 10;
    
    buildInstrumentedMex mysum ...
        -args {zeros(n,1,'like',T.x),T} -histogram
    
    %% Test inputs
    rng default
    x = cast(2*rand(n,1)-1,'like',T.x);
    y = mysum_mex(x,T);
     % Run once with this set of inputs
    y_expected = sum(double(x));
    err = double(y) - y_expected
    
    % Run again with this set of inputs. The logs will aggregate.
    x = -ones(n,1,'like',T.x);
    y = mysum_mex(x,T); 
    y_expected = sum(double(x));
    err = double(y) - y_expected 
    
    % Verify results
    
    showInstrumentationResults mysum_mex ...
        -defaultDT numerictype(1,16) -proposeFL
    
    y_expected = sum(double(x));
    
    err = double(y) - y_expected
    
    %% Generate C code
    
    codegen mysum -args {x,T} -config:lib -report
    

     

  5. 再次运行测试脚本。

    运行测试后,y 的值会溢出定点数据类型的范围。showInstrumentationResults 建议对于 y 采用新小数长度 11。

  6. 将测试脚本更新为对 y 使用具有建议的新类型的定标双精度。在 myTypes.m 中,对于 'scaled' 情况,使用 T.y = fi([],true,16,11,'DataType','ScaledDouble')

  7. 重新运行测试脚本。

    现在没有出现溢出。

为建议的定点类型生成代码

更新数据类型表以使用建议的定点类型并生成代码。

  1. 在 myTypes.m 中,对于 'fixed' 情况,使用 T.y = fi([],true,16,11)

  2. 更新测试脚本 mysum_test,以使用 T = mytypes('fixed');

  3. 运行测试脚本,然后点击“View Report”链接以查看生成的 C 代码。

    short mysum(const short x[10])
    {
      short y;
      int n;
      int i0;
      int i1;
      int i2;
      int i3;
      y = 0;
      for (n = 0; n < 10; n++) {
        i0 = y << 4;
        i1 = x[n];
        if ((i0 & 1048576) != 0) {
          i2 = i0 | -1048576;
        } else {
          i2 = i0 & 1048575;
       }
       
        if ((i1 & 1048576) != 0) {
         i3 = i1 | -1048576;
        } else {
          i3 = i1 & 1048575;
        }
    
      i0 = i2 + i3;
      if ((i0 & 1048576) != 0) {
        i0 |= -1048576;
      } else {
        i0 &= 1048575;
      }
    
      i0 = (i0 + 8) >> 4;
      if (i0 > 32767) {
        i0 = 32767;
      } else {
          if (i0 < -32768) {
            i0 = -32768;
          }
        }
    
       y = (short)i0;
      }
      return y;
    }

    默认情况下,fi 算术在溢出和最接近舍入时使用饱和,导致代码效率低下。

修改 fimath 设置

要使生成的代码更高效,请使用更适合于生成 C 代码的定点数学 (fimath) 设置:在溢出和向下取整时进行绕回。

  1. 在 myTypes.m 中,添加 'fixed2' case:

     case 'fixed2'
          F = fimath('RoundingMethod', 'Floor', ...
               'OverflowAction', 'Wrap', ...
               'ProductMode', 'FullPrecision', ...
               'SumMode', 'KeepLSB', ...
               'SumWordLength', 32, ...
               'CastBeforeSum', true);
          T.x = fi([],true,16,15,F);
          T.y = fi([],true,16,11,F);
    

     

    提示

    您可以使用 MATLAB Editor Insert fimath 选项,而不是手动输入 fimath 属性。有关详细信息,请参阅Building fimath Object Constructors in a GUI。

  2. 更新测试脚本以使用 'fixed2'、运行脚本,然后查看生成的 C 代码。

    short mysum(const short x[10])
    {
     short y;
     int n;
     y = 0;
     for (n = 0; n < 10; n++) {
       y = (short)(((y << 4) + x[n]) >> 4);
     }
    
      return y;
    }

     

    生成的代码更高效,但是 y 经过移位以与 x 对齐,失去 4 位精度。

  3. 为了解决这种精度丢失问题,将 y 的字长更新为 32 位,并保持 15 位的精度以与 x 对齐。

    在 myTypes.m 中,添加 'fixed32' case:

     case 'fixed32'
          F = fimath('RoundingMethod', 'Floor', ...
               'OverflowAction', 'Wrap', ...
               'ProductMode', 'FullPrecision', ...
               'SumMode', 'KeepLSB', ...
               'SumWordLength', 32, ...
               'CastBeforeSum', true);
          T.x = fi([],true,16,15,F);
          T.y = fi([],true,32,15,F);
    

     

  4. 更新测试脚本以使用 'fixed32' 并运行脚本以再次生成代码。

    现在,生成的代码非常高效。

    int mysum(const short x[10])
    {
      int y;
      int n;
      y = 0;
      for (n = 0; n < 10; n++) {
        y += x[n];
      }
     
      return y;
    }

     

有关详细信息,请参阅Optimize Your Algorithm。

 

 

关注公众号: MATLAB基于模型的设计 (ID:xaxymaker) ,每天推送MATLAB学习最常见的问题,每天进步一点点,业精于勤荒于嬉

 打开微信扫一扫哦!

 

版权声明:本文为52geek原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/52geek/p/10434202.html