面向矩陣的編程——【轉帖】寫給matlab新手

【kit_147】這篇文章寫得很好,很多時候用MATLAB寫程序的確還是脫離不了用編程語言編程的思想;MATLAB其實是要“面向矩陣編程”,所以稍微有所不同。

轉自 http://www.cnblogs.com/wmlong/archive/2010/10/31/1865578.html (貌似這個也是轉帖)

 

寫給MATLAB新手

 

本人接觸matlab已經有5年多的時間了,一直想寫點東西,但是之前不知道放在哪裏才能發揮它的最大作用,直到幾天前碰上了這個論壇(有點像諸葛亮遇見姜維,哈哈)。

廢話不說,我想借貴論壇寶地,寫一些經驗給使用matlab的新手們,當然了,老大們也可以看看,不嫌棄我寫得粗糙的話還可以指點一下,先謝過了~~~~

首先我想說的是,matlab跟其他語言不一樣(我用的比較多的編程語言,除了matlab就應該是c或c++了,VB和Delphi也接觸過,我想版面(matlab版)大部分人也差不多),如果你抱着“把其他語言的思想運用在matlab裏面”的話,那麼我想,即使程序運行不出錯,也很難把握matlab的精髓,也就很難發揮matlab的作用了。所以,如果你是希望掌握一門語言、一個工具,使它更有效爲你服務的話,那麼,希望本文對你有所幫助,請精讀;如果你是希望matlab作爲VC的附屬品,即你不想在matlab上面花太多功夫,只純粹想用matlab來完成VC做不了或很難做成的任務的話,那麼,本文你也應該至少瀏覽一下。

Matlab是一個基於矩陣運算的軟件,這恐怕是衆所周知的事情了,但是,真正在運用的時候(就是在編程的時候),許多人(特別是初學者)往往沒有注意到這個問題,因此,for循環(包括while循環)滿天飛…………..這不僅是暴殄天物(沒有發揮matlab所長),還浪費了你寶貴的時間。對此,版友MVH在他的“MATLAB 小技巧”一文中也有所涉及,雷同的東西我也就不重複了,matlab的“幫助”裏面也有相關的指示。我這裏想說的一點是,初學者往往在初始化矩陣的時候注意到這個問題,懂得了使用矩陣而不是循環來賦值,但是,在其他環節上,就很容易疏忽,或者說,仍然沒有擺脫C++的思想。舉個例子吧,下面的代碼是我的一個師弟寫的,我想他接觸matlab也有2、3年時間了(在此說明一下,接觸2、3年並不是表示每天都會跟matlab打交道,我本人也不是,只是在一年某幾個時間段裏面連續使用),但是仍然會出現類似的問題:

J = 0;
lt = size(imf1,2);
for (i = 1:lt)
    if (abs(imf1(i)) > 1)
        J = 1;
        break
    end
end

上面的代碼實現了一個目的――檢查信號imf1(一個向量)是否存在絕對值大於1的點,這顯然是基於C++的思想寫出來的。如果在matlab下面,其實用兩個語句就足夠了(當然,可以合併爲一個):

q = find(imf1>1);
J = ~isempty(q);

這樣的修改帶來的好處是很可觀的。

又如:

for j = 1:num
    imf1(start1+j) = 2*li1(j+1) - imf1(start1+j);
end

這是一個對稱翻折的問題,它完全可以用以下這個語句簡潔表示:
imf1(start1+1:start1+num) = 2*li1(2:num+1) - imf1(start1+1:start1+num);

因此,如果是新手,可以先用循環(基於C++的思想)來編寫代碼,然後看看能否用matlab的語言(基於矩陣的思想)來改進。當然,這樣做的前提是你對matlab提供的一些函數比較熟悉才行,這些函數在matlab的“幫助”那裏搜索“Functions Used in Vectorizing”就可以找到一些,其他的也可以找相關的書籍(沒找到?不可能,電子版總可以下載到的)

對提高matlab編程能力的方法,我想主要有以下三個:
1. 查help
    如何查?抽絲剝繭法,具體請看此貼2樓matlab畫的三維圖的怎麼使x軸的label標註平行於x軸

2. 多上上論壇,搜索帖子、發帖子提問

3. 閱讀別人、特別是牛人的程序

