周世欽+王波濤
摘要:通過MATLAB程序轉C代碼的研究與應用可以加快軟件、算法從研究到實際應用的進程,提高軟件、算法研發(fā)的效率。對于轉C的流程、方法、注意事項以及限制等問題需要深入研究。以MATLAB2014的轉C工具MATLAB Coder為基礎,分析了MATLAB轉C代碼的細節(jié),完整地研究了MATLAB代碼轉成C代碼的整體流程。通過合理的轉C規(guī)范,MATLAB支持常規(guī)算法和大多數工具庫函數轉C,保持原功能、邏輯不便。使用動態(tài)預分配內存,外置接口,簡化函數等方法,使得一部分非常規(guī)算法、不支持轉C或限制性MATLAB函數能夠正確轉化為C語言代碼。
Abstract: The research and application that MATLAB program transforming to C code can expedite the progress from algorithm or software research to practical application and improve the efficiency of software or algorithm development. These problems about transformation's processes, methods, points for attention, limitation and so on need to be further researched. Based on MATLAB Coder of Matlab2014 tool for transforming to C, it analyses details of MATLAB transforming to C code and its whole process. With reasonable transformation specification, MATLAB support general algorithm and most tool functions to transform to C code, which retain intrinsic function and logic. Using some methods such as dynamically pre-allocating memory, external interface and simplifying functions, it also makes a part of uncommon algorithm and MATLAB tool functions which are not support to transform to C or have transformation limitation possible to successfully transform to C language code.
關鍵詞:Matlab轉C;Coder;代碼規(guī)范;轉C流程;轉C限制
Key words: Matlab transformingto C;Coder;code specification;transformation process;transformation limitation
中圖分類號:TP311 文獻標識碼:A 文章編號:1006-4311(2018)02-0182-04
0 引言
目前,利用Matlab軟件[1]作為工具來進行算法設計、驗證已經成為研究者們首選的手段之一[2],而通過Matlab轉C,可以直接將Matlab函數轉換成高效優(yōu)化的C程序,移植到嵌入式環(huán)境中去[3]。
Matlab Coder工具是MathWorks公司推出的Matlab2014a版本中一個重要的產品[4],它可以將Matlab 函數直接生成C代碼[5]。借助Matlab Coder,軟件工程師不再需要將設計的算法進行C語言重新編程,而是利用Matlab軟件中強大的函數庫[6],按照通用的轉C流程,參照轉C規(guī)范,通過建立Matlab函數,并設置目標語言所需要的參數,生成能夠脫離Matlab環(huán)境獨立運行的C代碼,這樣就大大減輕了軟件工程師的編碼工作[7]。
對于基于Matlab2014a版本Coder的Matlab轉C,本文介紹經過實踐的、行之有效的轉C方案與流程,并將轉C中遇到的問題與解決方法、思路在下文中進行介紹,以助于更好的實現(xiàn)轉C工作。文章接下來的一節(jié)將詳細介紹Matlab程序整體轉C代碼流程。對于轉C過程中的幾個常遇問題及其處理方法,將在隨后的一節(jié)中羅列出來并給出詳細說明。實際轉C過程中,可能會存在障礙和一些限制,對此,創(chuàng)新性地通過動態(tài)預分配內存,外置接口,簡化函數等方法化解,在文章的最后一節(jié)將會對此進行詳細說明。
運用matlab轉C方法,可以方便、快捷、準備地將matlab算法轉化成C語音實現(xiàn),使之運用在嵌入式環(huán)境成為可能。通過本文的詳細介紹,能夠使讀者對于使用matlab coder工具進行matlab轉C有更加直觀、系統(tǒng)的認識;引導讀者正確使用2014a版本的matlab coder進行matlab轉C工作;為從matlab算法設計、仿真、驗證到算法的C語言實現(xiàn)、嵌入式環(huán)境應用提供了一條切實可行的途徑;同時,文章中也著重列出了多項技術要點,是轉C工作順利進行和是否成功的關鍵所在,對實際matlab轉C工作有著重要的借鑒意義。但也應當了解到, Matlab轉C依然存在著無法解決的情況,這些情況并不在本文討論范圍之內,故應盡量避開之,或者,隨著Matlab Coder的升級,某些問題可隨之化解。
1 Matlab程序整體轉C代碼流程
借助Matlab Coder轉C有其一定的步驟與要求規(guī)范,Matlab2014a版本Matlab Coder的轉C流程如圖1所示,以及其重要的幾步工作如下所述。簡單的Matlab函數經過簡單的調整,經過如下步驟和要求就能成功轉C,而面對復雜的情況時,除了要按照上述流程嚴格執(zhí)行外,還要根據具體情況做出相應的修改才能達到某些步驟的要求。endprint
1.1 封裝Matlab函數
將Matlab程序所要實現(xiàn)的功能封裝成一個Matlab函數文件,并將其所實現(xiàn)的功能結果作為函數輸出,將所需的數據作為輸入,再將整個函數的代碼進行規(guī)范,以此作為轉C函數。對于Matlab程序,腳本文件[8]是無法通過Coder 工具轉成C代碼的,只有函數文件能通過Coder工具轉成C。
轉C前要對函數代碼進行轉C規(guī)范。大部分不符合規(guī)范的代碼都可以通過代碼分析器檢測出來(編譯文本框的左側有對應的提示),可通過此依次做出相應的修改,以達到轉C要求。小部分是代碼分析器檢測不到的,需要自己發(fā)現(xiàn)或者轉C編譯報錯時才能從錯誤報告中找到,并對其進行規(guī)范。完成規(guī)范之后才能通過Matlab Coder進行轉C。
1.2 函數整體分析
利用Code Generation Readiness Tool整體分析函數是否符合轉C要求。此步驟主要檢查轉C函數中是否調用了不支持轉C的Matlab函數或Matlab對象[9](如:數據類型),Matlab編程[10]是否正確,是否存在嵌套調用等不符合轉C要求規(guī)范的算法,但是,不檢查語法細節(jié)是否符合轉C要求規(guī)范。
對于檢測出的、不符合轉C要求的,只能對Matlab程序的算法進行修改,去除不符合要求的部分,甚至要對部分算法的功能進行調整、取舍。
1.3 庫函數轉C限制檢查
確定轉C函數中調用的Matlab庫函數是否存在轉C限制??梢圆榭碝atlab幫助文檔中的轉C函數支持列表,對照的查看是否存在轉C限制的Matlab工具函數。若調用的Matlab函數存在轉C限制,并且調用時沒有遵循這個限制,則無法轉C。
1.4 建立轉C工程并運行
創(chuàng)建轉C工程,加載需要轉C的功能函數,設定輸入變量的數據類型及其大小,選擇轉C后代碼的輸出形式,點擊“編譯”或“Run”即可開始執(zhí)行轉C。創(chuàng)建轉C工程時,創(chuàng)建的轉C工程和需要轉C的功能函數都應存放在當前Matlab工作路徑下。
1.5 轉C錯誤檢查與修改
轉C出現(xiàn)錯誤,點擊“Open error report”或“View Report”打開錯誤報告,找到首條錯誤報告并查看錯誤信息和出錯代碼位置,根據相關信息提示修改或規(guī)范源代碼,使得其在不改變源代碼功能邏輯的情況下符合轉C 規(guī)范,保存后再次進行轉C編譯。以此重復類推來逐個消除轉C錯誤,直到最終成功完成轉C編譯。
1.6 轉C成功
成功完成轉C。點擊 “View Report”打開轉C結果報告,可以查看到數據類型等的轉C相關信息,也羅列了轉C的輸出文件。在轉C工程路徑下會有個codegen文件夾,里面根據文件輸出類型和轉C工程名新建文件夾,存放著相關輸出的文件,其中.c和.h文件為輸出的C代碼文件,與Matlab源代碼同名文件為其主調函數文件。
1.7 代碼驗證
對于轉出的C代碼正確與否,coder提供的方法是生成mex文件用于驗證,但是mex驗證不成功時,又無法通過其分析原因所在。對此,不再用mex函數驗證,直接以代碼驗證的方式進行。其主要解決的問題是,代碼驗證不通過時,可以同步分析C程序和Matlab程序以找出轉C失敗原因。
新建一個C語言工程用于調用轉C后的功能函數C語言代碼,產生結果并和用Matlab運算產生的結果進行比較,如果結果一樣或者誤差在合理范圍內,則說明轉C成功,轉出的C代碼功能完整,邏輯正確,可直接使用。如果結果不一致、誤差極大,則說明轉C出現(xiàn)問題,可單步運行C程序和Matlab程序,看誤差最先出現(xiàn)在那里,并分析是什么原因造成的,修改或規(guī)范它,然后再進行轉C編譯和代碼驗證,直到二者結果一致或者誤差在合理范圍內為止。代碼驗證時,C程序和Matlab程序用的輸入應當一致,并用多組數據進行驗證。如果有必要,也可以將程序運行中的、有代表性的對應數據進行比較,以此確保轉出的C程序功能、邏輯與源代碼一致。
2 轉C過程常遇問題及處理方法
轉C過程中會遇到諸如不符合Matlab Coder轉C規(guī)范的語句、對程序進行轉C規(guī)范時,不符合程序功能邏輯的修改、Matlab和C語言的編程差異[11]導致的轉C問題、Matlab轉C適應性問題與限制性問題、以及轉C對Coder 工具的影響等諸多方面的問題,甚至有些問題不能得到反饋,需自己察覺與分析。
根據Matlab轉C過程遇到的一些特別的情況總結的一些轉C細節(jié)概述以及對此做出的一些處理,在此列出僅供參考,以避免遇到此情況。
2.1 統(tǒng)籌編程
如果計劃要將所編寫的Matlab程序轉成C代碼,那么在設計算法之初,就一定要先參考轉C流程步驟的第二部和第三步,否則就有可能出現(xiàn)完成了算法設計卻無法轉成C代碼的窘境。若到轉C時才發(fā)現(xiàn)這些問題再去改,則有可能需要對算法進行重新設計,改動量較大,甚者是無法修改的情況。
2.2 數據類型變化
Matlab變量轉C過程中,變量的第一次調用(多為賦值語句,并為非可忽略語句),決定了它在C語言中的數據類型。如果在Matlab程序中,由于引用賦值(如下面第2)行語句)而導致它的類型發(fā)生變化,那么,則在轉C過程中就會報錯,這是由于Matlab和C語言的編程差異導致的[11]。Matlab程序中變量的數據類型可以發(fā)生改變,而C語言程序中卻不可以。這樣,變量a就從double變量變成了復數變量了。這樣的情況在轉C中會報錯。
2.3 if語句轉C
轉C時,Matlab程序中的if語句后面不能是非標量的形式(如數組或結果為數組的表達式),否則報錯。Matlab中,if后面的非標量,只有當全體為真時才認為是真(true),否則為假(false),所以轉C時可以據此做一定的的修改,使得if后面為一個值的標量即可。endprint
2.4 被忽略的變量
Matlab程序中,會被“忽略”的變量需要事先“聲明”,即預分配內存[12],否則會出錯。Matlab程序可以在運算中動態(tài)新增變量,有些變量雖然寫在代碼中,但是可能由于沒有執(zhí)行到這段代碼,所以內存中也就沒有出現(xiàn)這個變量,即被“忽略”了。但是在轉C過程中,這些變量卻要求事先“聲明”,這是Matlab與C語言編程差異導致的。
轉C時會報錯第7)行變量a33未被聲明過,因為第5)行變量賦值語句在選擇語句中,屬非一定執(zhí)行語句,所以被“忽略”了。
2.5 變量信息問題
把某項數據固定的寫在Matlab函數的變量中,則轉出的C代碼中,這個變量的信息(長度,數據類型等)都是固定了的,若在Matlab程序中對這個變量的信息有修改,則這些修改未必會反映到轉C中,如果錯誤使用這些信息,將導致程序邏輯錯誤。其他問題導致的變量信息修改未反映到轉C中也會出現(xiàn)這樣的情況。
2.6 錯誤的預分配內存
錯誤的預分配內存會導致轉出來的的C代碼邏輯錯誤,即Matlab轉的C代碼中,某些算法的運行結果、次數、或者數值等出現(xiàn)偏差,從而導致和原來的Matlab程序最終結果不一致。分配過多有可能會造成預分配內存前后的Matlab程序運行邏輯不一致,這屬于錯誤的轉C規(guī)范。分配過少則有可能導致Matlab轉出來的C程序邏輯錯誤,甚至轉出來的C程序在運行時會出現(xiàn)堆棧溢出[13]的現(xiàn)象。
多分配會導致原來的變量冗余,從而有可能導致后面的算法偏離原先設計。如果多分配內存是無法避免的,那么也可以在后面的算法中,加入修正語句,或避開這些冗余量的影響,也可以達到正確效果。預分配內存過少,則在轉C的C代碼后初始化這個變量時會保留錯誤的該變量信息(如數組長度,數據類型等)和申請內存不足,如果后面的算法使用了這些錯誤的信息,則程序運行時會偏離原先設計,甚至會有可能越界訪問內存而導致C程序運行時堆棧溢出。所以應避免預分配內存過少。
2.7 轉C致軟件崩潰
Matlab函數的轉C致使Matlab軟件崩潰,直接退出Matlab軟件程序的情況。這樣的情況不常遇見,但很棘手,是轉C的一大障礙。這個故障無法通過反饋分析原因,只能一次次調整程序試出來怎樣的形式才不至于Matlab崩潰。在實踐中發(fā)現(xiàn),Matlab崩潰似乎和復數或復數表達式作為參數調用其它函數再轉C有關。所以,建議轉C的函數盡量避免用復數作為參數參與調用,改用實部虛部做參數,而后在函數內合成復數的方式。另外,避免用作參數的變量重新賦值,尤其是改變長度的幅值。
3 轉C特殊處理辦法
3.1 動態(tài)預分配內存
提供了一種預分配內存的思路,具體是,下一步的預分配內存,是要根據上一步的結果來做出操作的,所以這樣需要預分配的內存長度是未知的。這種情況下,用一個變量作為參數來預分配合適長度的內存。而這個變量的值,則根據上一步運算結果和算法要求而得到。如此,轉出來的C程序就可以根據實際算法運算情況來預分配不同長度的“變量”,而不是固定長度的數組。
預分配內存是Matlab函數轉C前,規(guī)范Matlab代碼時一步重要的工作。轉C時,大部分的變量都是依照“第一次賦值語句”來聲明變量的,而部分變量在Matlab里的第一次出現(xiàn)卻不是賦值語句,而是循環(huán)語句里的引用賦值語句(例如:a(i)=i)。這樣的情況在Matlab程序中會實時地自動生成和加長對應的變量(即會根據算法迭代而增加變量長度),而轉C過程卻無法適應這種情況,所以要求對這個變量先預分配內存。預分配內存的方法是在其調用之前加一句相對應賦值語句,以起到“第一次賦值語句”的作用。如果這里的“變量”長度是不固定的,則可以采用動態(tài)預分配內存方式。
3.2 外置接口轉C
避開某些轉C限制的特殊處理方法,一種妥協(xié)思維。Matlab自帶的Coder轉C工具有其支持轉C函數庫,包括大多數普通常用的函數和信號處理函數。然而,有些函數在Matlab轉C過程中卻有不同的限制。
重采樣[14]是很多算法和系統(tǒng)中的重要環(huán)節(jié)。在設計算法之時,一般使用Matlab信號處理的resample函數,然而其在轉C時卻有重采樣數據的長度必須為一個確定值,上、下采樣率必須為確定值的常量。在很多算法或系統(tǒng)中,需要重采樣的數據,其長度是不確定的。對于這個情況,設定一個預分配內存足夠大的另一個“變量”,充當外置接口,專門作為resample的參數,把需要處理的數據值轉移到其中,多余的部分忽略(相當于補0值),然后對整體做處理、轉C,最后再從結果中提取出有用的部分(對應有用輸入參數部分的結果)即可。
經過驗證,確認了這一方法的可靠性,多余部分(補0值的部分、非有用部分)的存在不影響前面的有用輸入參數部分的運算結果,從整體結果中取出的有用結果與單單輸入有用參數所得到的結果相同。通過這種方式,使得在一定數據長度內,既能滿足resample轉C的這項限制要求,又適應了不同長度數據作為輸入的情況。當然這里不同的長度的數據只要不超過前面所說的“一定長度”即可。
3.3 簡化函數
通過對Matlab某些不支持轉C的函數進行簡化函數處理(去除冗余語句),使得它需要的部分功能可以轉C。但是,并不是所有的不支持轉C函數都能通過這種方式從而能轉C,只是個別函數能實現(xiàn)。
一些不支持轉C的函數,可能為了適應多種情況而使用了一些不支持轉C的方法,為了能夠轉C,將這些方法去除或替換。但是這樣一來,原函數的功能就有一定程度上的削弱或缺失。如果,可以確定這些削弱或缺失的功能是算法中所不需要的,那么就可以放心的通過這樣的處理方式以使得程序能夠轉C,不然,無法通過這種方式使得這個函數能夠轉C。整個流程很簡單,關鍵是要自己摸索著查找修改點,然后對其進行正確的簡化操作,并確定這樣子的操作不會對整個算法有影響。endprint
Matlab庫函數中的medfilter1、lpc函數是不支持轉C的,通過上述思路調整后得以轉C,到達設計要求。以lpc函數為例,大致介紹簡化函數轉C流程:
①在matlab庫函數相應的文件夾下找到lpc函數,將其復制到當前工程目錄下;
②再用Code Generation Readiness Tool對matlab函數整體分析;
③提示lpc函數中try/catch語句不支持轉C。
④進入工程目錄下的lpc函數,將try/catch相關語句去掉并保存,通過可行性分析后再轉C。
⑤再比較matlab程序和C程序的結果,得以驗證這樣操作能夠滿足要求。
4 結束語
Matlab程序轉C代碼是一項集工程創(chuàng)建、代碼規(guī)范[15]、錯誤分析與修正、對比驗證于一身的工程,有其一套行之有效的工作流程和解決方案。符合轉C條件的Matlab程序,通過Matlab Coder工具,按照轉C流程進行操作能夠將完整Matlab程序轉成C代碼。通過Matlab程序的轉C,縮短了算法研發(fā)與實際應用之間的距離,提高了工程師的研發(fā)效率。本文研究了MATLAB程序轉C代碼的方法,介紹了以Matlab2014a版本Coder為基礎的轉C流程,給出了轉C注意事項與處理意見,并且針對一些以前沒有解決辦法的轉C阻礙提出了創(chuàng)新性的解決思路與方法。但是也應看到,Matlab轉C也并不是包治百病的,除了轉C流程第二第三步提到的限制外,在Matlab編程中還應該注意到Matlab和C語言的編程差異以及適應性問題[11],這些都在一定程度上限定了Matlab算法編程。同時,我們可以看到,通過對某些轉C限制進行某種“妥協(xié)”,也可以繞開這樣的限制,以達到我們的目的。
參考文獻:
[1]印金國.遙控信號調制與Matlab程序實現(xiàn)[J].電腦編程技巧與維護,2006(10):25-29.
[2]劉浩,韓晶.MATLAB R2014a完全自學一本通[M].北京:電子工業(yè)出版社,2015.
[3]廖燦燦,張樹群,雷兆宜.Matlab Coder生成C代碼的研究與應用[J].計算機與現(xiàn)代化,2013(3):175-178.
[4]Online MATLAB. MATLABR2014a,MATLAB Coder[EB/OL],http:/ /www.mathworks.cn /products /matlab-coder/,2014-10-10.
[5]Online MATLAB.從 MATLAB 代碼生成 C 和 C++ 代碼[EB/OL]https://cn.mathworks.com/products/matlab-coder.html,2014-10-10.
[6]李???基于MATLAB函數庫增強VB數值計算能力的研究[J].計算機工程與應用,2003,39(23):57-59.
[7]陸楠.自動C/C++代碼轉換工具提高MATLAB設計效率[J].電子設計技術,2011(7):38.
[8]黃根嶺,張清淼,周利紅.MATLAB/Simulink在通信原理教學中的應用[J].鄭州鐵路職業(yè)技術學院學報,2015(3):94-97.
[9]劉春輝.C++、java、matlab面象對象編程之比較[J].硅谷, 2010(6):75.
[10]蔣鵬.MATLAB編程的特點與優(yōu)化[J].數字技術與應用, 2016(2):183.
[11]陳榮榮.C++與Matlab的基本語法比較[J].電腦編程技巧與維護,2011(14):32-34.
[12]李月潔,李蘭友,尤一鳴.內存預分配管理[J].儀器儀表用戶,2006,13(5):104-105.
[13]李宛娜.堆棧溢出技術剖析[J].哈爾濱職業(yè)技術學院學報, 2008(1):115-116.
[14]宗志毅,王曉音,楊莘元.多率信號處理中的重采樣技術[J].電子信息對抗技術,2003,18(3):37-41.
[15]李大勇.淺談軟件開發(fā)中代碼規(guī)范的問題[J].電子技術與軟件工程,2015(15):50.endprint