天天看點

定點設計師快速入門

  • 定點設計師産品說明
  • 系統要求

教程

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

屬性。您可以使用

setfimath

fimath

對象附加到

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      

a

ProductMode

屬性設定為

KeepMSB

,其餘而的

fimath

屬性使用預設值。

注意

有關

fimath

對象及其屬性和預設值的詳細資訊,請參閱fimath對象屬性。

位增長

表下顯示

fi

對象

A

狀語從句:

B

SumMode

狀語從句:

ProductMode

屬性使用預設

fimath

FullPrecision

時的位增長。

一個 Sum = A + B. 産品= A * B.
格式

fi(vA,s1,w1,f1)

fi(vB,s2,w2,f2)

- -
符号

s1

s2

Ssum

=(|| )

s1

s2

Sproduct

=(|| )

s1

s2

整數位

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

對象

F

F

指定和的字長和小數長度。在預設

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) = b

b

的值賦給由下标向量

I

指定的

a

的元素,保留同時

a

numerictype

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)訓示下标向量

(:)

處的值發生更改。但是,輸出

acc

numerictype

保持不變。由于

acc

是标量,是以如果您使用

(1)

作為下标向量,則也會收到相同的輸出。

對于 n = 1:numel(x)
    acc(1)= acc + x(n);
  結束
      
acc = 

     1
      s32,0

acc = 

     3
      s32,0

acc = 

     6
      s32,0      

acc

numerictype

for

循環的每次疊代中保持不變。

下标指派還可以幫助您控制函數中的位增長。在函數

cumulative_sum

中,

y

numerictype

不會更改,但由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

對象之一的資料類型,同時允許您指定舍入方法和輸入值中的溢出操作。

有關如何實作

accumpos

accumneg

的詳細資訊,請參閱避免生成代碼中的多字操作

溢出和舍入

在執行定點算術時,考慮溢出的可能性和後果。

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 配置。如果函數傳回 

,則 

fi

 對象使用預設 fimath 配置。

縮短 fi 對象的數值類型顯示

要進一步減少輸出量,可以将 

NumericTypeDisplay

 設定為 

'short'

。例如,

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

a = fi(pi)

a =
    3.1416
      s16,13

      

加速定點仿真

在 MATLAB 中嘗試

此示例說明如何使用 

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中試一試

此示例顯示如何通過檢測用于最小/最大日志記錄的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

在此函數中的變量

y

z

用作輸入和輸出。這是一個重要的模式,因為:

  • 您可以設定的資料類型

    y

    z

    外設功能,進而使您可以重複使用的功能,兩個定點和浮點類型。
  • 生成的C代碼将在函數參數清單中建立

    y

    z

    作為引用。有關此模式的更多資訊,請參閱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

    建議用于雙精度的預設資料類型,其中

    T

    numerictype

    對象或其中一個字元串

    {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位用于所提出的分數長度溢出,建議設定定點特性

y

z

從所述儀表化代碼生成報告。

在工作流程的這一點上,您使用了真正的定點類型(而不是在确定資料類型的早期步驟中使用的縮放雙重類型)。

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

     的 

    codegen

    codegen 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學習最常見的問題,每天進步一點點,業精于勤荒于嬉。

 打開微信掃一掃哦!