當然了,正如所有的程序語言一樣,“3分課本7分上機”,一定要動手才行,不能光看。多想、多思考、多嘗試,纔是正路。以下技巧就是平日動手編程、閱讀別人的帖子後整理出來的(不斷添加中):

  • 1. matlab的運算是基於矩陣的,但是也提供了對應元素的運算,即在運算符前面加上“點”。例如:
    >> a = [1,2;3,4]

    a =

         1     2
         3     4

    >> b = [-1,-2;-3,0]

    b =

        -1    -2
        -3     0

    >> a * b

    ans =

        -7    -2
       -15    -6

    >> a .* b

    ans =

        -1    -4
        -9     0

    也就是說,沒有加“點”的運算是對整個矩陣而言的,稱爲矩陣運算(整體運算),而加了“點”的運算是對每個元素而言的,稱爲點運算(局部運算)。另外,一般情況下,matlab作點運算(理解爲左右兩個對象(矩陣)的對應元素參與該運算)時,兩個矩陣的維數和長度都要求是同大小的,且此時要在運算法前面添加“點”,但是在某些情況下該“點”可以省略,例如一個標量a和一個向量b(或者矩陣)相加、相減、相乘、b/a時都可以不需要加點,表示b中每個元素都和a進行運算(即點運算的效果)
  • 2. 強烈建議大家在命名自己的函數名(更加準確應該說m文件名)時,在名稱前面加上 my 等個人專用標識,即假如你要把你的函數命名爲conv,則最好寫成 myConv,否則容易與matlab自帶的函數(m文件)名字重複而導致“Attempt to execute SCRIPT conv as a function”的錯誤!當你碰到這個錯誤時,可以在命令窗口中輸入 which conv all 來看看到底有否重複命名了該函數,有的話,建議把自己命名的文件改名,保留 matlab 自帶的文件。此外,命名文件名時,必須符合標識符的規範,即不能以數字開頭等等,否則會出現莫名其妙的錯誤!

  • 3. 在條件判斷中,y==0, a-b==0這類語句應該儘量避免使用,除非你可以保證y、a、b在整個計算過程中是整數,否則兩個浮點數相減、或者一個浮點數不可能完全等於0。因此,對浮點數進行條件判斷時,最好採用 abs(a-b) <= 1e-005 這種方式來進行等值比較
  • 4. 循環變量遞減時必須顯式給出步長,即 i = 5:-1:-5 (假設步長爲-1),如果遞增時且步長爲1,則可以省略,簡寫作 i = -5:5
  • 5. 在引號環境下的語句中,如果需要使用單引號,則要寫成兩個單引號的形式,不能用一個雙引號代替!例如: ...'callback','[imp,Fs,bits]=wavread(''temp.wav'');'  文件名 temp.wav 外面的是兩個單引號
  • 6. 如果你編寫的函數帶有輸入參數(例如 x ),則跟其他語言一樣,這只是形式參數,所以不能通過直接運行該函數(或者m文件)來測試,這樣會出現 ??? Input argument "x" is undefined. 的錯誤。一定要從其他地方(如命令窗口或者其他函數對其調用)來傳遞真實值,此時 x 纔是實際參數。如果你有C語言的編程經驗,命令窗口就相當於main函數;如果沒有,以下是舉例:
    myPlus.m:
    1. function d = myPlus(a,b)
    2. d = a + b;
    複製代碼
    命令窗口:
    1. >> x = 2;
    2. >> y = 5;
    3. >> z = myPlus(x,y)
    複製代碼
    此外,和每一種編程語言一樣,所有定義的變量都有一定的作用域。雖然matlab 宣稱變量不需要定義即可以直接使用,但是,事實上任何編程語言的變量都需要先定義才能使用,所以 matlab 也不例外(看來真的是“ matlab 宣稱變量不需要定義”惹的禍),只不過所不同的是並非使用 int x 這種方式來定義,而是使用一個簡單的賦值語句包含定義+初始化。因此,如果直接使用未定義的變量(最常用的是在“=”右邊首次出現),則會出現“Undefined function or variable” 的錯誤!例如:
    1. function y = myTest(x)
    2. z = x * 2;
    3. y = t + z;
    複製代碼
    則運行時 matlab 會報錯:Undefined function or variable t !此時當實際參數傳遞給輸入變量 x 後, x、z 就被定義了,但是 t  卻沒有。

    因此,強烈建議在使用變量之前(特別是循環中使用數組),先預分配空間,這樣容易減少很多莫名其妙的錯誤,具體做法參見以下圖片:

 

