cv.cm

編碼 · 程式語言

MATLAB 入門教學

閱讀約 9 分鐘

簡答

MATLAB 是 MathWorks 推出的數值運算語言與環境,其中每個值都是矩陣。你用 A * B 表示矩陣乘積,用 A .* B 表示逐元素相乘,索引從 1 開始,並且用向量化運算式取代許多迴圈。它內建繪圖功能,以及大量供工程與科學使用的工具箱。GNU Octave 是免費的開放原始碼替代品,可以原封不動地執行大多數基本的 MATLAB 程式碼。

MATLAB 是什麼、誰在使用

MATLAB(「matrix laboratory」,矩陣實驗室)起初是 Cleve Moler 為了方便使用線性代數函式庫而開發的工具,後來成為 MathWorks 的商業產品。它結合了語言、互動式桌面環境、繪圖,以及用於訊號處理、控制系統、最佳化、統計、影像處理與機器學習的工具箱。它的配套產品 Simulink 則以方塊圖為動態系統建立模型。

MATLAB 廣泛用於工程與科學課程、研究實驗室,以及汽車、航太與金融等產業。它需要付費授權(許多大學會提供)。GNU Octave 是自由軟體,語法大致相容;它涵蓋核心語言與許多函式,但不包含 MathWorks 的工具箱或 Simulink。

安裝並執行 Hello, world

可以從 MathWorks 安裝 MATLAB、在瀏覽器中使用 MATLAB Online,或從 octave.org 安裝 GNU Octave(Windows、macOS、Linux)。程式碼存放在 .m 檔案中。腳本是一個由指令組成的檔案;在命令視窗(Command Window)中輸入不含 .m 的檔名即可執行。

% hello.m
disp('Hello, world!')
matlab -batch "hello"   # MATLAB from a terminal
octave hello.m          # GNU Octave
# Hello, world!

註解以 % 開頭。結尾沒有分號的那一行會印出其結果,所以 x = 5 會顯示 x = 5,而 x = 5; 則保持安靜。

變數與基本型別

變數透過賦值建立,不需要宣告。數字預設為 double(64 位元浮點數),即使是單一個數字,也是 1×1 的矩陣。

型別範例說明
doublex = 3.14預設的數值型別
integer typesn = int32(42)int8 到 int64、uint8 到 uint64;運算會飽和(saturate)
logicalok = truex > 2 這類比較的結果
char arrayname = 'Ana'單引號;由字元組成的列向量
strings = "Ana"MATLAB 的字串物件;Octave 把雙引號視為 char 陣列
cell arrayc = {'Ana', 30}可存放不同型別的值
structp.name = 'Ana'具名欄位
x = 10;
y = 3;
x / y              % 3.3333
mod(x, y)          % 1
x ^ 2              % 100
name = 'Ana';
fprintf('%s is %d years old\n', name, 30)
% Ana is 30 years old
class(x)           % 'double'

向量與矩陣

方括號用來建立陣列:空格或逗號分隔欄,分號分隔列。索引使用小括號並從 1 開始;end 表示最後一個索引,: 表示「全部」。

v = [3 1 4 1 5];
v(1)               % 3
v(end)             % 5
v(2:4)             % [1 4 1]
v * 2              % [6 2 8 2 10]
v(v > 2)           % [3 4 5]   logical indexing
A = [1 2; 3 4];
A(2, :)            % second row: [3 4]
A'                 % transpose:  [1 3; 2 4]
A * A              % matrix product: [7 10; 15 22]
A .* A             % element-wise:   [1 4; 9 16]
b = [5; 11];
x = A \ b          % solves A*x = b: [1; 2]
z = zeros(2, 3);   % also ones, eye, rand
r = 0:0.25:1;      % [0 0.25 0.5 0.75 1]

帶點的運算子(.*、./、.^)逐元素運算;沒有點則遵循線性代數的規則。反斜線運算子可求解線性方程組,並且比計算 inv(A) * b 更精確。

流程控制

score = 85;
if score >= 90
    disp('A')
elseif score >= 80
    disp('B')
else
    disp('C')
end

total = 0;
for k = 1:10
    total = total + k;
end
fprintf('total = %d\n', total)   % total = 55

n = 3;
while n > 0
    n = n - 1;
end

switch 'red'
    case {'red', 'green'}
        disp('a color')
    otherwise
        disp('unknown')
end

每個區塊都以 end 結尾。許多迴圈可以用向量化運算式取代:上面的迴圈等同於 sum(1:10),更短,通常也更快。如果必須在迴圈中建立陣列,請先預先配置,例如 result = zeros(1, 1000);。

函式與匿名函式

函式放在自己的檔案中,檔名要與函式名稱相同。一個函式可以回傳多個輸出。在較新的 MATLAB 版本中,腳本的檔案結尾也可以包含區域函式。

