Simulink仿真入門到精通(十九) 總結回顧&自我練習


從2019年12月27到2020年2月12日,學習了Simulink仿真及代碼生成技術入門到精通,歷時17天。

學習的比較粗糙,有一些地方還沒理解透徹,全書梳理總結:

  • Simulink的基礎模塊已基本掌握,對不熟悉的模塊可以借助幫助文檔了解其功能;
  • Simulink信號基本掌握,了解了各種信號的外觀及意義的不同;
  • 對Simulink子系統的認識有待深入,對原子子系統需要進一步熟悉;
  • 對仿真過程及參數配置有所了解,對Debugger的應用不太熟悉;
  • 對回調函數有所認識,能夠簡單應用到參數預加載等場合;
  • 關於M語言對Simulink的操作有待進一步熟悉;
  • Simulink流控制有待進一步熟悉;
  • S函數掌握得不好;
  • 對模塊的封裝有所認識,能夠應用到子系統外觀繪制等場合;
  • 自定義庫、自定義環境估計暫且用不到;
  • 對代碼生成前的配置有了一定的認識,對各種優化代碼生成的技巧需要進一步練習;
  • 對TLC語言有初步的入門。

在學習過程中一直采用打字記錄的方法,其間一周由QQ拼音統計的結果如下,好處在於在仔細地輸入過程中對書中內容有了更多的思考時間,對參數配置都過了一遍,而不是走馬觀花,以后用到之時即使記不起具體內容,應該也會記得我在哪里曾經輸入過,方便回來查找。壞處在於花費了較多時間,且博客照搬書中文字,缺少自己的思考和創新,在以后的學習中,應該簡要記錄重點內容,加之自己的思考和描述。

全書共19章,最后一章由於沒有下載到相應的庫和工具,暫且放過。其他1~18章鏈接如下。在打字過程中難免疏漏,存在一些錯誤,希望日后查閱時能夠逐步改正,如果這些博客有幸為其他小伙伴所瀏覽,也歡迎評論指出錯誤之處。

Simulink仿真入門到精通(一) Simulink界面介紹

Simulink仿真入門到精通(二) Simulink模塊

Simulink仿真入門到精通(三) Simulink信號

Simulink仿真入門到精通(四) Simulink子系統

Simulink仿真入門到精通(五) Simulink模型的仿真

Simulink仿真入門到精通(六) Simulink模型保存為圖片

Simulink仿真入門到精通(七) Simulink的回調函數

Simulink仿真入門到精通(八) M語言對Simulink模型的自動化操作及配置

Simulink仿真入門到精通(九) Simulink的流控制

Simulink仿真入門到精通(十) S函數

Simulink仿真入門到精通(十一) 模塊的封裝

Simulink仿真入門到精通(十二) Publish發布M文件

Simulink仿真入門到精通(十三) Simulink創建自定義庫

Simulink仿真入門到精通(十四) Simulink自定義環境

Simulink仿真入門到精通(十五) Simulink在流程工業中的仿真應用

Simulink仿真入門到精通(十六) Simulink基於模型設計的工業應用概述

Simulink仿真入門到精通(十七) Simulink代碼生成技術詳解

Simulink仿真入門到精通(十八) TLC語言

學完本書,決定完成一個代碼生成的練習,以低通濾波器為例,以C51做載體,原因在於C51比較簡單,資源較少,我比較熟悉,另外C51可以借助Keil、Proteus等工具方便地進行仿真,驗證其正確性。

下面將介紹我的練習過程。

注:MATLAB版本2018a,Keil V5.24,Proteus8.6。

1. Simulink模型

1.1 模型外觀

說明:

  • 為了配合C51的數據類型,輸入輸出均設置為uint16,故需要進行數據類型轉換;
  • LPF(Low Pass Filter)內部結構及輸出表達式如圖所示;
  • 增益參數設為g,並在Model Properties→Callbacks→PreLoadFcn中設置回調函數為g=0.05;以便與在生成的代碼中對增益進行修改;
  • 在Mask Editor的Icon drawing commands中添加一下繪圖命令,繪制低通濾波器的大致形狀,使模塊美觀。
num=1;
den=[1,1];
ts=tf(num,den);
P=bodeoptions;
[mag,~,w]=bode(ts,P);
w=reshape(w,1,length(w));
mag=reshape(mag,1,length(w));
dB=20*log10(mag);
w=log10(w);
plot(w,dB);

傳遞函數G(s)=1/(s+1),使用bode獲取幅頻特性並繪圖。