preallocate.bmp

  • 7. 如何調試程序:編好程序(先保證代碼沒有語法錯誤),設置斷點(m文件編輯窗口中菜單 Debug 有 Set/Clear breakpoint),運行程序(菜單 Debug 有 Run 或 Save & Run),此時 matlab 會停在斷點處,各變量的值可以通過鼠標停留在變量名上觀察到,或者在命令窗口中敲入變量名後得到
  • 8. 對於matlab自帶函數(命令)的問題,請多利用matlab的幫助功能。即在命令窗口中輸入: help eval 或者 doc eval。更多的幫助指令請參閱以下鏈接的帖子:[轉帖]MATLAB中的幫助指令
  • 9. 對於 mat 文件的讀取,由於存放的是結構體數組,因此調用 A = load('*.mat') 後,得到的 A 並非原始數據,而是一個結構體,此時需要使用".域名" 才能正確得到數據,例如:
    1. A =load('*.mat');
    複製代碼
    後得到:

        A = 
              Signal: [85x7794x64 single]
          TargetChar: [1x85 char]
            Flashing: [85x7794 single]
        StimulusCode: [85x7794 single]
        StimulusType: [85x7794 single]

    則用:
    1. B = fieldnames(A);
    複製代碼
    可得到各結構體的域名。
    如果要獲得各域中(下以 Signal 爲例)的數據,必須用:
    1. S = A.(B{1});
    複製代碼
    此外,不建議使用 load *; 這種方式讀取 mat 文件(讀取 dat 等其他格式的文件也是類似),因爲此時讀取後的變量名是存儲時設定的,假若文件並非您本人存儲,則無法獲悉這個變量名,通過這種方式是無法在讀取時候指定數據存放在哪個變量中的,這樣將會導致下文不知道使用哪個變量名,甚至會導致出錯!因此,強烈建議採用A = load('*.mat'); 方式進行讀取,當然了,如果文件是您本人存儲的,則用前面的方式比較簡便,這另當別論。下面以 dat 文件作爲例子說明:
    clear all
    >> a = magic(4);  b = ones(2, 4) * -5.7;  c = [8 6 4 2];
    >> save -ascii 1_data.dat
    >> load 1_data.dat

    因爲這種方式的讀取是把數據默認存放在以“不含後綴的文件名”命名的變量中(這裏爲 1_data),但是由於 1_data 不是合法的標識符,因此 matlab 自動改成 X1_data(不同版本的matlab可能不同),即讀取出來的數據事實上是存放在 X1_data 變量中。如果使用 m 文件方式編程(即 load 1_data.dat 後有分號),則這個變量名根本不會顯示出來,也就是說,對它的改名你是毫不知情的,這時候下文繼續使用 1_data 的話,就會產生錯誤。
  • 10. matlab 對中文的文件路徑(不光是文件名)不太支持,特別是 6.5 版本。

  • 11. 函數不能在命令窗口中定義,只能在 m 文件中定義。否則出現: ??? Error: Function definitions are not permitted at the prompt or in scripts. 的錯誤!

最後,整理一下常用的快捷鍵(用【】表示)或命令:
1. 在命令窗口(Command Window)中:
1) 【上、下鍵】――切換到之前、之後的命令,可以重複按多次來達到你想要的命令
2) clc――清除命令窗口顯示的語句,此命令並不清空當前工作區的變量,僅僅是把屏幕上顯示出來的語句清除掉
3) clear――這個纔是清空當前工作區的變量命令,常用語句clear all來完成
4) 【Tab】鍵――(轉自版友心燈)在[email protected]看到的:在command窗口,輸入一個命令的前幾個字符,然後按tab鍵,會彈出前面含這幾個字符的所有命令,找到你要的命令,回車,就可以自動完成。目前討論結果是:matlab6.5版本中,如果候選命令超過100個,則不顯示。而在matlab7以後版本中,則沒有這個限制,均可正常提示
5) 【Ctrl+C】(或【Ctrl+Break】)――(轉自版友yangjin_ren)在matlab程序運行過程中,可能由於程序編寫的失誤,導致程序不停的運行,在命令窗口輸入“Ctrl+C”可以將運行的程序停下來,而不需要將整個Matlab程序關掉。不過進行此操作的前提是能夠激活切換到命令窗口才行,呵呵。
2. 在編輯器(Editor)中:
1) 【Tab】(或【Ctrl+]】)――增加縮進(對多行有效)
2) 【Ctrl+[】--減少縮進(對多行有效)
3) 【Ctrl+I】--自動縮進(即自動排版,對多行有效)
4) 【Ctrl+R】――註釋(對多行有效)
5) 【Ctrl+T】――去掉註釋(對多行有效)
6) 【Ctrl+B】――括號配對檢查(對版本6.5有效,但版本7.0以上無效,matlab把這項功能自動集成到編輯器裏面了,即在m文件編輯窗口中會自動進行括號配對檢查,並在窗口右側有紅橙綠三燈提示,具體請參考以下帖子:http://www.simwe.com/forum/thread-746722-1-4.html 
7) 【F12】――設置或取消斷點
8) 【F5】――運行程序
其餘的例如在Debug狀態下的快捷鍵就不多說了,自己看菜單Debug吧

累了, 有時間再寫吧。希望大家多交流~~~~~~

Coming: (以下東西都是一年前做的了,不知道能否記起,呵呵)——已經全部完成
1) 關於神經網絡的――調用matlab的nntool命令後的使用問題(我做的時候沒有看過其他書籍或資料,是自己閉門造車的結果,如果寫之前發現其他書籍有相關介紹的話就不寫了)
2) 關於外部接口的――matlab與C++Builder的接口,想詳細介紹如何利用matcom 4.5在C++Builder中調用matlab的代碼以及matcom的一些技巧。由於我不是搞項目開發的(搞科研、搞課題的),所以對VC不熟悉,大學的時候學過一點,不過我想對於搞科研來說C++Builder就足夠了,免去很多麻煩,Builder在界面設計和數據庫連接上面(我只接觸過這兩方面)還是做得不錯的。同樣,如果發現其他書籍上有類似的東西就不寫了
3) GUI方面也寫寫吧,只是一點點心得或者體會,呵呵,這個相對簡單些,篇幅相對要少些。

注:本帖不斷更新中,修正的部分用紅色字體表示,增加的部分用藍色字體表示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章