% stats.m
function [m, s] = stats(x)
%STATS Mean and sample standard deviation of a vector.
    m = mean(x);
    s = std(x);
end
[m, s] = stats([2 4 4 5 7])   % m = 4.4000, s = 1.8166
[biggest, where] = max([3 9 2])   % biggest = 9, where = 2

f = @(x) x.^2 + 1;            % anonymous function
f(3)                          % 10
f([1 2 3])                    % [2 5 10]
fzero(@(x) x.^2 - 2, 1)       % 1.4142, a root near 1
integral(f, 0, 1)             % 1.3333

以 @ 建立的匿名函式,經常傳給 fzero、integral、arrayfun 或最佳化常式等其他函式。請用逐元素運算子(.^)撰寫,讓它們也能作用於向量。

Struct 與 cell 陣列

person.name = 'Ana';
person.age = 30;
fprintf('%s is %d\n', person.name, person.age)   % Ana is 30

c = {'Ana', 30, [1 2 3]};   % cell array with mixed types
c{2}                         % 30 (curly braces get the content)
class(c(2))                  % 'cell' (parentheses get a sub-cell)
names = {'Ana', 'Ben', 'Cleo'};
numel(names)                 % 3
upper(names{1})              % 'ANA'

MATLAB 還有 table 型別,用於以欄為導向、帶有具名變數的資料,類似試算表;readtable 可將 CSV 與 Excel 檔案載入其中。

錯誤處理

用 error 引發錯誤,可選擇附上 'demo:negative' 這類識別碼,再用 try ... catch 處理。被攔截的物件(在 MATLAB 中是 MException)具有 identifier 與 message 欄位。

% safe_sqrt.m
function r = safe_sqrt(x)
    if x < 0
        error('demo:negative', 'Input must be non-negative, got %g', x);
    end
    r = sqrt(x);
end
try
    safe_sqrt(-4);
catch err
    fprintf('%s: %s\n', err.identifier, err.message)
end
% demo:negative: Input must be non-negative, got -4

對於不應中斷程式的問題,請使用 warning(...)。如果沒有這個檢查,sqrt(-4) 根本不會失敗:它會回傳複數 0 + 2i。

完整的小程式:分析並繪製資料

% temps.m - analyze a week of temperatures
temps = [21.5 23.0 19.8 25.1 24.3 18.9 22.7];
days = 1:numel(temps);

avg = mean(temps);
[hottest, idx] = max(temps);
above = days(temps > avg);

fprintf('Average: %.2f\n', avg)
fprintf('Hottest: %.1f on day %d\n', hottest, idx)
fprintf('Days above average: %s\n', mat2str(above))

plot(days, temps, '-o')
hold on
plot(days, avg * ones(size(days)), '--')
xlabel('Day'); ylabel('Temperature (C)')
title('Temperatures this week')
legend('Daily', 'Average')
% Average: 22.19
% Hottest: 25.1 on day 4
% Days above average: [2 4 5 7]

這個腳本使用邏輯索引,不用迴圈就找出高於平均值的日子,然後繪製帶標記的折線圖與一條虛線平均線。同樣的程式碼也能在 GNU Octave 中執行。

接下來可以學什麼

  • MathWorks 的 MATLAB 文件,從入門頁面開始。
  • MATLAB Onramp,MathWorks 提供的免費互動式入門課程。
  • 如果你使用 Octave,請閱讀 GNU Octave 手冊,包括其中關於 MATLAB 相容性的說明。
  • 接下來請學習向量化、用於資料檔案的 readtable,以及繪圖函式。

常見問題

MATLAB 有免費版嗎?

MATLAB 本身需要授權,不過 MathWorks 提供試用,許多大學也提供校園授權。GNU Octave 是免費的開放原始碼程式,可以執行大多數基本的 MATLAB 程式碼。

MATLAB 中的 * 與 .* 有什麼差別?

* 是線性代數的矩陣乘法,要求內部維度相符。.* 則是將兩個相同大小的陣列對應的元素相乘。

GNU Octave 與 MATLAB 完全相容嗎?

並非完全相容。核心語法、矩陣、函式與繪圖大致相容,但 Octave 沒有 MathWorks 工具箱、Simulink 與部分較新的 MATLAB 功能,而且它還接受一些自己額外的語法形式。

為什麼 MATLAB 從 1 開始索引?

MATLAB 遵循數學記號,向量或矩陣的第一個元素是第 1 個元素。Fortran、R 與 Julia 也使用相同的慣例。

該學 MATLAB 還是 Python?

如果你的課程、實驗室或公司使用 MATLAB,尤其是搭配 Simulink 或特定工具箱,就學 MATLAB。搭配 NumPy、SciPy 與 Matplotlib 的 Python 是免費的,也更通用,而且兩者的概念可以互通。

全部編碼教學