補:本想選用DSP System Toolbox→Filtering→Filter Implementations中的Analog Filter Design作為低通濾波器。但此模塊階數(Order)較高時,計算比較復雜,可能導致C51的RAM空間不足,此處只是為了驗證代碼生成的過程,故選用比較簡單的模型。

1.2 模型配置

Solver Type:Fixed-step

Solver:discrete(no continuous states)

生成嵌入式代碼必須采用固定步長,由於沒有連續環節,故可選用離散解算器。

Device:Intel

Device type:8051 Compatible

注:MATLAB2018a中沒有此選項,但可以在低版本MATLAB中建立模型,選擇此項,再將模型在2018a中打開即可。

System target file:ert.tlc

Language:C

Generate code only:√

Default parameter behavior:Tunable

Create code generation report:√

Open report automatically:√

生成報告並自動打開。

Generate an example main program:

自己編寫main主函數,不需生成示例。

其他參數保持默認。

1.3 模型仿真

在Simulink中建立如下模型。

輸入信號由正弦信號和正態隨機數疊加構成。

仿真時長30s,步長0.01s,得到仿真結果如下圖所示。

可以看到,模型具有較好的濾波效果。

1.4 代碼生成

配置好模型參數后,選定好工作目錄,按下Ctrl+B,啟動代碼生成。

得到Report如下圖。

在LPF_data中可以看到g的定義,在此處可進行修改。

LPF_step函數為核心函數。

void LPF_step(void)
{
  real_T rtb_Add1;
  real_T tmp;

  /* Sum: '<S1>/Add1' incorporates:
   *  DataTypeConversion: '<Root>/Data Type Conversion'
   *  Gain: '<S1>/Gain'
   *  Inport: '<Root>/In1'
   *  Sum: '<S1>/Add'
   *  UnitDelay: '<S1>/Unit Delay'
   */
  rtb_Add1 = ((real_T)LPF_U.In1 - LPF_DW.UnitDelay_DSTATE) * LPF_P.g +
    LPF_DW.UnitDelay_DSTATE;

  /* DataTypeConversion: '<Root>/Data Type Conversion1' */
  tmp = floor(rtb_Add1);
  if (rtIsNaN(tmp) || rtIsInf(tmp)) {
    tmp = 0.0;
  } else {
    tmp = fmod(tmp, 65536.0);
  }

  /* Outport: '<Root>/Out1' incorporates:
   *  DataTypeConversion: '<Root>/Data Type Conversion1'
   */
  LPF_Y.Out1 = tmp < 0.0 ? (uint16_T)-(int16_T)(uint16_T)-tmp : (uint16_T)tmp;

  /* Update for UnitDelay: '<S1>/Unit Delay' */
  LPF_DW.UnitDelay_DSTATE = rtb_Add1;
}

2. Proteus硬件連接

2.1 帶噪聲的正弦信號發生器

由於Proteus中沒有直接產生白噪聲的元件,在這里采用基於EPROM的波形發生方式。首先采用外部函數將白噪聲數據寫入txt文件,在轉換為二進制數據加載到27256中,得到噪聲信號。

比如我采用R語言生成這些數據,R代碼如下。

#生成波形數據部分
noise<-rnorm(500,mean=36*3.5,sd=36)
noise<-round(noise)
noise_H<-as.character(as.hexmode(noise))
#寫入文件部分
write.table(noise_H,file='C:/Users/lenovo/Desktop/noise_H.txt', row.names =FALSE,col.names =FALSE, quote =FALSE)

由於正態分布在3倍標准差范圍內的概率已經達到99.74%,因此此處選3.5足夠。得到數據文件如下:

利用從網上下載的轉換工具進行轉換:(感謝這位博主)

https://download.csdn.net/download/mouseleoz/10905646

即得到可加載的bin文件。

555定時器產生周期性信號,74LS161構成16進制計數器,噪聲數據即在27256的D0到D7端口輸出。

2.2 A/D轉換

將上面的輸入信號封裝為子電路圖,總電路圖如下。

利用11通道12位串行A/D轉換芯片TLC2543進行A/D轉換,TLC2543引腳說明如下。

AIN0~AIN10為模擬輸入通道。
CS為片選端,低電平有效。
DATA INPUT為串行數據輸入端。
DATA OUT為A/D轉換結果的三態串行輸出端。
EOC為轉換結束端。
I/O CLK為I/O時鍾端。
REF+為正基准電壓端。
REF-為負基准電壓端。
VCC為電源端。
GND為地。

