MATLAB是我們常用的工具。而快速學(xué)習(xí)和熟練掌握MATLAB對(duì)于高效完成工作很有意義。本文從親身的經(jīng)驗(yàn)出發(fā),介紹一下怎樣學(xué)習(xí)和使用MATLAB,這些辦法大都是本人和同事們經(jīng)常使用且被認(rèn)為不錯(cuò)的辦法。
1. 學(xué)習(xí)MATLAB的基礎(chǔ)語(yǔ)法略過(guò)了。如果你不太確定,可以在command下邊用一些簡(jiǎn)單的數(shù)字試一試。如果你習(xí)慣用C,那么注意要將運(yùn)算矩陣化,什么叫運(yùn)算矩陣化呢?就是盡量將循環(huán),尤其是帶if的循環(huán)用矩陣代替。舉個(gè)例子:比如把數(shù)組中所有大于1000的數(shù)據(jù)置為1000,而其它的數(shù)據(jù)不變,可以寫(xiě)作x(x>100)=100;如果采用for循環(huán)加if來(lái)做,那么效率是它的1/4。有時(shí)候似乎必須用for解決了,比如將一個(gè)1x6的數(shù)組改成2行3列,那么不妨可以找找?guī)旌瘮?shù),此例用reshape就可以解決。如果必須要用循環(huán),且對(duì)某數(shù)組x的若干下標(biāo)依次賦值,則一定要先定義x這個(gè)數(shù)組,例如可以用x=zeros(1,1000)。否則等于聲明了一個(gè)不定長(zhǎng)度的數(shù)組,效率十分低下。這是絕大多數(shù)程序效率損失的原因,當(dāng)然是有辦法進(jìn)行檢查的。查的辦法是用MATLAB提供的profiler工具。位于tools->open profiler,工具欄也有圖標(biāo)。在這個(gè)工具上寫(xiě)入你想運(yùn)行的函數(shù)名或者m文件名,程序就開(kāi)始運(yùn)行,運(yùn)行完畢后,會(huì)將其每個(gè)語(yǔ)句的執(zhí)行時(shí)間統(tǒng)計(jì)出來(lái),一下子就可以找到癥結(jié)。如果是循環(huán)體內(nèi)數(shù)組賦值類的操作,一般是不正常的,你應(yīng)該看看是否犯了沒(méi)有初始化的錯(cuò)誤。有時(shí)候一些函數(shù)會(huì)占用掉很多時(shí)間,你可以想想有沒(méi)有辦法替代它們,如果沒(méi)有就進(jìn)到這個(gè)函數(shù)內(nèi)部再去找一找,有時(shí)候會(huì)有優(yōu)化的空間。最后的結(jié)果往往是絕大部分時(shí)間已經(jīng)耗費(fèi)在了你很清楚的地方,比如調(diào)用的底層C函數(shù)、卷積運(yùn)算、矩陣運(yùn)算等等。
2. 在MATLAB常用的函數(shù)中,clear,clc,figure等等要牢記。另外,有時(shí)候需要注意某些庫(kù)函數(shù)的第二個(gè)返回值,往往就是你想要的,比如max函數(shù)的第一個(gè)值時(shí)最大的數(shù)值,而第二個(gè)就是數(shù)組的角標(biāo),直接用[value index]=max(x)就可以同時(shí)獲得,如果你把第二個(gè)數(shù)丟了,再用find去找,那就累死了。
3. 學(xué)習(xí)MATLAB的toolbox函數(shù)及其用法不需要看雜七雜八的書(shū),它的幫助足夠了。打開(kāi)help->product help,左側(cè)列出了很多toolbox,每個(gè)toolbox都有幾個(gè)子項(xiàng),Getting Started里邊具有最權(quán)威的上手示例,如果需要長(zhǎng)期使用,應(yīng)該把User’s Guide看一遍,沒(méi)有多少內(nèi)容,一般一兩天時(shí)間就夠了。里邊具有很多示例的代碼,有用的部分一定親手試一下。另外對(duì)于典型應(yīng)用,它都有Examples,雖然對(duì)于前沿領(lǐng)域來(lái)講,這些算法有點(diǎn)“老”,但是其精煉和高效是其他教材無(wú)可比擬的。它會(huì)給你展示在這個(gè)領(lǐng)域的專家最起碼的實(shí)驗(yàn)技能和討論的主題,甚至可以當(dāng)做所學(xué)專業(yè)可能的實(shí)驗(yàn)課本。如果你對(duì)上述過(guò)程中的具體函數(shù)及其實(shí)現(xiàn)感興趣,可以到Functions里邊找,那里對(duì)每個(gè)函數(shù)都有詳細(xì)的解釋。如果你對(duì)這個(gè)函數(shù)的實(shí)現(xiàn)很感興趣,那么直接在command中寫(xiě) “edit 函數(shù)名”,你就可以看到它的實(shí)現(xiàn)的源代碼。甚至某些圖形工具,例如fdatool、imtool、bertool等等。函數(shù)內(nèi)部有可能嵌套更深層的函數(shù),那么請(qǐng)你用一個(gè)你最熟悉的數(shù)據(jù)調(diào)用它,通過(guò)調(diào)試+單步跟蹤的方式一步一步查下去,由于數(shù)據(jù)你是熟悉的,因此你可以很快搞定其內(nèi)部工作方式。
有兩種例外,其一是MATLAB新的函數(shù)啟用的object類型,對(duì)其源碼進(jìn)行了封裝,通過(guò)edit可能看不到什么東西,那么怎么找到它的源代碼呢?有兩個(gè)辦法,其一是單步跟蹤,如果還解決不了,那么可以用上文提到的profiler工具,它會(huì)把調(diào)用到的函數(shù)一一列寫(xiě),很有可能是最頂層的某個(gè)函數(shù)進(jìn)不去,可以在其下的函數(shù)上定一個(gè)斷點(diǎn),看看數(shù)據(jù)跑過(guò)來(lái)怎樣,再往下一步步跟蹤,基本上就不會(huì)有單步跟不到的地方了。
另一個(gè)例外是遇到了MATLAB的buildin函數(shù)或者C函數(shù),那就真的沒(méi)辦法了,因?yàn)檫@兩個(gè)函數(shù)是沒(méi)有源代碼的。
MATLAB庫(kù)函數(shù)有統(tǒng)一的結(jié)構(gòu),第一部分是幫助信息,help可以看到的部分,之后是變量檢查,最后是實(shí)現(xiàn)過(guò)程。由于很多函數(shù)為了通用,實(shí)現(xiàn)的細(xì)節(jié)不是最優(yōu)的,并且對(duì)參數(shù)做了太多的檢查,如果你需要更好的性能,可以將其關(guān)鍵的語(yǔ)句提煉出來(lái),或者用純粹的矩陣運(yùn)算表述出來(lái),往往可以起到提速的作用。另外,你也可以把自己的注釋寫(xiě)在最前邊,這樣就可以通過(guò)help查到。
4. 有幾個(gè)在源代碼編輯器中的快捷鍵很管用,推薦掌握,ctrl+R注釋選定代碼,ctrl+T取消注釋,調(diào)試的F5,F10,F11之類,終止運(yùn)行中的程序ctrl+C。另外,如果你在源碼編輯器中閱讀源代碼時(shí)遇到一個(gè)函數(shù)想查看,直接在函數(shù)上點(diǎn)右鍵,選擇open selection即可。MATLAB保存之后的代碼也是可以撤銷的,甚至可以撤銷到打開(kāi)MATLAB時(shí)最原始時(shí)候的狀態(tài)。因此應(yīng)該常保存,以便于防止文檔丟失。源碼中可以通過(guò)兩個(gè)百分號(hào)“%%”分割源碼,甚至只執(zhí)行一部分,十分有利于比較長(zhǎng)的源碼。
如果在command中想調(diào)用函數(shù)或者變量,敲寫(xiě)前幾個(gè)字母再按tab鍵就可以得到匹配提示。如果需要查看變量,尤其是二維的數(shù)組,可以用workspace找到它并雙擊,打開(kāi)Variable Editor,這個(gè)編輯器可以和Excel互相復(fù)制粘貼,很是方便。另外,各種窗體的字體和顏色大多是可以改的,在Preferences中有fonts及其他項(xiàng)目,可以關(guān)注一下。最后值得一提的是plot畫(huà)出的圖像由于是矢量圖,如果數(shù)據(jù)點(diǎn)很多的話,復(fù)制到word中很可能會(huì)顯示卡殼或很慢,可以先拷貝到畫(huà)圖里邊,然后再貼到word,這樣就是位圖了。
5. 如果遇到了大運(yùn)算量,建議不要運(yùn)算結(jié)束后直接繪圖或者打印結(jié)果,而應(yīng)該采用運(yùn)算和結(jié)果顯示獨(dú)立的程序架構(gòu)。運(yùn)算是一個(gè)程序,計(jì)算后的結(jié)果通過(guò)save語(yǔ)句存儲(chǔ)成mat文件,再用另一個(gè)程序通過(guò)load讀取此文件,這樣的好處是可以防止結(jié)果丟失和篡改。另外,為了顯示直觀和調(diào)試的方便,可以實(shí)時(shí)的將計(jì)算的進(jìn)度顯示在command中,比如:
type={'AACH' 'BSCH' 'TCH/4.8_1' };
i=3;a=1;
fprintf('Calculating Logical Channel %s using %d antennas\n',cell2mat(type(i)),a);
則可以顯示出
Calculating Logical Channel TCH/4.8_1 using 1 antennas
如果制作了日志文件,那就更好了,首先打開(kāi)一個(gè)文件,寫(xiě)入時(shí)間戳clock,它是個(gè)數(shù)組,代表年月日時(shí)分秒之類。
logfid=fopen('log7-26.txt','a+');
fprintf(logfid,'time ');
fprintf(logfid,'%d.',clock);
fprintf(logfid,'\n');
之后依然用fprintf來(lái)打印,只不過(guò)需要加入logfid句柄。
fprintf(logfid,'Calculating Logical Channel %s using %d antennas\n',cell2mat(type(i)),a);
最后fclose(logfid); 用以關(guān)閉日志文件,幸運(yùn)的是,如果由于終止運(yùn)算而沒(méi)有執(zhí)行到這個(gè)語(yǔ)句,大多數(shù)日志結(jié)果也是存盤(pán)了的。
如果需要運(yùn)算完畢后自動(dòng)關(guān)閉計(jì)算機(jī),可以加入這么一句
!shutdown -s
嘆號(hào)代表執(zhí)行一個(gè)外部命令,后邊是windows默認(rèn)的關(guān)機(jī)程序,可以在運(yùn)行對(duì)話框?qū)嶒?yàn)一下,如果需要停止已經(jīng)關(guān)機(jī),那么再運(yùn)行shutdown –a。
6. MATLAB功能實(shí)在很多,新功能層出不窮,最好使用新的版本,MATLAB不一定總是對(duì)的,很多細(xì)節(jié)是有失偏頗的,我就遇到了幾次,最嚴(yán)重的一次是gaussfir函數(shù)出來(lái)的結(jié)果整個(gè)就是不對(duì)的,后來(lái)發(fā)現(xiàn)高版本已經(jīng)修正了,因此盡量使用更高的版本。有時(shí)隨著版本更新,會(huì)對(duì)你的代碼提出新的要求,比如用1i代替j代表復(fù)數(shù),或者用strcmp而不是~=比較字符串等等,它都會(huì)用紅線提醒,你可以根據(jù)它的提示予以更正。
7. 對(duì)于是否使用Simulink,我認(rèn)為它很直觀,但是缺點(diǎn)是效率不高(主要針對(duì)通信物理層仿真),尤其是蒙特卡洛仿真這種需要大數(shù)據(jù)量的循環(huán)仿真。當(dāng)時(shí)曾經(jīng)嘗試過(guò),學(xué)長(zhǎng)用Simulink去做,跑5萬(wàn)點(diǎn)就慢死了,我自己用代碼來(lái)寫(xiě),跑到50萬(wàn)點(diǎn)比他的快很多,后來(lái)又通過(guò)提取函數(shù)內(nèi)部實(shí)現(xiàn)和矩陣優(yōu)化等方法又有了很大的提升。有時(shí)發(fā)現(xiàn)循環(huán)和判斷太多了,只能用C來(lái)做。這是MATLAB的很多庫(kù)函數(shù)的選擇,因此如果你需要更高的效率,也可以這樣來(lái)做。MATLAB-C聯(lián)合編程雖然有利于提高運(yùn)算效率(甚至可以利用好多核),但是很難調(diào)試C代碼,在編寫(xiě)時(shí)一定要注意緩沖區(qū)溢出之類的問(wèn)題,因?yàn)樗鼤?huì)使整個(gè)MATLAB崩潰而重啟。因此最好先在VC調(diào)試好,再跟接口連接起來(lái)。當(dāng)然,調(diào)試的時(shí)候C代碼部分沒(méi)法單步,但是printf還是可以用的。另外,MATLAB的界面制作工具很好用,而且做出來(lái)的東西很贊,建議花點(diǎn)時(shí)間學(xué)一學(xué),能夠操縱按鈕,讀取復(fù)選框和文本的數(shù)值基本上就夠用了,它會(huì)使你的結(jié)果匯報(bào)變得很直觀。
很抱歉,由于思路未加整理,十分凌亂,謹(jǐn)此獻(xiàn)給常常使用MATLAB的同志們,希望能夠起到一點(diǎn)作用,使大家能善于利用MATLAB開(kāi)展自己的研究工作。