2.3 D/A轉換

利用DAC0832進行D/A轉化,由於0832是8位D/A轉換器,因此損失了部分精度。

DAC0832引腳功能說明:
DI0~DI7:數據輸入線,TTL電平。
ILE:數據鎖存允許控制信號輸入線,高電平有效。
CS:片選信號輸入線,低電平有效。
WR1:為輸入寄存器的寫選通信號。
XFER:數據傳送控制信號輸入線,低電平有效。
WR2:為DAC寄存器寫選通輸入線。
Iout1:電流輸出線。當輸入全為1時Iout1最大。
Iout2: 電流輸出線。其值與Iout1之和為一常數。
Rfb:反饋信號輸入線,芯片內部有反饋電阻。
Vcc:電源輸入線 (+5v~+15v)。
Vref:基准電壓輸入線 (-10v~+10v)。
AGND:模擬地,摸擬信號和基准電源的參考地。
DGND:數字地,兩種地線在基准電源處共地比較好。

3. Keil工程

3.1 main函數

#include<reg52.h>
#include "LPF.h"
#include "LPF_private.h"
#define uint unsigned int
#define uchar unsigned char
#define y P2
uint volt; 
uchar addr;
sbit CLK=P1^7;//定義時鍾信號口
sbit DIN=P1^6;//定義2543數據寫入口
sbit DOUT=P1^5;//定義2543數據讀取口
sbit CS=P1^4;//定義2543片選信號口
sbit P2_5=P2^5;

void read2543(uchar addr)
{
    uint ad=0;
    uchar i;
    CLK=0;
    CS=0;//片選段,啟動2543
    addr<<=4;//對地址位預處理
    for(i=0;i<12;i++) //12個時鍾走完,完成一次讀取測量
    {
        if(DOUT==1)
            ad=ad|0x01;//單片機讀取ad數據
        DIN=addr&0x80;//2543讀取測量地址位
        CLK=1;
        ;;;//很短的延時
        CLK=0;//產生下降沿,產生時鍾信號
        ;;;
        addr<<=1;
        ad<<=1;//將數據移位准備下一位的讀寫
    }
    CS=1;//關2543
    ad>>=1;
    volt=ad;//取走轉換結果
    }

void main()
{
    addr=0;
    LPF_initialize();
    TMOD=0x01;
    TH0=0xD8;
    TL0=0xF0;
    TR0=1;
    EA=1;
    ET0=1;
    while(1)
    {
        read2543(addr);
    }
}
void Timer0_ISR(void) interrupt 1
{
    TH0=0xD8;
    TL0=0xF0;
    LPF_U.In1=volt;
    LPF_step();
    y=LPF_Y.Out1/16;
    
}

在while(1)中不斷讀取A/D轉換結果,在定時器中固定步長執行LPF_step函數。定時器初值D8F0=55536=2^12-10000,故步長為0.01s。

由於讀取的轉換結果是12位數據,因此除以16轉換為8位,同時損失了精度。

3.2 編譯方法

將Simulink生成的.c和.h文件加入到工程下,啟動編譯。

編譯無誤即可得到hex文件,將其加載到單片機中,啟動仿真,得到示波器結果如下所示。

可以看到,該電路完成了濾波任務。

4. 模型評價總結

該實例僅是為了練習Simulink生成代碼的過程,實際效果並不理想,主要缺點有:

  • 中間經過A/D和D/A轉換,損失了精度,得到的結果是離散的;
  • 算法導致輸出比輸入有一定的相位滯后。

如圖,放大后即可看到其離散性,實際效果甚至不如一階RC濾波器(有源或無源)。

在這個過程中對Proteus的總線創建、標號添加及子電路圖繪制方法進行了回顧。

對C51的端口賦值方法進行了復習,#define y P2。

在建模過程中參考了以下網頁,對這些博主表示感謝。

Simulink生成代碼在C51中的用法:https://blog.csdn.net/weixin_41911709/article/details/90648818

TLC2543的用法:https://blog.csdn.net/nanfeibuyi/article/details/80564741

通過此練習,起碼簡單驗證了Simulink生成C代碼的可行性,其他學習有待以后深入。

總之,本書由淺入深,還是非常值得一讀,錯誤也比較少,即使偶爾有拼寫錯誤也不影響閱讀。

我的模型文件打包如下:

鏈接:https://pan.baidu.com/s/1iedYzuQbcezU4_-fW2s6tw
提取碼:k3fj


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM