Skip to content

MATLAB 速查表

用于工程和科学的数值计算环境。

01

矩阵与基本运算

创建矩阵和向量

MATLAB(MATrix LABoratory)将所有变量视为矩阵。向量是 1xN 或 Nx1 的矩阵。使用空格或逗号分隔行中的元素,使用分号分隔新行。zeros、ones、eye、rand 和 magic 创建常见的测试矩阵。冒号运算符 start:step:stop 生成范围(默认步长为 1)。linspace(a, b, n) 创建 n 个均匀分布的点——非常适合用作绘图坐标轴。

matlab
% row vector
v = [1 2 3 4 5];

% column vector (semicolon = new row)
c = [1; 2; 3];

% 3x3 matrix
A = [1 2 3; 4 5 6; 7 8 9];

% special matrices
Z = zeros(3);          % 3x3 zeros
O = ones(2, 4);        % 2x4 ones
I = eye(3);            % 3x3 identity
R = rand(2, 3);        % 2x3 uniform random
N = randn(4);          % 4x4 normal random
M = magic(4);          % 4x4 magic square
D = diag([1 2 3]);     % diagonal matrix

% linear spacing
l = linspace(0, 1, 5); % [0 0.25 0.5 0.75 1]
r = 0:0.5:2;           % [0 0.5 1 1.5 2]

矩阵索引与切片

MATLAB 从 1 开始索引(不是从 0 开始)。冒号 : 表示'全部'——A(:,2) 是整个第二列。A(1:3, :) 选择第 1-3 行。'end' 指该维度的最后一个索引。逻辑索引(A(A > 5))非常强大——它可以提取或修改满足条件的元素。find 返回非零/真元素的索引,使用两个输出参数时可分别返回行和列。

matlab
A = magic(4);          % 4x4 magic square

% single element (1-indexed!)
A(2, 3)                % row 2, col 3

% entire row or column
A(1, :)                % first row (all columns)
A(:, 2)                % second column (all rows)

% submatrix
A(1:2, 2:4)            % rows 1-2, cols 2-4

% linear indexing (column-major)
A(5)                   % 5th element counting down columns

% end keyword
A(end, :)              % last row
A(:, end-1)            % second-to-last column

% logical indexing
A(A > 10)              % all elements > 10 (as vector)
A(A > 10) = 0;         % set large elements to 0

% find indices
[r, c] = find(A == 16) % row and col of value 16

矩阵算术运算

运算符前的点(.*)使其变为逐元素运算而非矩阵运算——这是初学者错误的头号来源。A*B 是矩阵乘法;A.*B 将对应元素相乘。反斜杠运算符(\)高效且精确地求解线性方程组(LU 分解)——始终优先使用 x = A\b 而非 inv(A)*b。撇号(')表示转置;对于复矩阵,使用 .' 进行非共轭转置。

matlab
A = [1 2; 3 4];
B = [5 6; 7 8];

% matrix operations
C = A + B;             % addition
D = A - B;             % subtraction
E = A * B;             % matrix multiplication
F = A';                % transpose
G = A^2;               % matrix power (A * A)

% element-wise operations (use the dot!)
H = A .* B;            % element-wise multiply
I = A ./ B;            % element-wise divide
J = A .^ 2;            % element-wise power
K = 2 * A;             % scalar multiply

% matrix functions
det(A)                 % determinant
inv(A)                 % inverse
pinv(A)                % pseudo-inverse
rank(A)                % rank
trace(A)               % trace (sum of diagonal)

% solving linear systems Ax = b
b = [5; 11];
x = A \ b;              % left division: solves A*x = b
x = inv(A) * b;        % equivalent but slower

矩阵操作

使用 [A B](空格)进行水平拼接;使用 [A; B](分号)进行垂直拼接——与行创建语法一致。reshape 按列优先填充(先向下再向右)。flipud/fliplr/rot90 重新调整矩阵方向。repmat 以网格模式平铺矩阵。将某行或某列设为 [] 可删除它。size 返回维度,length 返回最大维度,numel 返回元素总数。

matlab
A = [1 2; 3 4];
B = [5 6; 7 8];

% concatenation
C = [A B];             % horizontal: [1 2 5 6; 3 4 7 8]
D = [A; B];            % vertical: 4x4

% reshape
E = reshape(1:12, 3, 4);  % 3x4 matrix from 1..12

% flip and rotate
F = flipud(A);         % flip up-down
G = fliplr(A);         % flip left-right
H = rot90(A);          % rotate 90 degrees

% repmat (tile)
I = repmat([1 2], 2, 3);  % repeat [1 2] in a 2x3 grid

% size and length
[m, n] = size(A);      % m=2, n=2
len = length(A);       % max dimension = 2
num = numel(A);        % total elements = 4

% remove rows/cols
A(2, :) = [];          % delete row 2
A(:, 1) = [];          % delete column 1

逐元素函数与向量化

MATLAB 的优势在于向量化——一次性对整个数组应用运算,底层运行优化的 C/Fortran 代码。sin、exp、sqrt 等自动进行逐元素运算。sum/prod/max/min 默认按列运算(维度 1);传入维度 2 则按行运算。A(:) 将矩阵展平为向量。为了性能,始终优先使用向量化运算而非 for 循环——它们可以快 10-100 倍。

matlab
% math functions operate element-wise
x = 0:0.1:2*pi;
y = sin(x);            % sine of each element
z = exp(x);            % exponential
w = sqrt(x);           % square root

% rounding
round(3.7)             % 4
floor(3.7)             % 3
ceil(3.2)              % 4
fix(-3.7)              % -3 (toward zero)

% sums and products along dimensions
A = magic(3);
sum(A)                 % sum of each column (row vector)
sum(A, 2)              % sum of each row (column vector)
sum(A(:))              % sum of ALL elements
prod(A)                % product of each column
cumsum(A)              % cumulative sum

% min, max, sort
[v, i] = max(A(:))     % max value and its index
sort(A, 'descend')     % sort each column descending

% AVOID loops — vectorize!
% BAD: for i=1:1000, y(i)=sin(i); end
% GOOD:
i = 1:1000;
y = sin(i);            % fast, vectorized
02

控制流与逻辑

If / Elseif / Else

MATLAB 使用 if/elseif/else/end(注意:elseif 是一个词)。逻辑运算符:&&(标量与)、||(标量或)、&(逐元素与)、|(逐元素或)、~(非,不是 !)。字符串比较使用 strcmp/strcmpi(不区分大小写)——== 运算符只对相同长度的字符数组有效。始终用 'end' 结束代码块。

matlab
score = 85;

if score >= 90
    grade = 'A';
elseif score >= 80
    grade = 'B';
elseif score >= 70
    grade = 'C';
else
    grade = 'F';
end

disp(grade);  % B

% logical operators: && (and), || (or), ~ (not)
if x > 0 && x < 10
    disp('in range');
end

% compare strings with strcmp
if strcmp(name, 'Alice')
    disp('hi Alice');
end

For 和 While 循环

for 遍历给定表达式的每一列(对于向量,则是每个元素)。while 在条件为真时运行。始终在循环前预分配数组(result = zeros(1,N))——在循环中增长数组会迫使每次迭代都重新分配内存,速度极慢。冒号运算符 1:5 创建 [1 2 3 4 5]。fprintf 打印格式化输出(类似 C 的 printf)。

matlab
% for loop over a range
for i = 1:5
    fprintf('i = %d\n', i);
end

% iterate over a vector
v = [10 20 30];
for val = v
    disp(val);
end

% nested loop over a matrix
A = zeros(3, 3);
for r = 1:3
    for c = 1:3
        A(r, c) = r * c;
    end
end

% while loop
n = 10;
while n > 1
    n = n / 2;
    fprintf('%.2f\n', n);
end

% preallocate for speed (IMPORTANT!)
result = zeros(1, 1000);
for i = 1:1000
    result(i) = i^2;
end

Switch 与 Break/Continue

switch 将值与 case 标签匹配——不需要 break(与 C/Java 不同)。case 可以接受元胞数组以匹配多个值。otherwise 是默认分支。break 退出最内层循环;continue 跳到下一次迭代。try/catch 优雅地处理错误;ME 是一个 MException 对象,包含 .message 和 .identifier。MATLAB 没有三元运算符——使用 if/else 或内联函数。

matlab
% switch statement
method = 'linear';
switch method
    case 'linear'
        disp('using linear');
    case 'cubic'
        disp('using cubic');
    case {'nearest', 'spline'}
        disp('using nearest or spline');
    otherwise
        disp('unknown method');
end

% break and continue
for i = 1:10
    if i == 5
        break        % exit the loop entirely
    end
    if mod(i, 2) == 0
        continue     % skip to next iteration
    end
    disp(i);         % prints 1 3
end

% try-catch for error handling
try
    x = 1 / 0;       % may error
catch ME
    fprintf('Error: %s\n', ME.message);
end

逻辑运算与索引

逻辑索引是 MATLAB 的杀手级特性——A(condition) 选择逻辑数组为真的元素。~= 是'不等于'(不是 !=)。& 和 | 是逐元素运算;&& 和 || 是短路运算(仅限标量,在 if 条件中优先使用)。find 返回真值的线性索引。any/all 测试是否有任何/所有元素为真,可沿指定维度进行。is* 系列函数测试类型和特殊值(NaN、Inf)。

matlab
A = [1 2 3 4 5 6 7 8 9 10];

% comparison operators
A > 5                  % logical array
A == 5
A ~= 5                 % not equal (NOT !=)
A >= 3 & A <= 7        % element-wise AND
A < 3 | A > 7          % element-wise OR

% logical indexing (powerful!)
A(A > 5)               % [6 7 8 9 10]
A(A > 5) = 0;          % set elements > 5 to 0
A(mod(A, 2) == 0)      % even numbers

% find indices
idx = find(A > 5);     % indices of elements > 5
[r, c] = find(A > 5);  % row and col (for matrices)

% any and all
any(A > 5)             % true if ANY element > 5
all(A > 0)             % true if ALL elements > 0
any(A > 5, 2)          % per row

% is functions
isnan(x); isinf(x); isfinite(x);
isnumeric(x); ischar(x); iscell(x);

字符串与格式化

MATLAB 有两种字符串类型:字符数组('text',传统类型)和字符串标量("text",R2017+)。字符串标量在操作上更灵活。sprintf 返回格式化字符串;fprintf 打印到控制台或文件。常用格式说明符:%s(字符串)、%d(整数)、%f(浮点数)、%.2f(2 位小数)、%e(科学计数法)。strsplit/strjoin 处理分隔列表。num2str/mat2str 将数字转换为字符串。

matlab
% string creation
s1 = 'Hello';          % char array
s2 = "World";          % string scalar (R2017+)

% concatenation
greeting = [s1 ', ' s2 '!'];  % char array concat
full = s1 + " " + s2;          % string concat

% formatting
name = 'Alice';
age = 30;
fprintf('Name: %s, Age: %d\n', name, age);
str = sprintf('Pi is %.2f', pi);  % returns string

% common string functions
upper('hello')         % HELLO
lower('WORLD')         % world
strlength("hello")     % 5 (string)
length('hello')        % 5 (char array)
strcmp('a', 'a')       % true
strfind('hello', 'll') % 3 (index)
strrep('cat', 'c', 'b') % bat
strsplit('a,b,c', ',') % {'a','b','c'}
strjoin({'a','b'}, '-') % a-b
num2str(42)             % '42'
03

函数与脚本

函数定义

函数必须放在同名文件中(函数 add 放在 add.m 中),或位于脚本文件的末尾。第一行是函数声明。函数有自己的工作区(与基础工作区分开)。nargin/nargout 让你处理可选参数——nargin 计算实际输入参数个数。多个输出通过 [a, b] = func() 获取。如果调用时输出参数较少,多余的输出会被丢弃。

matlab
% function in a file named 'add.m'
function result = add(a, b)
    % ADD returns the sum of a and b
    result = a + b;
end

% with multiple inputs and outputs
function [mn, mx, avg] = stats(v)
    mn = min(v);
    mx = max(v);
    avg = mean(v);
end

% calling functions
s = add(3, 4);              % 7
[lo, hi, mu] = stats([1 2 3 4 5]);

% capture only first output
minimum = stats([1 2 3]);   % gets mn only

% nargin and nargout (number of args)
function y = power(x, n)
    if nargin < 2
        n = 2;              % default value
    end
    y = x .^ n;
end

匿名函数与内联函数

匿名函数(@(args) expr)是内联定义的快速单行函数——非常适合传递给求解器(fzero、integral、ode45)而无需创建文件。它们在创建时捕获工作区变量。函数句柄(@sin)让你将内置或用户函数作为参数传递。这对数值计算至关重要:integral(@(x) f(x), a, b) 可以积分你定义的任何函数。

matlab
% anonymous function (one-liner, no file needed)
square = @(x) x .^ 2;
square(5)              % 25
square([1 2 3])        % [1 4 9]

% with multiple inputs
add = @(a, b) a + b;
add(3, 4)              % 7

% capture variables from workspace
c = 10;
addc = @(x) x + c;
addc(5)                % 15

% function handle to built-in
f = @sin;
f(pi/2)                % 1

% pass functions as arguments
result = integral(@(x) x.^2, 0, 1);  % integrate x^2 from 0 to 1
result = fzero(@(x) x^2 - 2, 1);     % find root near 1

% array of function handles
funs = {@sin, @cos, @tan};
funs{1}(0)             % 0

脚本与实时脚本

脚本是在基础工作区中运行的命令序列(不像函数有隔离的工作区)。%% 标记创建'单元格'(分区),可以用 Ctrl+Enter 独立运行——非常适合增量开发。实时脚本(.mlx)类似 Jupyter 笔记本:它们将代码、格式化文本、方程和内联绘图组合在一个交互式文档中。对于可重用代码,优先使用函数而非脚本。

matlab
% A script is just a sequence of commands in a .m file
% It shares the base workspace

% script: analyze_data.m
data = load('data.mat');
cleaned = data.values(data.values > 0);
mean_val = mean(cleaned);
fprintf('Mean: %.2f\n', mean_val);
plot(cleaned);
title('Cleaned Data');

% sections (cells) with %%
%% Initialize
x = linspace(0, 2*pi, 100);

%% Plot
plot(x, sin(x));

%% Analyze
disp(mean(sin(x)));

% Run a section: Ctrl+Enter (in editor)
% Live Scripts (.mlx): rich text, inline plots, equations

嵌套函数与局部函数

脚本可以在文件末尾包含局部函数(自 R2016b 起)——它们只在该文件内可见。嵌套函数(定义在另一个函数内部)共享父函数的工作区,因此可以读取和修改其变量——对回调和累加器很有用,但可能使代码难以理解。函数文件中的局部函数是仅在该文件内可见的辅助函数。使用局部函数可以在不创建多个文件的情况下保持脚本有条理。

matlab
% local functions in a script (must be at the end)
% main_script.m
x = 1:10;
y = process(x);
disp(y);

function r = process(v)
    r = normalize(scale(v));  % calls another local function
end

function s = scale(v)
    s = v * 10;
end

function n = normalize(v)
    n = v / max(v);
end

% nested function (inside another function)
function outer(x)
    y = 0;
    function inner()
        y = y + x;    % can access outer's variables
    end
    inner();
    disp(y);
end

变量作用域与全局变量

MATLAB 按值传递参数(修改时复制),因此函数不会意外更改调用者的变量——与 C/Python 不同。使用 global 实现真正的共享状态(在每个使用它的函数中声明),但优先使用参数传递。persistent 变量在函数调用之间保留其值(类似 C 中的 static)——对计数器、缓存或记忆化很有用。在首次调用时使用 isempty 检查来初始化 persistent 变量。避免使用全局变量,转而使用函数返回值或嵌套函数。

matlab
% base workspace variables
x = 10;

% functions have their OWN workspace
function y = myfunc()
    % x is NOT accessible here
    y = 5;
end

% pass by value (modifications don't affect caller)
function y = modify(v)
    v = v * 2;        % local copy
    y = v;
end
a = 5;
b = modify(a);        % b=10, a still 5

% global variables (use sparingly!)
global COUNTER
COUNTER = 0;
function increment()
    global COUNTER
    COUNTER = COUNTER + 1;
end

% persistent variables (like static in C)
function counter()
    persistent count
    if isempty(count)
        count = 0;
    end
    count = count + 1;
    disp(count);
end
04

数据结构

元胞数组

元胞数组是 MATLAB 用于混合类型数据的容器(类似 Python 列表)。使用花括号 {} 访问元胞的内容,使用圆括号 () 获取元胞本身(对切片有用)。这个区别至关重要:c{1} 给出字符串;c(1) 给出包含字符串的元胞。元胞数组对于处理不同长度的字符串、可变大小的矩阵和不规则数据至关重要。num2cell/mat2cell 在数值数组和元胞之间转换。

matlab
% cell arrays hold mixed data types
c = {'Alice', 30, [1 2 3], magic(2)};

% access with {} (content) vs () (cell)
c{1}                  % 'Alice' (the string itself)
c(1)                  % {'Alice'} (a 1x1 cell)
c{3}(2)               % 2 (second element of third cell)

% modify and append
c{2} = 31;
c{end+1} = 'new';     % append
c{5} = 'skip';        % auto-fills gaps with []

% multi-dimensional cell array
c2 = {'a', 'b'; 'c', 'd'};  % 2x2 cell

% iterate over cells
for i = 1:numel(c)
    disp(c{i});
end

% convert: cell2mat, mat2cell, num2cell
nums = num2cell(1:5);  % {1, 2, 3, 4, 5}

结构体与表格

结构体用命名字段分组相关数据——像没有方法的对象。表格(R2013+)是 MATLAB 中类似 dataframe 的结构:面向列,具有命名的变量和行名。表格非常适合 CSV/Excel 数据。按名称(T.ages)或索引访问列。逻辑索引可用于行:T(T.age > 25, :) 筛选行。summary() 给出每列的统计信息。表格与 readtable/writetable 集成用于数据输入输出。

matlab
% struct: named fields with any data
user.name = 'Alice';
user.age = 30;
user.scores = [90 85 88];
disp(user.name);      % Alice

% struct constructor
s = struct('name', 'Bob', 'age', 25, 'active', true);

% array of structs
users(1) = struct('name', 'Alice', 'age', 30);
users(2) = struct('name', 'Bob', 'age', 25);
disp(users(2).name);  % Bob

% table (like a dataframe) — great for tabular data
names = {'Alice'; 'Bob'; 'Carol'};
ages = [30; 25; 28];
scores = [90; 85; 88];
T = table(names, ages, scores);

% access table columns
T.ages               % column as array
T(:, 2)              % column as table
T(1:2, :)            % first 2 rows
T.age > 26           % logical indexing
T(T.age > 26, :)     % rows where age > 26

% summary statistics
summary(T)

字符串数组与字符处理

现代 MATLAB(R2017+)优先使用字符串数组("text")而非字符数组('text')。字符串数组支持向量化运算:strlength、+、split、join、contains、matches、replace 都可逐元素工作。字符数组在旧代码中仍然常见,某些函数也需要它。使用字符串数组存储文本集合;它们自然处理不同长度(不像字符数组需要填充或使用元胞)。

matlab
% string array (R2017+) — recommended for text
names = ["Alice", "Bob", "Carol"];
names(1)              % "Alice"
names'                % column string array
strlength(names)      % [5 3 5]

% char array (legacy)
c = 'Hello World';
c(1:5)                % 'Hello'
size(c)               % [1 11]

% cell array of char vectors (legacy mixed-length)
old = {'Alice', 'Bob', 'Carol'};

% convert between types
s = string('hello');          % char -> string
c = char("hello");            % string -> char
cellarr = cellstr(names);     % string array -> cell of char

% combine and split
full = "Alice" + " " + "Smith";  % "Alice Smith"
parts = split("a,b,c", ",");     % ["a", "b", "c"]
joined = join(["a" "b" "c"], "-"); % "a-b-c"

% pattern matching
matches(names, 'A*')  % logical: [true false false]
contains(names, 'li') % [true false false]
replace("hello", 'l', 'L')  % "heLLo"

Containers.Map 与集合

containers.Map 是 MATLAB 的键值字典(哈希映射)——适用于查找表和配置。键可以是字符串或数字。isKey 检查存在性;keys/values 检索所有键/值。集合运算(union、intersect、setdiff、setxor、ismember)适用于数值数组和字符串元胞数组。ismember 测试成员资格并返回逻辑数组——非常适合筛选。这些补充了逻辑索引用于数据操作。

matlab
% map (dictionary / hash table)
m = containers.Map;
m('name') = 'Alice';
m('age') = 30;
m('scores') = [90 85];

% access
m('name')             % 'Alice'
isKey(m, 'name')      % true
keys(m)               % {'age', 'name', 'scores'}
values(m)             % {30, 'Alice', [90 85]}
remove(m, 'age');

% create with initial values
m2 = containers.Map({'a','b','c'}, {1, 2, 3});

% set operations
A = [1 2 3 4 5];
B = [4 5 6 7 8];
union(A, B)           % [1 2 3 4 5 6 7 8]
intersect(A, B)       % [4 5]
setdiff(A, B)         % [1 2 3]
setxor(A, B)          % [1 2 3 6 7 8]
ismember(3, A)        % true
ismember([1 6], A)    % [true false]

分类数组与日期时间

categorical 数组高效存储文本数据(作为带标签映射的整数)并支持排序——非常适合调查回复、评级或任何固定类别集合。datetime/duration(R2014+)用现代的、时区感知的日期系统取代了传统的 datenum/datestr 函数。日期算术很直观:添加 days()、hours()、minutes()。这些类型与表格和绘图集成,用于时间序列分析。

matlab
% categorical data (efficient for repeated strings)
colors = categorical({'red', 'blue', 'red', 'green', 'blue'});
categories(colors)    % list of categories
summary(colors)       % count per category
ord = categorical({'low','med','high'}, ...
     {'low','med','high'}, 'Ordinal', true);
ord(1) < ord(2)       % true (ordered)

% datetime
t = datetime('now')   % current date and time
t = datetime(2024, 1, 15)
t.Format = 'yyyy-MM-dd HH:mm:ss';

% duration
d = duration(2, 30, 0);  % 2 hours 30 min
d = hours(2) + minutes(30);

% date arithmetic
t2 = t + days(7);     % add a week
t2 - t                % duration of 7 days

% date strings and numbers
s = datestr(t, 'yyyy-mm-dd');  % to string (legacy)
n = datenum(t);                 % to serial number
t = datetime(n, 'ConvertFrom', 'datenum');

% generate date range
dates = datetime(2024,1,1) + days(0:6);  % one week
05

绘图与可视化

基本 2D 绘图

plot() 是核心的 2D 绘图函数。第三个参数指定颜色和样式('b-' = 蓝色实线)。hold on 让你叠加多个绘图;hold off 释放。始终标注坐标轴并添加图例。axis([xmin xmax ymin ymax]) 设置范围。saveas/print 导出图形——使用 -r300 的 print 可获得 300 DPI。gcf 获取当前图形句柄。'Location','best' 选项自动放置图例。

matlab
x = linspace(0, 2*pi, 100);

% line plot
plot(x, sin(x), 'b-', 'LineWidth', 2);
hold on;
plot(x, cos(x), 'r--', 'LineWidth', 2);
hold off;

% labels and legend
xlabel('x (radians)');
ylabel('amplitude');
title('Sine and Cosine');
legend('sin(x)', 'cos(x)', 'Location', 'best');
grid on;

% line styles: b- blue solid, r-- red dashed
% g: green dotted, m-. magenta dash-dot
% markers: o circle, * star, s square, + plus

% axis control
axis([0 2*pi -1.5 1.5]);  % [xmin xmax ymin ymax]
xlim([0 2*pi]);
ylim([-1.5 1.5]);

% save figure
saveas(gcf, 'plot.png');
print('-dpng', '-r300', 'plot.png');

多图与子图

subplot(r, c, n) 将图形分为 r 行 c 列的网格,并选择第 n 个单元格进行绘图。tiledlayout(R2019+)是现代替代方案——间距更清晰且有共享标题。nexttile 前进到下一个子图。yyaxis 创建具有两个 y 轴(左和右)的绘图,适用于不同比例的数据。始终先调用 figure 打开新窗口,否则会覆盖当前绘图。

matlab
% subplot(rows, cols, index)
figure;
subplot(2, 2, 1);
plot(x, sin(x));
title('Sine');

subplot(2, 2, 2);
plot(x, cos(x));
title('Cosine');

subplot(2, 2, 3);
plot(x, tan(x));
title('Tangent');
ylim([-5 5]);

subplot(2, 2, 4);
plot(x, exp(-x));
title('Decay');

% tiledlayout (newer, cleaner)
figure;
t = tiledlayout(2, 2);
nexttile; plot(x, sin(x)); title('Sine');
nexttile; plot(x, cos(x)); title('Cosine');
nexttile; plot(x, tan(x)); title('Tangent');
nexttile; plot(x, exp(-x)); title('Decay');
title(t, 'Trig Functions');  % overall title

% multiple y-axes
yyaxis left;  plot(x, sin(x));
yyaxis right; plot(x, 100*cos(x));

专用绘图

MATLAB 有数十种专用绘图:bar/barh(条形图)、histogram(替代 hist)、scatter(可选颜色/大小映射)、pie、area、stem、stairs、compass、feather。scatter(x, y, size, color, 'filled') 特别强大——第 4 个参数按值着色点,揭示第三维度。使用 'Normalization','pdf' 的 histogram 归一化为概率密度,便于与连续分布比较。

matlab
% bar chart
bar([1 2 3], [10 15 7]);
bar([1 2 3; 4 5 6], 'grouped');  % grouped bars
bar([1 2 3; 4 5 6], 'stacked');  % stacked bars

% histogram
data = randn(1000, 1);
histogram(data, 30);    % 30 bins
histogram(data, 'Normalization', 'pdf');

% scatter plot
x = rand(100, 1);
y = 2*x + randn(100, 1)*0.1;
scatter(x, y, 50, 'filled');
% colored scatter
scatter(x, y, 50, y, 'filled');  % color by y value
colorbar;

% pie chart
pie([30 20 50], {'A', 'B', 'C'});

% area plot
area(1:5, [1 3 2 4 5]);

% stem (discrete)
stem(0:5, [1 4 9 16 25 36]);

% boxplot (requires Statistics toolbox)
boxplot(randn(100, 3));

3D 绘图与曲面

plot3 绘制 3D 参数曲线。对于曲面,首先用 meshgrid 创建网格,然后计算 Z = f(X, Y)。surf 绘制填充曲面;mesh 绘制线框;contour 绘制 2D 等高线。colormap(jet、parula、hot、cool)控制颜色映射;colorbar 添加图例。shading interp 移除网格线以获得平滑渐变。view(az, el) 设置相机角度。'EdgeColor','none' 隐藏网格线以获得干净的外观。

matlab
% 3D line plot
t = 0:0.1:10*pi;
plot3(sin(t), cos(t), t);
xlabel('x'); ylabel('y'); zlabel('z');

% meshgrid for surface plots
[X, Y] = meshgrid(-2:0.1:2);
Z = X .* exp(-X.^2 - Y.^2);

% surface plots
figure;
subplot(1, 3, 1);
surf(X, Y, Z);     % surface
title('surf');

subplot(1, 3, 2);
mesh(X, Y, Z);     % wireframe
title('mesh');

subplot(1, 3, 3);
contour(X, Y, Z, 20);  % contour lines
title('contour');

% colored surface with colorbar
figure;
surf(X, Y, Z, 'EdgeColor', 'none');
colorbar;
colormap jet;
shading interp;     % smooth colors

% view angle
view(45, 30);       % azimuth, elevation
axis equal;

绘图自定义与导出

几乎每个视觉方面都可通过名称-值对或 set() 自定义。颜色是 0-1 范围的 RGB 三元组 [r g b]。set(gca, ...) 修改当前坐标轴(字体、比例、范围)。MATLAB 通过 'Interpreter','latex' 在标题/标签中支持 LaTeX。exportgraphics(R2020+)是现代导出函数,支持矢量和高 DPI 选项。使用图形句柄(f1、f2)管理多个窗口。annotation() 添加箭头、文本框和形状。

matlab
% customize line appearance
plot(x, y, ...
    'Color', [0.2 0.6 0.8], ...     % RGB 0-1
    'LineWidth', 2, ...
    'Marker', 'o', ...
    'MarkerSize', 8, ...
    'MarkerFaceColor', 'r');

% annotations
text(1, 0.5, 'important point');
annotation('arrow', [0.3 0.5], [0.3 0.5]);

% figure and axes properties
set(gcf, 'Position', [100 100 800 600]);
set(gca, 'FontSize', 14, 'FontName', 'Arial');
set(gca, 'XScale', 'log');  % log scale

% latex in labels
title('Function: \\alpha + \\beta^2', 'Interpreter', 'latex');

% export high quality
exportgraphics(gcf, 'plot.pdf', 'ContentType', 'vector');
exportgraphics(gcf, 'plot.png', 'Resolution', 300);

% legend customization
legend('show', 'Location', 'northwest', ...
       'FontSize', 12, 'Box', 'off');

% multiple figures
f1 = figure; plot(x, sin(x));
f2 = figure; plot(x, cos(x));
figure(f1);  % switch back to f1
06

数据分析与统计

描述性统计

MATLAB 提供了全面的统计函数。mean/median/mode 用于集中趋势;std/var/range/iqr 用于离散程度。默认情况下,这些函数沿第一维度(列)运算。使用 'omitnan' 跳过 NaN 值(对真实世界数据很重要)。quantile/prctile 给出百分位数。统计和机器学习工具箱添加了 geomean、harmmean、zscore 和分布函数。分析前始终检查 NaN——它们会通过大多数运算传播。

matlab
data = [1 2 3 4 5 6 7 8 9 10];

% central tendency
mean(data)            % 5.5
median(data)          % 5.5
mode(data)            % 1 (first mode)
geomean(data)         % geometric mean (Stats toolbox)
harmmean(data)        % harmonic mean

% dispersion
std(data)             % standard deviation
var(data)             % variance
range(data)           % max - min
iqr(data)             % interquartile range
mad(data)             % mean absolute deviation

% extremes and quantiles
min(data); max(data);
quantile(data, 0.25)  % 25th percentile
prctile(data, 95)     % 95th percentile

% along dimensions
A = randn(100, 3);
mean(A)               % mean of each column
mean(A, 2)            % mean of each row
mean(A, 'all')        % overall mean

% ignoring NaNs
data(5) = NaN;
mean(data, 'omitnan') % skip NaN values
nanmean(data)         % legacy equivalent

曲线拟合与回归

polyfit 拟合给定次数的多项式;polyval 对其求值。对于线性回归,regress() 给出系数加统计量(R²、F 统计量、p 值)。corrcoef 返回完整的相关矩阵。曲线拟合工具箱提供 fit() 用于交互式和编程式拟合自定义模型。lsqcurvefit(优化工具箱)拟合任意非线性模型。始终将拟合结果与数据绘图以检查质量——高阶多项式可能过拟合。

matlab
% polynomial fit
x = 0:0.5:10;
y = 2*x + 1 + randn(size(x))*2;  % noisy linear data

% linear least squares (degree 1)
p = polyfit(x, y, 1);   % [slope, intercept]
yfit = polyval(p, x);
plot(x, y, 'o', x, yfit, '-');

% higher-order polynomial
p3 = polyfit(x, y, 3);
yfit3 = polyval(p3, x);

% fit with fittype (Curve Fitting Toolbox)
f = fit(x', y', 'poly2');  % quadratic
plot(f, x, y);

% custom model fit
% fit y = a*exp(b*x) using lsqcurvefit
model = @(p, x) p(1)*exp(p(2)*x);
params = lsqcurvefit(model, [1 0.1], x, y);

% correlation
r = corrcoef(x, y);     % correlation matrix
r = corr(x, y);         % correlation coefficient

% linear regression with stats
X = [ones(size(x)) x'];  % design matrix
[b, bint, r, rint, stats] = regress(y', X);
% stats = [R^2, F, p, error_var]

插值与重采样

interp1 对 1D 数据进行插值——'linear' 快速,'spline' 平滑(可能过冲),'pchip' 保持形状(无过冲)。interp2 对 2D 网格做同样的事。对于重复查询,griddedInterpolant 更高效(构建一次,查询多次)。resample 改变信号的采样率(需要信号处理工具箱)。始终根据数据选择方法:平滑函数用 spline,单调数据用 pchip,分类数据用 nearest。

matlab
% 1D interpolation
x = 0:5;
y = [0 1 4 9 16 25];
xi = 0:0.5:5;

yi = interp1(x, y, xi, 'linear');   % linear (default)
yi = interp1(x, y, xi, 'spline');   % cubic spline
yi = interp1(x, y, xi, 'pchip');    % shape-preserving
yi = interp1(x, y, xi, 'nearest');  % nearest neighbor

% extrapolation
yi = interp1(x, y, xi, 'linear', 'extrap');

% 2D interpolation
[X, Y] = meshgrid(0:2:10);
Z = X.^2 + Y.^2;
[Xi, Yi] = meshgrid(0:0.5:10);
Zi = interp2(X, Y, Z, Xi, Yi, 'spline');

% resample signal to new rate
y_resampled = resample(y, 3, 2);  % 3/2 times the rate

% griddedInterpolant (efficient for repeated queries)
F = griddedInterpolant(x, y, 'spline');
y1 = F(2.5);
y2 = F([1.5 3.5 4.5]);

FFT 与信号处理

fft 计算快速傅里叶变换——频域分析的基础。输出是复数;取 abs() 获得幅值。通过取前半部分并加倍(DC 和 Nyquist 除外)转换为单边频谱。频率范围从 0 到 fs/2(Nyquist)。ifft 反变换回时域。频域滤波(将不需要的频率置零)简单但可能导致振铃;使用 designfilt 进行正确的滤波。spectrogram 显示随时间变化的频率内容。

matlab
% generate a signal with two frequencies
fs = 1000;                    % sampling rate (Hz)
t = 0:1/fs:1-1/fs;            % 1 second of time
x = 2*sin(2*pi*50*t) + 1*sin(2*pi*120*t);

% compute FFT
N = length(x);
Y = fft(x);
P2 = abs(Y/N);                % two-sided spectrum
P1 = P2(1:N/2+1);             % one-sided spectrum
P1(2:end-1) = 2*P1(2:end-1);
f = fs*(0:(N/2))/N;

% plot
plot(f, P1);
xlabel('Frequency (Hz)');
ylabel('Amplitude');
title('Single-Sided Spectrum');

% filtering (simple low-pass)
cutoff = 100;  % Hz
Y_filt = Y;
Y_filt(f > cutoff) = 0;       % zero out high freqs (simplified)
x_filtered = real(ifft(Y_filt));

% spectrogram
spectrogram(x, 128, 120, 128, fs, 'yaxis');

优化与求根

fzero 查找 1D 函数的根(需要包围区间或猜测)。fminbnd 在有界区间上最小化 1D 函数;fminsearch 使用 Nelder-Mead 进行多变量无约束优化。fmincon(优化工具箱)处理约束。linprog 求解线性规划。始终为迭代求解器提供良好的初始猜测(x0)。检查 exitflag 输出以确认收敛。对于全局优化,使用 GlobalSearch 或 MultiStart。

matlab
% find root of f(x) = 0
f = @(x) x^2 - 2;
x_root = fzero(f, 1);         % ~1.4142 (sqrt(2))
x_root = fsolve(f, 1);        % alternative

% minimize a function
fun = @(x) (x-3)^2 + 1;
[x_min, f_min] = fminbnd(fun, 0, 5);  % bounded 1D
% x_min = 3, f_min = 1

% multivariate minimization
fun2 = @(x) x(1)^2 + x(2)^2;  % sphere function
x0 = [1, 1];
[x_opt, f_opt] = fminsearch(fun2, x0);
% x_opt ≈ [0, 0]

% constrained optimization (Optimization Toolbox)
% minimize fun subject to A*x <= b
A = []; b = []; Aeq = []; beq = [];
lb = [0 0]; ub = [];
[x, fval] = fmincon(fun2, x0, A, b, Aeq, beq, lb, ub);

% linear programming
% minimize f'*x subject to A*x <= b
f = [-1; -1];                 % maximize x+y
A = [1 1; -1 0; 0 -1];
b = [2; 0; 0];
[x, fval] = linprog(f, A, b);
07

文件输入输出与数据导入

MAT 文件与保存/加载

.mat 是 MATLAB 的原生二进制格式——快速、紧凑,并保留所有变量类型。save/load 是主要命令。对于超过 2GB 的文件使用 -v7.3(基于 HDF5)。-ascii 导出到人类可读的文本(丢失类型信息)。加载到结构体中(s = load(...))可避免污染工作区。clear 移除变量;clearvars -except 保留指定的变量。在长时间计算中始终保存中间结果以便恢复。

matlab
% save variables to a .mat file
x = 1:10;
y = sin(x);
save('data.mat');             % save ALL variables
save('data.mat', 'x', 'y');   % save specific variables
save('data.mat', '-append');  % add more variables

% load variables
load('data.mat');             % load all into workspace
loaded = load('data.mat');    % load into a struct
loaded.x                      % access via struct

% save with compression
save('data.mat', 'x', 'y', '-v7.3');  % large files (>2GB)
save('data.mat', '-v7');              % compressed (default)

% save specific format
save('data.txt', 'x', '-ascii');      % plain text
save('data.csv', 'x', '-ascii', '-double');

% clear variables
clear x y;                    % remove specific
clear all;                    % remove everything
clearvars -except x;          % keep only x

读取文本与 CSV 文件

readtable 是读取 CSV/Excel 的现代方式——它返回带有命名列的表格并自动处理标题。readmatrix 将数值数据读入矩阵。要完全控制,使用 fopen/fgetl/fprintf/fclose(始终关闭文件!)。fscanf 读取格式化数据,类似 C。始终检查 fid 是否出错:如果 fid == -1,则文件无法打开。readcell 处理不适合矩阵或表格的混合类型数据。

matlab
% readtable (recommended for tabular data)
T = readtable('data.csv');
T = readtable('data.xlsx', 'Sheet', 'Sheet1');
T = readtable('data.csv', 'Delimiter', ',');

% access columns by name
T.Var1; T.age;

% readmatrix (numeric data)
M = readmatrix('numbers.csv');
M = readmatrix('data.txt', 'Delimiter', '\t');

% readcell (mixed data)
C = readcell('mixed.csv');

% low-level file I/O
fid = fopen('data.txt', 'r');
while ~feof(fid)
    line = fgetl(fid);
    disp(line);
end
fclose(fid);

% read formatted data
fid = fopen('data.txt', 'r');
data = fscanf(fid, '%f %f', [2, inf]);
fclose(fid);

% write text
fid = fopen('output.txt', 'w');
fprintf(fid, 'Result: %.2f\n', 3.14159);
fclose(fid);

Excel 与电子表格输入输出

readtable/writetable 是 Excel 输入输出的推荐函数。它们自动处理标题、类型和工作表。detectImportOptions 让你自定义列的解析方式(例如,强制将某列解析为 int32 或字符串)。使用 'Range' 读取/写入特定单元格。'WriteMode','append' 向现有工作表添加行。对于大型 Excel 文件,考虑 CSV(更快)或 .mat(原生)。Spreadsheet Link 工具箱将 MATLAB 直接连接到 Excel。

matlab
% read Excel files
T = readtable('data.xlsx');
T = readtable('data.xlsx', 'Sheet', 'Sales', 'Range', 'A1:D100');

% numeric data only
M = readmatrix('data.xlsx', 'Sheet', 1);

% write to Excel
writetable(T, 'output.xlsx');
writetable(T, 'output.xlsx', 'Sheet', 'Results');

% write matrix
writematrix(M, 'output.xlsx', 'Sheet', 1);

% cell array (mixed types)
C = {'Name','Age'; 'Alice',30; 'Bob',25};
writecell(C, 'people.xlsx');

% append to existing sheet
writetable(T, 'data.xlsx', 'Sheet', 1, 'WriteMode', 'append');

% read specific range
T = readtable('data.xlsx', 'Range', 'B2:D10');

% detect import options (customize parsing)
opts = detectImportOptions('data.csv');
opts = setvartype(opts, 'age', 'int32');
T = readtable('data.csv', opts);

处理路径与目录

dir() 返回一个结构体数组,包含每个文件的 .name、.date、.bytes、.isdir、.datenum。fullfile 可移植地连接路径(在每个操作系统上使用正确的分隔符)。fileparts 将路径拆分为目录、名称和扩展名。exist('name', 'file') 检查文件是否存在。addpath 将目录添加到 MATLAB 的搜索路径,使其中的函数可访问;savepath 持久化此设置。这些对于批量处理文件夹中的文件至关重要。

matlab
% current directory
pwd
cd('C:\\Users\\data')

% list files
files = dir();              % struct array of files
files = dir('*.mat');       % filter by pattern
files = dir('subdir/');     % list a subdirectory

% access file info
for i = 1:length(files)
    if ~files(i).isdir
        fprintf('%s - %d bytes\n', files(i).name, files(i).bytes);
    end
end

% path operations
fullfile('data', '2024', 'file.csv')  % data/2024/file.csv
[filepath, name, ext] = fileparts('C:\\data\\test.csv')
% filepath = 'C:\data', name = 'test', ext = '.csv'

% create and remove directories
mkdir('output');
rmdir('output', 's');      % remove recursively

% file existence
if exist('data.mat', 'file')
    load('data.mat');
end

% add folder to path
addpath('C:\\myfunctions');
savepath();                 % save for future sessions

图像与音频

imread/imshow/imwrite 处理图像(JPEG、PNG、TIFF、BMP)。图像存储为 uint8 矩阵(0-255)或 double(0-1)。rgb2gray 将彩色转换为灰度。图像处理工具箱添加了 imresize、imrotate、imfilter、边缘检测和形态学运算。audioread/audiowrite/sound 处理音频文件。图像和音频只是矩阵,因此所有 MATLAB 数学运算和绘图工具都直接适用。

matlab
% read and display an image
img = imread('photo.jpg');
imshow(img);
[m, n, c] = size(img);     % dimensions, c=3 for RGB

% write image
imwrite(img, 'output.png');
imwrite(img, 'output.jpg', 'Quality', 90);

% convert to grayscale
if size(img, 3) == 3
    gray = rgb2gray(img);
    imshow(gray);
end

% image processing
img2 = imresize(img, 0.5);          % scale 50%
img3 = imrotate(img, 45);           % rotate 45 degrees
img4 = imadjust(img, [0.2 0.8], []); % contrast adjust

% audio
[y, fs] = audioread('song.wav');    % y = samples, fs = sample rate
sound(y, fs);                        % play audio
audiowrite('output.wav', y, fs);

% record audio
recObj = audiorecorder(44100, 16, 1);
recordblocking(recObj, 3);           % record 3 seconds
y = getaudiodata(recObj);
08

符号数学与高级主题

符号变量与化简

符号数学工具箱支持精确(非数值)计算。syms 声明符号变量。simplify、expand、factor、collect 操作代数表达式。subs 替换值或变量。vpa(可变精度算术)以任意精度计算——当浮点舍入误差有影响时很有用。符号结果是精确的(例如,sqrt(2) 保持为 sqrt(2),而不是 1.4142...)。需要时用 double() 转换为数值。

matlab
% create symbolic variables (Symbolic Math Toolbox)
syms x y z

% symbolic expressions
f = x^2 + 2*x + 1;
g = sin(x)^2 + cos(x)^2;

% simplify
simplify(f)             % (x + 1)^2
simplify(g)             % 1
expand((x+1)^3)         % x^3 + 3*x^2 + 3*x + 1
factor(x^2 - 1)         % (x - 1)*(x + 1)
collect(x^2 + 2*x + x^2)% 2*x^2 + 2*x

% substitute values
subs(f, x, 3)           % 16 (f at x=3)
subs(f, x, y)           % y^2 + 2*y + 1

% pretty print
pretty(f)
disp(f)

% convert between numeric and symbolic
double(sym('1/3'))      % 0.3333
sym(0.5)                % 1/2
vpa(pi, 50)             % 50-digit pi: 3.1415926535897...

微积分:导数与积分

diff 求导(传入第二个参数求高阶导数)。int 求积分——没有边界时返回原函数;有边界时计算定积分。limit 计算极限(包括用 'left'/'right' 求单侧极限)。taylor 将函数在某点展开为泰勒级数。这些返回符号表达式;使用 double() 或 vpa() 获得数值结果。符号微积分是精确的,避免了数值舍入误差。

matlab
syms x

% differentiation
f = x^3 + 2*x^2 + x;
df = diff(f)            % 3*x^2 + 4*x + 1
d2f = diff(f, 2)        % second derivative: 6*x + 4
diff(f, x, 3)           % third derivative: 6

% partial derivatives
syms x y
g = x^2 * y + sin(x*y);
diff(g, x)              % 2*x*y + y*cos(x*y)
diff(g, y)              % x^2 + x*cos(x*y)

% integration
int(x^2)                % x^3/3 (indefinite)
int(x^2, x, 0, 1)       % 1/3 (definite, 0 to 1)
int(sin(x), x, 0, pi)   % 2

% limits
limit(sin(x)/x, x, 0)   % 1
limit(1/x, x, inf)      % 0
limit(1/x, x, 0, 'left')  % -inf

% Taylor series
taylor(exp(x), x, 0, 'Order', 6)
% 1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120

求解方程

solve 求代数方程和方程组的精确(符号)解。对于没有闭式解的方程,使用 vpasolve(数值)。dsolve 符号求解常微分方程——提供初始/边界条件可获得特解。结果是符号的;用 double/vpa 转换以便绘图。对于无法符号求解的复杂 ODE,改用 ode45(数值求解器)。始终检查 solve 是否返回空(未找到解)。

matlab
syms x y

% solve algebraic equations
solve(x^2 - 4 == 0, x)        % [2; -2]
solve(x^2 + 1 == 0, x)        % [i; -i] (complex roots)

% solve a system
sol = solve([x + y == 5, x - y == 1], [x, y]);
sol.x                        % 3
sol.y                        % 2

% solve with parameters
syms a b c
r = solve(a*x^2 + b*x + c == 0, x);
% r = -(b + (b^2 - 4*a*c)^(1/2))/(2*a), ...

% numerical solve (no closed form)
vpasolve(x^5 - 3*x + 1 == 0, x)

% differential equations
syms y(t) t
ode = diff(y, t) == -k*y;     % dy/dt = -k*y
cond = y(0) == y0;
ySol(t) = dsolve(ode, cond);  % y0*exp(-k*t)

% system of ODEs
syms x(t) y(t)
eq1 = diff(x,t) == y;
eq2 = diff(y,t) == -x;
sol = dsolve([eq1, eq2]);

拉普拉斯与傅里叶变换

laplace/ilaplace 计算拉普拉斯变换对——对求解线性 ODE 和分析控制系统至关重要。fourier/ifourier 对傅里叶变换(连续频率)做同样的事。ztrans/iztrans 处理离散信号(数字滤波器)。通过拉普拉斯求解 ODE 的工作流程:将 ODE 变换为代数方程,求解 Y(s),然后反变换。这些是精确的符号运算;数值变换使用 fft。

matlab
syms t s w

% Laplace transform
f = exp(-a*t);
F = laplace(f)          % 1/(a + s)
% default: f(t) -> F(s)

% inverse Laplace
f2 = ilaplace(1/(s+1))  % exp(-t)

% Fourier transform
g = exp(-t^2);
G = fourier(g)          % pi^(1/2)*exp(-w^2/4)

% inverse Fourier
g2 = ifourier(G)

% Z-transform (for discrete signals)
syms n z
h = a^n;
H = ztrans(h)           % -z/(a - z) (for |z| > |a|)
h2 = iztrans(z/(z-a))   % a^n

% apply transform to solve ODE
% y'' + y = 0, y(0)=0, y'(0)=1
syms y(t) Y(s)
ode = diff(y, t, 2) + y == 0;
% take Laplace of both sides, solve for Y(s), then invert

数值 ODE 求解器

ode45 是首选的 ODE 求解器——一种 Runge-Kutta (4,5) 方法,准确且自适应。对于方程组,状态是向量 v,函数返回导数的列向量。ode15s 用于刚性问题(动力学在非常不同的时间尺度上运行)。odeset 配置容差和事件。要传递参数,使用捕获它们的匿名函数。始终绘制解以验证其合理性。对于边值问题,使用 bvp4c。

matlab
% solve dy/dt = f(t, y) numerically with ode45

% define the ODE as a function
f = @(t, y) -2*y;       % dy/dt = -2y (exponential decay)

% solve on [0, 5] with y(0) = 1
[t, y] = ode45(f, [0 5], 1);
plot(t, y);
xlabel('t'); ylabel('y');

% system of ODEs (Lotka-Volterra predator-prey)
% dx/dt = 1.5x - xy,  dy/dt = -0.7y + 0.1xy
ode_sys = @(t, v) [1.5*v(1) - v(1)*v(2);
                   -0.7*v(2) + 0.1*v(1)*v(2)];
[t, V] = ode45(ode_sys, [0 20], [10; 5]);
plot(t, V(:,1), 'b', t, V(:,2), 'r');
legend('Prey', 'Predator');

% stiff ODE solver (for fast dynamics)
[t, y] = ode15s(f, [0 5], 1);

% set options
opts = odeset('RelTol', 1e-6, 'AbsTol', 1e-9);
[t, y] = ode45(f, [0 5], 1, opts);

% pass parameters via anonymous function
a = 0.5;
f = @(t, y, a) -a*y;
[t, y] = ode45(@(t,y) f(t,y,a), [0 10], 1);
09

矩阵运算深入

线性方程与分解

反斜杠运算符(\)是 MATLAB 首选的线性求解器——它根据矩阵自动选择 LU、QR 或 Cholesky 分解。除非你确实需要逆矩阵,否则永远不要使用 inv(A)*b;它更慢且数值稳定性更差。lu、qr 和 chol 返回标准的矩阵分解。eig 计算特征值/特征向量,svd 给出奇异值分解——对 PCA、伪逆和低秩近似至关重要。

matlab
% solve Ax = b
A = [3 2 -1; 2 -2 4; -1 0.5 -1];
b = [1; -2; 0];
x = A \ b;             % backslash: preferred solver
x = inv(A) * b;         % explicit inverse (slower, less stable)
x = linsolve(A, b);     % optimized linear solver

% LU, QR, Cholesky decompositions
[L, U, P] = lu(A);      % PA = LU
[Q, R] = qr(A);         % QR factorization
R = chol(A'*A);         % Cholesky (needs SPD matrix)

% eigenvalues and eigenvectors
[V, D] = eig(A);        % A*V = V*D
eigenvalues = diag(D);

% singular value decomposition
[U, S, V] = svd(A);     % A = U*S*V'

稀疏矩阵

稀疏矩阵只存储非零元素——在处理 100k+ 维且大部分为零的矩阵时至关重要(常见于有限元方法、图算法和 PDE)。sparse(i,j,v) 从三元组形式构建;full 转换回去。稀疏矩阵之间的算术运算保持稀疏。nnz 计算非零元素,spy 绘制稀疏模式。稀疏线性求解(A\b)自动使用 UMFPACK 等专用求解器。

matlab
% create sparse matrix (memory efficient for large, mostly-zero)
S = sparse(10000, 10000);
S(1, 1) = 5;
S(2, 3) = 10;

% from triplets (row, col, value)
i = [1 2 2 3];
j = [1 1 3 3];
v = [4 5 7 9];
S = sparse(i, j, v, 3, 3);

% convert sparse <-> full
F = full(S);
S2 = sparse(F);

% sparse identity and diagonal
I = speye(1000);
D = spdiags(ones(1000,1), 0, 1000, 1000);

% operations preserve sparsity
nnz(S)                  % number of nonzeros
spy(S)                  % visualize sparsity pattern

矩阵函数与重塑

reshape 按列优先(先沿列向下)重新排列元素——从行优先语言移植时的常见错误来源。flipud/fliplr/rot90 用于以非标准方式反转或转置很方便。repmat 平铺矩阵;repelem 复制单个元素。拼接使用 [A; B](垂直)和 [A B](水平),或使用 horzcat/vertcat 进行编程式使用。当无法向量化时,arrayfun 逐元素应用函数。

matlab
A = [1 2 3; 4 5 6];

% reshape (column-major order!)
B = reshape(A, 3, 2);   % [1 5; 4 3; 2 6]
C = reshape(A, 6, 1);   % column vector

% flip and rotate
flipud(A)               % flip up-down
fliplr(A)               % flip left-right
rot90(A)                % rotate 90 degrees
rot90(A, 2)             % rotate 180 degrees

% repmat and repelem
repmat([1 2], 2, 3)     % tile 2x3
repelem([1 2 3], 2)     % [1 1 2 2 3 3]

% concatenation
[A; A]                  % vertical (must have same # cols)
[A A]                   % horizontal (must have same # rows)
horzcat(A, A); vertcat(A, A);

% matrix functions (apply element-wise via fun)
arrayfun(@(x) x^2, A)

广播与向量化

自 R2016b 起,MATLAB 自动广播(扩展)大小为 1 的维度以匹配另一个操作数——不需要 bsxfun 或 repmat。向量化(对整个数组而非逐元素循环进行操作)是 MATLAB 中最大的性能提升,因为底层的 BLAS/LAPACK 例程高度优化。在循环中填充数组前始终预分配;动态增长数组会迫使每次迭代重新分配,复杂度为 O(n^2)。

matlab
% MATLAB implicitly expands (broadcasts) since R2016b
A = [1 2 3; 4 5 6];     % 2x3
b = [10 20 30];         % 1x3
C = A + b;              % 2x3: b added to each row

c = [1; 2];             % 2x1
D = A + c;              % 2x3: c added to each column

% vectorized operations (much faster than loops)
x = linspace(0, 2*pi, 1e6);
y = sin(x) .* cos(x);   % element-wise, no loop needed

% avoid growing arrays in loops
% BAD: for k=1:1e6, s(k) = k; end
% GOOD: preallocate
s = zeros(1, 1e6);
for k = 1:1e6
    s(k) = k;
end

% even better: vectorize
s = 1:1e6;

% bsxfun (legacy, before auto-broadcasting)
E = bsxfun(@plus, A, b);

数值线性代数应用

当 A 是矩形(行多于列)时,反斜杠运算符自动求解最小二乘问题。polyfit/polyval 拟合和求值多项式。PCA 最稳定地通过中心化数据矩阵的 SVD 计算——V 的列是主方向,diag(S) 给出标准差。cond(A) 衡量数值敏感性;值超过 1e12 意味着对于双精度算术,矩阵本质上是奇异的。

matlab
% least-squares fit (overdetermined system)
A = [1 1; 1 2; 1 3; 1 4];
b = [6; 5; 7; 10];
x = A \ b;             % least-squares solution

% polynomial curve fitting
t = 0:0.1:5;
y = 2*t.^2 + 1 + 0.5*randn(size(t));
p = polyfit(t, y, 2);   % degree-2 fit
yfit = polyval(p, t);

% PCA via SVD
X = randn(100, 5);
Xc = X - mean(X);       % center
[U, S, V] = svd(Xc, 0);
scores = Xc * V;        % principal components
variances = diag(S).^2 / (size(X,1)-1);

% condition number (numerical stability)
cond(A)                 % large = ill-conditioned
10

2D 与 3D 绘图深入

线图与自定义

plot 是主力 2D 绘图函数。线型字符串如 'r--'(红色虚线)组合颜色、标记和样式。hold on 让你叠加多个绘图。subplot(m,n,k) 创建 m 行 n 列网格并选择第 k 个单元格(行优先)。set(gca, ...) 修改当前坐标轴;gcf 是当前图形。使用 -dpng 和 -r300 的 print 导出 300 DPI 的 PNG——质量远高于 saveas。

matlab
x = linspace(0, 2*pi, 200);
y1 = sin(x); y2 = cos(x);

figure;
plot(x, y1, 'b-', 'LineWidth', 2); hold on;
plot(x, y2, 'r--', 'LineWidth', 1.5);
hold off;

% annotations
xlabel('Angle (rad)');
ylabel('Amplitude');
title('Sine and Cosine');
legend('sin(x)', 'cos(x)', 'Location', 'best');
grid on;

% axis control
axis([0 2*pi -1.2 1.2]);
set(gca, 'FontSize', 12, 'FontName', 'Arial');

% multiple subplots
subplot(2, 1, 1); plot(x, y1);
subplot(2, 1, 2); plot(x, y2);

% save figure
saveas(gcf, 'plot.png');
print('-dpng', '-r300', 'plot_hi.png');

3D 曲面、网格与等高线图

meshgrid 创建曲面图所需的 X、Y 坐标网格。surf 绘制填充曲面,mesh 绘制线框,contour 投影到 2D 等高线。colormap 更改颜色映射(jet、parula、hot、cool、gray);parula 是现代默认值。shading interp 平滑颜色过渡。plot3 绘制 3D 参数曲线。view(az, el) 设置相机角度;axis equal 防止失真。

matlab
[X, Y] = meshgrid(-2:0.1:2);
Z = X .* exp(-X.^2 - Y.^2);

figure;
subplot(2,2,1); surf(X, Y, Z);    title('surf');
subplot(2,2,2); mesh(X, Y, Z);    title('mesh');
subplot(2,2,3); contour(X, Y, Z, 20); title('contour');
subplot(2,2,4); surfc(X, Y, Z);   title('surfc');

% color mapping
colormap(jet(256)); colorbar;
shading interp;        % smooth colors

% 3D line plot (parametric)
t = 0:0.01:10;
plot3(sin(t), cos(t), t, 'LineWidth', 2);
xlabel('x'); ylabel('y'); zlabel('z');

% view angle
view(45, 30);          % azimuth, elevation
axis equal;

统计与专用绘图

histogram(R2014b+)以更多功能替代 hist,如用于 PDF 的 'Normalization'。boxplot 比较各组分布。scatterhist 显示带有边缘直方图的散点图——非常适合可视化相关性。bar 支持分组和堆叠布局。errorbar 添加不确定性可视化。这些专用绘图对科学数据展示和探索性分析至关重要。

matlab
data = randn(1000, 1);

% histogram (modern)
histogram(data, 30, 'Normalization', 'pdf');
hold on; x = -4:0.1:4; plot(x, normpdf(x), 'r-', 'LineWidth', 2);

% box plot by group
g = randi([1 3], 100, 1);
boxplot(data, g);

% scatter with marginal histograms
x = randn(200,1); y = x + 0.5*randn(200,1);
scatterhist(x, y);

% bar chart
sales = [10 25 30; 20 15 40];
bar(sales); legend('Q1','Q2','Q3');

% pie chart
pie([30 20 50], {'A','B','C'});

% error bars
y = [1 2 3 4]; e = [0.1 0.2 0.15 0.3];
errorbar(y, e, 'o-');

动画与交互式图形

动画在循环内更新绘图数据并调用 drawnow 刷新。为了流畅的性能,创建一次绘图并更新 XData/YData 而非重新绘图。getframe 捕获当前图形;movie 播放序列。VideoWriter 导出到 MP4 或 AVI——用于分享结果很有用。始终在循环外设置坐标轴范围以防止自动缩放抖动。

matlab
% animated line plot
figure;
h = plot(NaN, NaN);
axis([0 10 -1 1]); xlabel('t'); ylabel('y');
for t = 0:0.1:10
    set(h, 'XData', [get(h,'XData') t], ...
           'YData', [get(h,'YData') sin(t)]);
    drawnow;
end

% getframe to capture animation
frames = [];
for k = 1:50
    plot(sin(linspace(0, k*pi/10, 200)));
    axis([0 200 -1 1]);
    frames = [frames, getframe];
end
movie(frames, 1, 30);   % play once at 30 fps

% write to video file
v = VideoWriter('anim.mp4', 'MPEG-4');
v.FrameRate = 30; open(v);
for k = 1:50
    plot(sin(linspace(0, k*pi/10, 200)));
    writeVideo(v, getframe);
end
close(v);

图形对象与句柄自定义

MATLAB 图形建立在句柄对象树之上(figure → axes → lines、text、patches)。set/get 修改属性;findobj 按属性定位对象。'Interpreter' 选项启用 TeX 或完整 LaTeX 渲染数学符号。exportgraphics(R2020a+)生成出版质量的矢量 PDF,带有紧凑的边界框——远胜旧的 print 用于嵌入论文。

matlab
% everything in MATLAB graphics is a handle object
h = plot(1:10, 'r-');
set(h, 'LineWidth', 3, 'Marker', 'o', 'MarkerSize', 8);
get(h, 'Color')         % returns [1 0 0]

% find objects
ax = gca;               % current axes
fig = gcf;              % current figure
lines = findobj(ax, 'Type', 'line');

% property exploration
get(ax)                 % list all axes properties
set(ax)                 % list possible values

% text annotations with LaTeX
text(2, 0.5, '\alpha^2 + \beta^2', 'Interpreter', 'tex');
title('$\int_0^1 x^2 dx$', 'Interpreter', 'latex');

% legend with custom location and orientation
legend({'data1','data2'}, 'Location','northwest','Orientation','horizontal');

% export with tight bounding box
exportgraphics(gcf, 'fig.pdf', 'ContentType','vector');
12

GUI 与 App Designer

App Designer 基础

App Designer(通过 appdesigner 启动)是用于构建 MATLAB GUI 的现代可视化工具,保存捆绑布局和代码的 .mlapp 文件。对于编程式 UI,uifigure(R2014b+)创建带有 uibutton、uilabel、uieditfield、uislider、uidropdown 和 uiaxes 的现代图形窗口。回调是分配给 ButtonPushedFcn 等属性的函数句柄。旧的 GUIDE 已弃用;新代码应使用基于 uifigure 的组件或 App Designer。

matlab
% App Designer (appdesigner command) creates .mlapp files
% Modern replacement for GUIDE (deprecated in R2020a)

% programmatic UI (alternative to App Designer)
f = uifigure('Name', 'My App', 'Position', [100 100 600 400]);

% add components
btn = uibutton(f, 'Text', 'Click Me', ...
    'Position', [50 300 100 30]);
lbl = uilabel(f, 'Text', 'Hello', ...
    'Position', [50 250 200 30]);
fld = uieditfield(f, 'text', 'Position', [50 200 200 30]);

% slider and drop-down
sld = uislider(f, 'Position', [50 150 200 3]);
dd = uidropdown(f, 'Items', {'A','B','C'}, ...
    'Position', [50 100 100 30]);

% axes for plotting
ax = uiaxes(f, 'Position', [300 100 250 250]);
plot(ax, 1:10, rand(1,10));

% callback
btn.ButtonPushedFcn = @(src,event) clickHandler(lbl);

function clickHandler(lbl)
    lbl.Text = ['Clicked at ' datestr(now)];
end

布局管理器与容器

uigridlayout(R2018b+)是现代响应式布局管理器——行和列可以是固定的、成比例的('1x')或适应内容的。uitabgroup/uitab 创建选项卡式界面。uipanel 在视觉上分组相关组件。uiscrollbox 为超出窗口的内容添加滚动。对话框函数(uigetfile、inputdlg、msgbox、questdlg)处理标准文件选择、输入和通知。这些布局工具对于构建专业的、可调整大小的 MATLAB 应用程序至关重要。

matlab
f = uifigure;

% grid layout (responsive)
g = uigridlayout(f, [3 2]);
g.RowHeight = {'1x', '2x', '1x'};
g.ColumnWidth = {'1x', '2x'};

btn1 = uibutton(g); btn1.Layout.Row = 1; btn1.Layout.Column = 1;
btn2 = uibutton(g); btn2.Layout.Row = 1; btn2.Layout.Column = 2;

% tab group
tg = uitabgroup(f);
t1 = uitab(tg, 'Title', 'Plot');
t2 = uitab(tg, 'Title', 'Data');
ax = uiaxes(t1); plot(ax, rand(5));

% panel for grouping
p = uipanel(f, 'Title', 'Settings', 'Position', [20 20 200 150]);

% scrollable container for long content
sf = uiscrollbox(f);
% add many components inside sf

% dialog windows
uigetfile('*.mat', 'Select MAT file');
inputdlg({'Name','Age'}, 'Enter data');
msgbox('Operation complete');

回调与事件处理

现代 MATLAB 使用带两个参数(src、event)的函数句柄回调,其中 event 携带结构化数据,如 event.Value 或 event.Key。ValueChangingFcn 在交互过程中持续触发;ValueChangedFcn 在结束时触发一次。addlistener 在任何属性上创建持久监听器。timer 对象按计划运行回调——对实时数据采集 UI 很有用。始终清理监听器和计时器(delete)以避免内存泄漏。

matlab
% value-changing callback (slider)
sld = uislider(f);
sld.ValueChangingFcn = @(src,event) onSlider(src, event);

function onSlider(src, event)
    disp(['Dragging: ' num2str(event.Value)]);
end

% value-changed callback (final value)
sld.ValueChangedFcn = @(src,event) disp(['Final: ' num2str(event.Value)]);

% button callback with event data
btn.ButtonPushedFcn = @onButton;
function onButton(src, event)
    fprintf('Button %s pushed
', src.Text);
end

% keyboard callback on figure
f.WindowKeyPressFcn = @(src,event) onKey(event);
function onKey(event)
    fprintf('Key: %s
', event.Key);
end

% listener pattern (any property change)
lh = addlistener(btn, 'Text', 'PostSet', @(src,event) disp('Text changed'));
delete(lh);  % remove listener

% timer for periodic updates
t = timer('ExecutionMode','fixedRate','Period',1, ...
    'TimerFcn',@(~,~) disp('tick'));
start(t);

打包应用程序以供分发

matlab.apputil.package 将 App Designer 应用程序打包成 .mlappinstall 文件,用户通过应用程序选项卡安装。应用程序编译器(deploytool)生成独立可执行文件(.exe),随免费的 MATLAB Runtime 运行——目标机器上不需要 MATLAB 许可证。Web Apps(R2020a+)部署到 MATLAB Web App Server 并在任何浏览器中运行。此分发管道让你与非 MATLAB 用户共享 MATLAB 应用程序。

matlab
% package an App Designer app as a .mlappinstall file
% using the Application Compiler (deploytool app)

% programmatically create a packaged app
appFile = matlab.apputil.package(...
    'Name', 'MyPlotTool', ...
    'Summary', 'A simple plotting utility', ...
    'Description', 'Plots user-supplied data.', ...
    'MainFile', 'MyPlotTool.mlapp', ...
    'FolderPath', 'my_app_package');

% install the app
matlab.apputil.install('MyPlotTool.mlappinstall');

% list installed apps
apps = matlab.apputil.getInstalledApps;

% uninstall
matlab.apputil.uninstall('MyPlotTool');

% standalone desktop app (MATLAB Runtime required)
% deploytool -> Application Compiler -> produce .exe

% web app (runs in browser, MATLAB Web App Server)
% deploytool -> Web App

常见 UI 模式

drawnow limitrate 更新图形而不阻塞——对实时数据显示至关重要。uitable 显示带有可排序列的表格数据。uiprogressdlg 为长时间操作显示模态进度条。uicontextmenu 为任何组件添加右键菜单。这些模式涵盖最常见的 UI 需求:实时更新、数据表、进度反馈和上下文相关操作。对于高吞吐量实时绘图,考虑为流数据优化的 animatedline。

matlab
% live plot update from worker
f = uifigure; ax = uiaxes(f); h = plot(ax, NaN, NaN);
for k = 1:100
    set(h, 'XData', 1:k, 'YData', rand(1,k));
    drawnow limitrate;  % throttle for performance
end

% table display
tdata = table({'A';'B';'C'}, [1;2;3], 'VariableNames', {'Name','Val'});
uit = uitable(f, 'Data', tdata.Variables, ...
    'ColumnName', tdata.Properties.VariableNames, ...
    'Position', [20 20 200 150]);

% progress dialog
d = uiprogressdlg(f, 'Title', 'Working', 'Message', 'Processing...');
for k = 1:100
    pause(0.01);
    d.Value = k;
    d.Message = sprintf('%d%% complete', k);
end
close(d);

% context menu
cm = uicontextmenu(f);
m1 = uimenu(cm, 'Text', 'Reset', 'MenuSelectedFcn', @reset);
ax.UIContextMenu = cm;
13

图像处理工具箱

读取、写入和显示图像

imread 支持 PNG、JPEG、TIFF、BMP 和许多科学格式。图像数据类型很重要:uint8(0-255)常用于文件,double(0-1)用于处理。始终使用 im2double/im2uint8(会重新缩放)而非 double()/uint8(会截断)。im2gray(R2020b+)替代 rgb2gray。imwrite 支持特定格式的选项,如 JPEG 质量。imfinfo 读取元数据而不加载像素数据。

matlab
% read and display an image
img = imread('peppers.png');
imshow(img);
title('RGB image');

% image types
% uint8 (0-255), uint16, double (0-1), logical (binary)
whos img
class(img)              % uint8
size(img)               % rows x cols x channels

% convert between types
d = im2double(img);     % scale to [0,1]
u = im2uint8(d);        % scale to [0,255]
g = im2gray(img);       % RGB to grayscale (R2020b+, replaces rgb2gray)

% write to file
imwrite(g, 'gray.png');
imwrite(g, 'gray.jpg', 'Quality', 90);

% info without loading
info = imfinfo('peppers.png');
disp(info.Width);

% montage of multiple images
fileList = dir('*.png');
montage({fileList.name});

滤波与增强

imgaussfilt 是现代高斯模糊(替代 fspecial('gaussian') + imfilter)。medfilt2 去除椒盐噪声而不模糊边缘。fspecial 创建预定义核(sobel、prewitt、laplacian、gaussian)。imsharpen 通过非锐化掩蔽增强边缘。histeq 执行全局直方图均衡化;adapthisteq(CLAHE)局部执行,在非均匀图像中对比度更好。imadjust 映射强度范围以进行亮度/对比度校正。

matlab
img = im2double(imread('cameraman.tif'));

% Gaussian blur
h = imgaussfilt(img, 2);   % sigma = 2
h2 = imgaussfilt(img, [3 3], 1.5);

% median filter (salt-and-pepper noise)
noisy = imnoise(img, 'salt & pepper', 0.05);
m = medfilt2(noisy, [3 3]);

% custom 2D filter
kernel = fspecial('sobel');
edge_img = imfilter(img, kernel);

% unsharp masking (sharpen)
sharp = imsharpen(img, 'Amount', 0.8, 'Radius', 1.5);

% histogram equalization
eq = histeq(img);          % global
eq2 = adapthisteq(img);    % CLAHE (local)

% image arithmetic
bright = imadd(img, 0.1);
contrast = imadjust(img, [0.3 0.7], []);

形态学运算与分割

形态学运算(腐蚀、膨胀、开、闭)使用结构元素(strel)处理二值图像。开运算去除小物体;闭运算填充小孔。bwconncomp 查找连通区域;regionprops 为每个区域提取测量值(面积、质心、边界框)。watershed 分割接触的物体。edge 检测边界(Canny 最鲁棒)。graythresh 计算 Otsu 的全局阈值;multithresh 进行多级阈值。这些工具构成计算机视觉预处理的核心。

matlab
bw = imread('text.png');
bw = imbinarize(bw);

% morphological operations
se = strel('disk', 3);
er = imerode(bw, se);       % shrink objects
di = imdilate(bw, se);      % grow objects
op = imopen(bw, se);        % erode then dilate (removes small noise)
cl = imclose(bw, se);       % dilate then erode (fills small holes)

% connected components
cc = bwconncomp(bw);
stats = regionprops(cc, 'Area', 'Centroid', 'BoundingBox');
[areas, idx] = sort([stats.Area], 'descend');

% watershed segmentation
grad = imgradient(bw);
D = -bwdist(~bw);
L = watershed(D);

% edge detection
edges = edge(bw, 'canny');
edges2 = edge(bw, 'sobel');

% thresholding
T = graythresh(img);        % Otsu's method
bw2 = imbinarize(img, T);

特征检测与变换

特征检测为匹配和跟踪找到独特的点。Harris 角点快速但非尺度不变;SURF 和 ORB 是尺度/旋转不变的,可在不同视图间稳健匹配。extractFeatures 在检测到的点处计算描述符。霍夫变换通过在参数空间中投票检测直线(和圆)——对文档倾斜校正和车道检测很有用。imregtform 执行基于强度的图像配准,计算对齐两幅图像的几何变换。

matlab
img = imread('cameraman.tif');

% corner detection (Harris)
corners = detectHarrisFeatures(img);
[~, strength] = corners;
imshow(img); hold on; plot(corners);

% SURF features (scale-invariant)
points = detectSURFFeatures(img);
[f1, vpts1] = extractFeatures(img, points);

% ORB features (faster, binary)
points = detectORBFeatures(img);

% Hough transform for line detection
bw = edge(img, 'canny');
[H, T, R] = hough(bw);
P = houghpeaks(H, 5);
lines = houghlines(bw, T, R, P);

% image registration
% (find transform between two images)
moving = imread('rotated.png');
fixed = img;
[optimizer, metric] = imregconfig('monomodal');
tform = imregtform(moving, fixed, 'affine', optimizer, metric);
registered = imwarp(moving, tform);

批处理与大图像

对于批处理,parfor 跨图像并行化。blockproc 以分块方式处理大图像——当完整图像不适合内存时至关重要;'Destination' 选项将输出流式传输到磁盘。imageDatastore 管理太大而无法手动枚举的集合,并与 tall 数组和 MapReduce 框架集成用于核外计算。bigTIFF 支持处理千兆像素显微和遥感图像。

matlab
% process many images in a folder
fileList = dir('*.tif');
parfor k = 1:numel(fileList)
    img = imread(fileList(k).name);
    result = processImage(img);
    imwrite(result, ['out_' fileList(k).name]);
end

% block processing for large images
fun = @(block) std2(block);
B = blockproc('large.tif', [256 256], fun);
B = blockproc('large.tif', [256 256], fun, 'Destination', 'out.tif');

% work with very tall/wide images without loading all
% (bigTIFF, multiresolution)
t = Tiff('big.tif', 'r');
imgInfo = t.getImageInfo;

% image datastore for huge collections
imds = imageDatastore('images/', 'IncludeSubfolders', true);
imds.ReadSize = 10;  % read 10 at a time
while hasdata(imds)
    [imgs, info] = read(imds);
    % process batch
end

% tall arrays (out-of-core) for pixel statistics
t = tall(imds);
14

优化工具箱

无约束与有约束优化

fminunc 求解平滑无约束问题;fmincon 处理边界、线性和非线性约束。linprog 和 quadprog 专门用于带线性约束的线性和二次目标——比通用求解器快得多。optimoptions 配置求解器行为(算法、容差、显示)。'interior-point' 算法对大问题很鲁棒;'sqp' 适用于非线性约束。当有解析梯度时始终提供,以提高速度和准确性。

matlab
% unconstrained minimization
f = @(x) (x(1)-2)^2 + (x(2)-3)^2;
x0 = [0 0];
[x, fval] = fminunc(f, x0);

% constrained (with fmincon)
A = []; b = []; Aeq = []; beq = [];
lb = [0 0]; ub = [];
nonlcon = @(x) deal([], x(1) + x(2) - 4);  % x1+x2 <= 4
[x, fval] = fmincon(f, x0, A, b, Aeq, beq, lb, ub, nonlcon);

% linear programming
f_lp = [-1 -1];            % minimize -x1 - x2
A_lp = [1 1; -1 1]; b_lp = [4; 2];
[x, fval] = linprog(f_lp, A_lp, b_lp, [], [], [0;0]);

% quadratic programming
H = [1 -1; -1 2]; c = [-2; -6];
[x, fval] = quadprog(H, c, [], [], [], [], [0;0]);

% set optimization options
opts = optimoptions('fmincon', 'Algorithm','interior-point', ...
    'Display','iter', 'MaxIterations', 200);
[x, fval] = fmincon(f, x0, A, b, Aeq, beq, lb, ub, nonlcon, opts);

全局与多目标优化

局部求解器(fminunc、fmincon)可能陷入局部最小值。GlobalSearch 和 MultiStart 从许多起始点运行局部求解器。ga(遗传算法)、particleswarm 和 simulannealbnd 是无导数的全局方法——较慢但适用于不连续或噪声目标。gamultiobj 为多目标问题找到 Pareto 前沿,返回一组非支配解。根据问题平滑度、维度以及是否需要全局最优保证来选择。

matlab
% GlobalSearch / MultiStart for non-convex problems
f = @(x) x(1)^2 + x(2)^2 + 10*sin(x(1)) + 10*sin(x(2));
opts = optimoptions('fmincon', 'Algorithm','sqp');
problem = createOptimProblem('fmincon','objective',f, ...
    'x0',[0 0],'lb',[-5 -5],'ub',[5 5],'options',opts);
gs = GlobalSearch;
[x, fval] = run(gs, problem);

% genetic algorithm
[x, fval] = ga(f, 2, [], [], [], [], [-5 -5], [5 5]);

% particle swarm
[x, fval] = particleswarm(f, 2, [-5 -5], [5 5]);

% simulated annealing
[x, fval] = simulannealbnd(f, [0 0], [-5 -5], [5 5]);

% multiobjective (Pareto front)
f_multi = @(x) [x(1)^2 + x(2)^2, (x(1)-1)^2 + (x(2)-1)^2];
[x, fval] = gamultiobj(f_multi, 2, [], [], [], [], [-2 -2], [2 2]);
plot(fval(:,1), fval(:,2), 'o');

曲线拟合与参数估计

fittype 定义自定义参数模型;fit 执行回归,带有自动起始点启发式。lsqcurvefit 是较低级别的非线性最小二乘求解器——当你需要精细控制或自定义雅可比矩阵时很有用。confint 和 predint 返回置信区间和预测区间用于不确定性量化。Curve Fitter 应用程序(cftool)提供交互式界面来探索拟合。始终检查残差是否有系统结构,这表明模型设定错误。

matlab
% fit a custom model to data
x = linspace(0, 5, 50);
y = 2*exp(-0.5*x) + 0.1*randn(size(x));

% define model and fit
model = fittype('a*exp(-b*x)', 'independent', 'x', ...
    'coefficients', {'a','b'});
f = fit(x', y', model, 'StartPoint', [1 1]);
plot(f, x, y);

% predefined models
f2 = fit(x', y', 'exp2');     % two-term exponential
f3 = fit(x', y', 'poly2');    % quadratic polynomial

% nonlinear least squares with lsqcurvefit
fun = @(p, xdata) p(1)*exp(-p(2)*xdata);
[p, resnorm] = lsqcurvefit(fun, [1 1], x, y);

% confidence intervals
ci = confint(f, 0.95);
predint(f, x', 0.95, 'observation', 'functional');

% smoothing spline
sf = fit(x', y', 'smoothingspline');

整数与组合优化

intlinprog 求解混合整数线性规划——调度、路由和分配问题的主力。matchpairs 在 O(n^3) 中最优求解分配问题。旅行商问题需要迭代子巡回消除,因为约束集是指数级的。surrogateopt 适用于昂贵的黑盒函数(例如,每次评估需要几分钟的仿真)——它构建代理模型并智能采样。对于精确方法无法处理的组合问题,考虑 ga 或自定义启发式。

matlab
% mixed-integer linear programming (TSP-like problems)
f = [-3 -2];             % maximize 3x + 2y
A = [1 1; 2 1]; b = [4; 6];
intcon = 1:2;            % both variables integer
[x, fval] = intlinprog(f, intcon, A, b, [], [], [0;0]);

% assignment problem (Hungarian algorithm)
cost = [4 1 3; 2 3 4; 3 4 1];
[assignment, cost_total] = matchpairs(cost, false);

% traveling salesman via intlinprog
n = 8;  % cities
distances = rand(n, n); distances = distances + distances';
% (build subtour elimination constraints iteratively)

% knapsack
weights = [2 3 4 5]; values = [3 4 5 6];
W = 5;
f = -values;
A = weights; b = W;
intcon = 1:4;
[x, fval] = intlinprog(f, intcon, A, b, [], [], zeros(4,1), ones(4,1));

% surrogate optimization (expensive black-box)
obj = @(x) expensive_eval(x);
[x, fval] = surrogateopt(obj, lb, ub);

优化工作流程与最佳实践

选择正确的求解器是最重要的决定——对线性规划使用 fmincon 会浪费数量级的性能。提供解析梯度(通过基于问题的框架或 optimoptions)可显著提高速度和可靠性。将变量缩放到 1 量级可改善条件数。检查 exitflag 和 firstorderopt 以验证收敛。基于问题的框架(optimproblem、optimvar)更易读,让 MATLAB 自动选择求解器——新代码首选。

matlab
% 1. choose solver based on problem type
%    smooth? -> fminunc/fmincon
%    linear? -> linprog/intlinprog
%    integer? -> intlinprog
%    nonsmooth/global? -> ga/particleswarm/GlobalSearch

% 2. provide gradients and Jacobians when possible
f = @(x) x(1)^2 + x(2)^2;
gradf = @(x) [2*x(1); 2*x(2)];
prob = optimproblem('Objective', f);
prob.Objective.Gradient = gradf;

% 3. scale variables to ~[1, 1]
x_scaled = (x - x0) / scale;

% 4. check optimality and feasibility
output.exitflag       % 1 = converged
output.firstorderopt  % should be near 0

% 5. warm start sequential problems
opts = optimoptions('quadprog','ObjectiveLimit',1e-8);
x_new = quadprog(H, c, A, b, [], [], lb, ub, x_old, opts);

% 6. use problem-based framework (cleaner)
x = optimvar('x', 2, 'LowerBound', 0);
prob = optimproblem('Objective', x(1)^2 + x(2)^2);
prob.Constraints.c1 = x(1) + x(2) >= 1;
sol = solve(prob);
15

并行计算

parfor 循环与并行池

parfor 是最简单的并行化路径——它将循环迭代分配给工作进程。迭代必须独立(没有迭代 k 依赖于 k-1)。变量分类为:循环变量(k)、切片变量(仅由 k 在第一/最后维度索引)、广播变量(只读)和归约变量(用 + 或 * 等关联运算组合)。通信开销意味着只有当每次迭代做大量工作时 parfor 才有帮助。启动池一次;在 parfor 循环之间重用以避免启动成本。

matlab
% start a parallel pool (workers = CPU cores)
pool = gcp('nocreate');
if isempty(pool)
    parpool;  % start default pool
end

% parfor: parallel for loop
n = 1e6;
results = zeros(1, n);
parfor k = 1:n
    results(k) = expensive_computation(k);
end

% restrictions:
% - iterations must be independent (no data dependencies)
% - variables classified as loop, sliced, broadcast, reduction
% - cannot break/continue

% reduction variables (combine results)
total = 0;
parfor k = 1:n
    total = total + compute(k);
end

% sliced variables (each iteration writes distinct element)
out = zeros(n, 1);
parfor k = 1:n
    out(k) = k^2;
end

% control pool size
delete(gcp('nocreate'));  % shut down
parpool('local', 4);      % 4 workers

spmd 与分布式数组

spmd 在所有工作进程上运行相同代码,用 labidx 标识每个进程——适用于每个工作进程处理一块的数据并行算法。Composite 变量(A{1}、A{2})保存每个工作进程的结果。distributed 数组将单个逻辑数组分散到工作进程上;localpart 给出本地块。labSendrecv 和 gcat/gplus 实现工作进程间通信。当 parfor 无法表达时(例如,需要通信的迭代算法),使用 spmd 进行细粒度并行化。

matlab
% spmd: single program, multiple data
spmd
    labidx              % worker index (1 to n)
    numlabs             % total workers
    A = rand(1000) * labidx;
    % each lab has its own A
end

% access Composite (per-worker data)
A{1}                    % A from worker 1
A{2}                    % A from worker 2

% distributed arrays (spread across workers)
D = distributed.rand(10000);
size(D)                 % 10000x10000 total
L = localpart(D);       % this worker's chunk

% communicate between labs
spmd
    data = rand(100, 1);
    % send to next lab, receive from previous
    next_lab = mod(labidx, numlabs) + 1;
    prev_lab = mod(labidx - 2, numlabs) + 1;
    rcvd = labSendrecv(data, next_lab, prev_lab);
end

% gather distributed to local
D = distributed.rand(1000);
full_matrix = gather(D);

GPU 计算

gpuArray 将数据传输到 GPU;后续操作在那里执行并保留在 GPU 上,直到 gather() 将结果带回。大多数逐元素和线性代数函数都支持 GPU。arrayfun 在 GPU 上运行自定义逐元素函数(但仅限标量运算)。对于多 GPU 系统,通过 gpuDevice(k) 为每个 parfor 工作进程分配不同的 GPU。GPU 计算在大型密集线性代数和逐元素运算方面表现出色;数据传输的开销使其对小数组效率低下。

matlab
% move data to GPU
A = gpuArray(rand(10000));
B = gpuArray(eye(10000));

% operations execute on GPU
C = A * B;              % GPU matrix multiply
D = A + B;
E = sum(A, 1);

% gather results back to CPU
C_cpu = gather(C);

% many built-in functions are GPU-enabled
x = gpuArray.linspace(-10, 10, 1e6);
y = sin(x) .* exp(-x.^2);

% arrayfun on GPU (custom element-wise functions)
f = @(a, b) a.^2 + b.^2;
result = arrayfun(f, A, B);

% check GPU
gpuDevice            % info about current GPU
gpuDeviceCount       % number of available GPUs

% page multiple GPUs
parfor k = 1:4
    gpuDevice(k);
    A = gpuArray(rand(5000));
    % ... compute on GPU k
end

batch 与作业调度

batch 在后台异步运行函数——适用于不想阻塞会话的长时间计算。带 'Pool' 选项的 batch 运行本身使用 parfor 的函数。较低级别的作业/任务 API 提供对调度的精细控制。parcluster 选择集群配置文件;MATLAB 通过并行计算工具箱的通用调度器接口与 SLURM、PBS 和 LSF 集成。对于 HPC,将数据保存到文件并提交脚本,而不是依赖共享内存。

matlab
% run a function in background
job = batch(@my_function, 0, {arg1, arg2});

% check status
job.State              % 'queued', 'running', 'finished'
wait(job);             % block until done
load(job);             % retrieve results

% batch with parfor inside
job = batch(@my_parfor_func, 1, {input_data}, 'Pool', 4);

% job and task objects (lower-level)
job = createJob(pool);
task = createTask(job, @my_func, 1, {arg1});
submit(job);
wait(job);
result = fetchOutputs(task);

% cluster types
% 'local' - on this machine
% 'MJS' - MATLAB Job Scheduler (server cluster)
% 'SLURM'/'PBS' - HPC scheduler integration
c = parcluster('local');
c.NumWorkers = 8;
c.saveProfile;

性能与并行代码分析

使用 profile on -parallel 分析并行代码以查看每个工作进程的时间线。加速受阿姆达尔定律限制:如果 10% 的代码是串行的,无论工作进程数量如何,最大加速为 10 倍。常见陷阱:迭代太小(开销超过工作)、大型广播变量(传输成本)和过多的归约运算。parallel.pool.DataQueue 实现从工作进程实时进度更新而不阻塞——对监控长时间并行作业很有用。始终在前后测量以验证并行化确实有帮助。

matlab
% profile parallel code
profile on -parallel
parfor k = 1:100
    compute(k);
end
profile off
profview                % visualize

% measure speedup
tic;
serial_result = serial_compute();
t_serial = toc;

tic;
parfor_result = parallel_compute();
t_parallel = toc;

speedup = t_serial / t_parallel;
fprintf('Speedup: %.2fx using %d workers
', speedup, pool.NumWorkers);

% avoid common pitfalls:
% 1. too little work per iteration (overhead dominates)
% 2. large broadcast variables (transfer cost)
% 3. false sharing via reduction variables

% data queue for live updates from workers
Q = parallel.pool.DataQueue;
afterEach(Q, @update_plot);
parfor k = 1:n
    % ... compute ...
    send(Q, partial_result);
end
16

面向对象编程

类与属性

MATLAB 类位于名为 ClassName.m 的文件中。classdef 块包含属性和方法。属性特性控制访问:SetAccess=protected 表示只有类方法可以写入;Constant 定义类级常量。构造函数是与类同名的方法。MATLAB 默认使用值语义(对象在赋值时被复制)——使用 handle 类获得引用语义。像 disp 这样的重载方法自定义默认行为。

matlab
% class definition in a file named Point.m
classdef Point
    properties
        x = 0       % public, with default
        y = 0
    end
    properties (SetAccess = protected)
        id          % settable only by class methods
    end
    properties (Constant)
        PI = 3.14159
    end

    methods
        function obj = Point(x, y)
            if nargin > 0
                obj.x = x;
                obj.y = y;
            end
            obj.id = randi(1e6);
        end

        function r = distance(obj)
            r = sqrt(obj.x^2 + obj.y^2);
        end

        function disp(obj)
            fprintf('Point(%.2f, %.2f) [id=%d]
', ...
                obj.x, obj.y, obj.id);
        end
    end
end

% usage
p = Point(3, 4);
p.distance()           % 5
disp(p)

Handle 类与 Value 类

value 类和 handle 类之间的选择是根本性的。Value 类(默认)在赋值和方法调用时复制——对不可变数据更安全。Handle 类(handle 的子类)是引用:赋值和副本指向同一个对象,类似 Java/Python 对象。GUI 组件、文件句柄和跨调用者共享的可变状态需要 handle 类。对于不可变性是理想的数学对象(向量、矩阵),使用 value 类。

matlab
% value class (default): copies on assignment
classdef Vec
    properties
        data
    end
    methods
        function obj = Vec(d)
            obj.data = d;
        end
    end
end

v1 = Vec([1 2 3]);
v2 = v1;             % COPY
v2.data = [4 5 6];
disp(v1.data)        % still [1 2 3]

% handle class: references shared
classdef HVec < handle
    properties
        data
    end
    methods
        function obj = HVec(d)
            obj.data = d;
        end
    end
end

h1 = HVec([1 2 3]);
h2 = h1;             % REFERENCE (same object)
h2.data = [4 5 6];
disp(h1.data)        % [4 5 6] - changed!

% handle classes support delete method
% isequal(h1, h2) -> true (same object)

继承与多态

继承在 classdef 行使用 <;obj@SuperClass(args) 调用超类构造函数。MATLAB 支持多重继承但很少见,可能导致菱形问题。抽象方法(在 methods (Abstract) 中声明)必须由子类实现;基类不能被实例化。多态自然工作:在任何对象上调用方法,MATLAB 分派到正确的实现。使用 isa(obj, 'ClassName') 和 isprop/ismethod 进行运行时类型检查。

matlab
% single inheritance
classdef Dog < Animal
    methods
        function obj = Dog(name)
            obj@Animal(name);  % call superclass constructor
        end
        function sound(obj)
            disp([obj.name ' says Woof']);
        end
    end
end

% multiple inheritance
classdef FlyingFish < Fish & Bird
    methods
        function obj = FlyingFish(name)
            obj@Fish(name);
            obj@Bird(name);
        end
    end
end

% abstract methods and classes
classdef Shape
    methods (Abstract)
        area(obj)
        perimeter(obj)
    end
end

classdef Circle < Shape
    properties
        radius
    end
    methods
        function obj = Circle(r)
            obj.radius = r;
        end
        function a = area(obj)
            a = pi * obj.radius^2;
        end
        function p = perimeter(obj)
            p = 2 * pi * obj.radius;
        end
    end
end

% polymorphism
shapes = {Circle(2), Square(3)};
for k = 1:numel(shapes)
    fprintf('Area: %.2f
', shapes{k}.area());
end

事件与监听器

事件模型实现观察者模式:类声明事件,监听器注册回调,notify 触发事件。这将生产者与消费者解耦——对 GUI、仿真和响应式系统至关重要。属性 set 方法(set.PropertyName)拦截赋值并可触发事件。监听器可以是临时的(addlistener,与对象生命周期绑定)或持久的(保存在变量中的 listener 对象)。完成后始终删除监听器以防止内存泄漏。

matlab
classdef TemperatureSensor < handle
    properties
        Temperature = 20
    end
    events
        TemperatureChanged
        Overheated
    end
    methods
        function set.Temperature(obj, t)
            obj.Temperature = t;
            notify(obj, 'TemperatureChanged');
            if t > 100
                notify(obj, 'Overheated');
            end
        end
        function obj = TemperatureSensor()
            % nothing
        end
    end
end

% create sensor and listen
s = TemperatureSensor();
addlistener(s, 'TemperatureChanged', @onTempChanged);
addlistener(s, 'Overheated', @onOverheat);

function onTempChanged(src, event)
    fprintf('Temp now: %.1f
', src.Temperature);
end

function onOverheat(src, event)
    warning('Overheated at %.1f!', src.Temperature);
end

% trigger
s.Temperature = 25;     % prints "Temp now: 25.0"
s.Temperature = 105;    % prints temp + warning

运算符重载与索引

运算符重载让用户类可以使用 +、*、[] 等。每个运算符映射到一个函数(plus、mtimes、minus、mrdivide、horzcat、vertcat)。subsref 和 subsasgn 自定义索引(obj(i)、obj.field、obj{i})。现代 MATLAB 优先使用点表示法访问属性,但 subsref/subsasgn 仍用于伪索引模式(例如,张量库中 T(1,2,3) 提取元素)。重载 disp 以获得可读输出,重载 end/numel 以获得自定义索引语义。

matlab
classdef Complex
    properties
        re
        im
    end
    methods
        function obj = Complex(re, im)
            obj.re = re; obj.im = im;
        end
        function r = plus(a, b)            % a + b
            r = Complex(a.re + b.re, a.im + b.im);
        end
        function r = mtimes(a, b)          % a * b
            r = Complex(a.re*b.re - a.im*b.im, ...
                        a.re*b.im + a.im*b.re);
        end
        function r = abs(obj)              % |obj|
            r = sqrt(obj.re^2 + obj.im^2);
        end
        function disp(obj)
            fprintf('%.2f %+.2fi
', obj.re, obj.im);
        end
    end
    methods
        function r = subsref(obj, S)       % obj(...)
            if strcmp(S(1).type, '()')
                r = obj.re + 1i*obj.im;
            end
        end
        function obj = subsasgn(obj, S, val)  % obj(...) = val
            % custom assignment
        end
    end
end

c1 = Complex(1, 2); c2 = Complex(3, 4);
c3 = c1 + c2;          % uses plus
c4 = c1 * c2;          % uses mtimes
abs(c1)                % uses abs
17

调试与性能调优

调试器与断点

dbstop 设置断点——最强大的调试工具。条件断点(dbstop ... if condition)仅在谓词为真时暂停,对于在大循环中查找错误至关重要。dbstop if error 将任何未捕获的异常转为调试暂停,让你在失败点检查工作区。catch 块中的 ME(MException)对象携带 .message、.identifier 和 .stack 用于丰富的错误处理。使用 dbstack 导航调用栈,dbup/dbdown 检查调用者工作区。

matlab
% set breakpoints in the Editor or programmatically
dbstop in my_function at 42      % line 42 of my_function.m
dbstop in my_function at 42 if x > 10  % conditional
dbstop if error                  % pause on any error
dbstop if naninf                 % pause on NaN/Inf
dbstop if warning                % pause on warnings
dbclear all                      % clear all breakpoints
dbclear in my_function           % clear in one file

% at a breakpoint, the command window enters debug mode K>>
whos                             % inspect workspace
x                                % view variables
dbstep                           % step to next line
dbstep in                        % step into function
dbstep out                       % step out of function
dbcont                           % continue execution
dbstack                          % show call stack
dbup / dbdown                    % move up/down stack frames
dbquit                           % exit debug mode

% error recovery
try
    risky_operation();
catch ME
    fprintf('Error: %s
', ME.message);
    fprintf('Stack:
');
    for k = 1:numel(ME.stack)
        fprintf('  %s (line %d)
', ME.stack(k).name, ME.stack(k).line);
    end
end

性能分析与热点检测

性能分析器(profile on/off + profile viewer)逐行显示时间花在哪里——最重要的优化工具。始终在优化前分析;对瓶颈的直觉通常是错的。timeit 比 tic/toc 更准确用于微基准测试,因为它多次运行函数并考虑开销。-memory 选项跟踪分配,对查找内存泄漏或过度复制很有用。将优化精力集中在排名前几的热点上以获得最大影响。

matlab
% profile a script or function
profile on
my_expensive_script();
profile off

% view results
profile viewer                 % GUI
p = profile('info');           % structure
profsave(p, 'profile_results'); % HTML report

% time individual operations
tic; A = rand(5000); A = A * A; toc;   % ~0.5s

% timeit for accurate single-function timing
f = @() sort(rand(1e6,1));
t = timeit(f);

% memory profiling
profile on -memory
% ... run code ...
profile viewer   % shows memory allocation

% identify bottlenecks
% 1. profile viewer shows time per function/line
% 2. focus on the top few hottest lines
% 3. vectorize, preallocate, or use MEX for those

向量化与预分配

MATLAB 中三个最大的性能提升:(1) 在循环中填充前预分配数组(zeros、NaN、cell),(2) 向量化运算以利用 BLAS/LAPACK,(3) 使用 JIT 友好的模式(简单循环现在很快,但增长数组仍然是 O(n^2))。逻辑索引用单个向量化赋值替换 if/else 循环。除非需要 GPU 支持,否则避免使用 arrayfun——普通的预分配循环通常更快。用 tic/toc 或 timeit 测量以验证改进。

matlab
% BAD: growing array in loop
tic;
s = [];
for k = 1:100000
    s = [s, k^2];     % reallocates every iteration!
end
toc;                  % ~10 seconds

% GOOD: preallocate
tic;
s = zeros(1, 100000);
for k = 1:100000
    s(k) = k^2;
end
toc;                  % ~0.01 seconds

% BEST: vectorize
tic;
s = (1:100000).^2;
toc;                  % ~0.001 seconds

% vectorize conditional logic
x = rand(10000, 1);
% BAD:
% for k = 1:numel(x)
%     if x(k) > 0.5, y(k) = 1; else, y(k) = 0; end
% end
% GOOD:
y = double(x > 0.5);

% vectorize with logical indexing
y = zeros(size(x));
y(x > 0.5) = 1;
y(x > 0.8) = 2;

% use arrayfun/gpuArray only when truly needed
% (loops with preallocation are often faster than arrayfun)

MEX 文件与 C 集成

MEX 文件让你从 MATLAB 调用 C/C++/Fortran——当关键循环无法向量化或包装现有库时至关重要。mex 将 C 文件编译成 .mexw64(Windows)或 .mexa64(Linux)二进制文件。现代 C++ MATLAB Data API(R2018a+)是类型安全的,比旧的 mxGetPr/mxCreate API 更干净。要从外部应用程序调用 MATLAB,使用 MATLAB Engine API 或 MATLAB Compiler SDK。loadlibrary 包装通用共享库而无需编译。先分析——只对实际瓶颈进行 MEX 化。

matlab
% call C/C++/Fortran code from MATLAB via MEX
% write a C file (my_func.c):
/*
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double *x = mxGetPr(prhs[0]);
    size_t n = mxGetNumberOfElements(prhs[0]);
    plhs[0] = mxCreateDoubleMatrix(n, 1, mxREAL);
    double *y = mxGetPr(plhs[0]);
    for (size_t k = 0; k < n; k++) y[k] = x[k] * x[k];
}
*/

% compile
mex my_func.c           % produces my_func.mexw64
% usage:
y = my_func([1 2 3]);   % [1 4 9]

% C++ with MATLAB Data API (modern, R2018a+)
% #include "mex.hpp", "mexAdapter.hpp"
% use matlab::data::TypedArray<double>

% call MATLAB from C/C++ application (MATLAB Engine API)
% #include "engine.h"
% eng = engOpen("");
% engPutVariable(eng, "x", x);
% engEvalString(eng, "y = sqrt(x)");

% loadlibrary for generic shared libraries
loadlibrary('mylib.dll', 'mylib.h');
calllib('mylib', 'my_function', arg);
unloadlibrary('mylib');

内存管理与大数据

内存通常是大型计算的瓶颈。使用 single 而非 double 可减半内存并使吞吐量翻倍。稀疏矩阵只存储非零元素。memmapfile 将二进制文件映射到内存而不加载它——非常适合顺序访问的超大数据集。tall 数组(带 datastore)以不适合 RAM 的分块处理数据,底层使用 MapReduce。自 R2018b 起,MATLAB 可以进行一些原地操作(A = A + 1)而无需复制,但显式 A(:) = ... 保证它。完成后始终清除大型变量。

matlab
% check memory usage
[usr, sys] = memory;
disp(usr.PhysicalMemory.Available);

% view variable sizes
whos                  % all variables with sizes
[x_size, x_bytes] = compute_size(x);

% clear large variables when done
clear big_array;

% use single precision when possible
A = rand(5000, 'single');   % half the memory of double
B = A * A;                   % single precision matmul

% sparse for mostly-zero matrices
S = sparse(1e5, 1e5);
S(1, 1) = 1;

% memory-mapped files for huge data
m = memmapfile('large.bin', 'Format', 'double', 'Offset', 0, ...
    'Repeat', 1e8);
m.Data(1)              % access without loading all

% tall arrays for out-of-core
ds = datastore('big.csv');
t = tall(ds);
mean_t = mean(t.Var1);
gather(mean_t);        % triggers computation

% avoid copies: in-place operations
A = A + 1;             % may modify A in place (since R2018b)
A(:) = A(:) + 1;       % definitely in place
18

高级绘图

子图与 tiledlayout

tiledlayout(R2019b+)是 subplot 的现代替代品——更好的间距、更容易的跨越,以及通过 title(..., 'tiledtitle') 的共享标题。nexttile([1 2]) 跨越多个分块。subplot(n, m, k) 仍适用于旧代码但灵活性较差。

matlab
% tiledlayout (R2019b+) replaces subplot
tiledlayout(2, 3, 'TileSpacing', 'compact', 'Padding', 'compact');

nexttile; plot(1:10);
nexttile; scatter(rand(1, 50), rand(1, 50));
nexttile; bar(rand(5, 3));
nexttile; imagesc(magic(10));
nexttile; histogram(randn(1000, 1), 30);
nexttile; pie([30 20 50]);

% span multiple tiles
nexttile(7, [1 2]); plot(sin(0:0.1:2*pi));

% shared title and labels
title('Dashboard Demo');
xlabel('X'); ylabel('Y');

% legacy subplot
subplot(2, 2, 1); plot(1:10);
subplot(2, 2, 2); plot(10:-1:1);

自定义坐标轴

大多数坐标轴属性可通过坐标轴句柄(gca)访问。xlim/ylim 设置范围;xticks/xticklabels 控制刻度位置和标签。像 \pi 这样的 TeX 标记渲染希腊字母。set(gca, ...) 是旧语法;ax.Property = value 是现代(R2014b+)等价物。

matlab
x = linspace(0, 2*pi, 100);
plot(x, sin(x));

% axis limits
xlim([0 2*pi]); ylim([-1.2 1.2]);

% ticks and labels
xticks(0:pi/2:2*pi);
xticklabels({'0', '\pi/2', '\pi', '3\pi/2', '2\pi'});

% grid and minor grid
grid on; grid minor on;

% axis appearance
box on;
ax = gca;
ax.FontSize = 12;
ax.FontName = 'Courier';
ax.LineWidth = 1.5;
ax.XColor = [0.5 0.5 0.5];
ax.YDir = 'reverse';

% log scale
semilogy(1:100, 2.^(1:100));
set(gca, 'YScale', 'log');

多图与图例

hold on 让你在同一坐标轴上叠加多个绘图——始终以 hold off 结束以避免意外。'Location', 'best' 选择最少重叠的角落。'Interpreter', 'latex' 选项启用完整的 LaTeX 数学。将特定线条句柄传递给 legend 以仅包含某些绘图。

matlab
x = linspace(0, 2*pi, 100);
y1 = sin(x); y2 = cos(x); y3 = sin(x) + cos(x);

% hold on for multiple lines
plot(x, y1, 'r-', 'LineWidth', 2); hold on;
plot(x, y2, 'b--', 'LineWidth', 2);
plot(x, y3, 'g:', 'LineWidth', 2); hold off;

% legend with location
legend('sin(x)', 'cos(x)', 'sin+cos', ...
       'Location', 'best', 'Orientation', 'horizontal');

% legend with TeX
legend('$\sin(x)$', '$\cos(x)$', 'Interpreter', 'latex');

% specify which lines to include
h1 = plot(x, y1); hold on;
h2 = plot(x, y2);
h3 = plot(x, y3);
legend([h1 h3], 'sin', 'sin+cos');

3D 绘图

surf 绘制彩色曲面;mesh 绘制线框。contour 和 contourf 显示 2D 投影;clabel 添加标签。plot3 绘制 3D 参数曲线。view(az, el) 设置相机角度(方位角、仰角,以度为单位)。shading interp 平滑颜色过渡。

matlab
[X, Y] = meshgrid(-2:0.1:2, -2:0.1:2);
Z = X .* exp(-X.^2 - Y.^2);

% surface plot
figure;
surf(X, Y, Z);
colorbar; shading interp;

% mesh plot (wireframe)
figure;
mesh(X, Y, Z);
hidden off;                      % show hidden lines

% contour
figure;
contour(X, Y, Z, 20); colorbar;
contourf(X, Y, Z, 20); colorbar; % filled
[c, h] = contour(X, Y, Z, 20); clabel(c, h);

% 3D parametric
t = 0:0.01:10;
plot3(sin(t), cos(t), t);
xlabel('x'); ylabel('y'); zlabel('z');
view(45, 30);                    % azimuth, elevation

动画与电影

动画在循环内更新绘图数据并调用 drawnow 刷新。对于流畅的视频,使用 VideoWriter(替代已弃用的 avifile)。getframe 将当前图形捕获为图像。打开视频前设置 FrameRate。完成后始终 close(v) 以刷新文件。

matlab
% animate a sine wave
figure;
h = plot(NaN, NaN);
xlim([0 2*pi]); ylim([-1 1]);

for k = 1:100
  x = linspace(0, 2*pi, k);
  set(h, 'XData', x, 'YData', sin(x));
  drawnow;
end

% capture frames and save as video
v = VideoWriter('animation.mp4', 'MPEG-4');
v.FrameRate = 30; open(v);

for k = 1:60
  plot(sin(0:0.1:k/10));
  frame = getframe(gcf);
  writeVideo(v, frame);
end
close(v);

% getframe for static snapshots
figure; plot(1:10);
frame = getframe;                % struct with cdata
19

矩阵运算深入

线性代数基础

始终使用 A\b(反斜杠)求解线性方程组——它根据矩阵分派到正确的分解(LU、Cholesky、QR)。inv(A)*b 更慢且数值上更差。eig 将特征向量作为 V 的列返回,特征值在 D 的对角线上。expm 是矩阵指数(不同于逐元素的 exp)。

matlab
A = [1 2; 3 4];
b = [5; 6];

% solve Ax = b
x = A \ b;                       % preferred (LU-based)
x = inv(A) * b;                  % avoid — slower, less stable

% factorizations
[L, U, P] = lu(A);               % PA = LU
[Q, R] = qr(A);                  % A = QR
[V, D] = eig(A);                 % A V = V D
[U, S, V] = svd(A);              % A = U S V'

% properties
det(A); trace(A); rank(A); cond(A);
null(A);                         % null space
orth(A);                         % orthonormal basis of range

% matrix functions
expm(A); logm(A); sqrtm(A);      % matrix (not element-wise)

逐元素与矩阵运算

点前缀(.*)表示逐元素;没有它,运算是矩阵运算。最常见的 MATLAB 错误:当 x 是行向量时使用 x*x——使用 x*x' 获得点积或 x.*x 获得逐元素平方。' 是共轭转置(翻转虚部的符号);.' 是普通转置。

matlab
A = [1 2; 3 4];
B = [5 6; 7 8];

% element-wise (use .)
A .* B                           % [5 12; 21 32]
A ./ B                           % element-wise divide
A .^ 2                           % [1 4; 9 16]
A .^ B                           % element-wise power

% matrix ops (no .)
A * B                            % matrix product
A / B                            % A * inv(B)
A \ B                            % inv(A) * B
A^2                              % A * A (matrix power)
A'                               % conjugate transpose
A.'                              % non-conjugate transpose

% common gotcha
x = [1 2 3];
x * x                            % ERROR: inner dims mismatch
x * x'                           % 14 (dot product)
x .* x                           % [1 4 9] (element-wise)

重塑与索引

MATLAB 按列优先存储矩阵,因此 4x4 矩阵中的 A(5) 是 A(1, 2)。逻辑索引(A(mask))强大且快速——无需循环即可提取或修改满足条件的元素。reshape 要求总元素数匹配。permute 将转置推广到 N 维数组。

matlab
A = magic(4);                  % 4x4 matrix

% linear indexing (column-major)
A(5)                             % A(1, 2)
A(:)                             % column vector of all elements
A(2:5)                           % elements 2-5

% submatrix
A(1:2, 2:4)                      % rows 1-2, cols 2-4
A(:, 3)                          % all rows, col 3
A(end, :)                        % last row
A(1:2:end, :)                    % odd rows (stride)

% logical indexing
mask = A > 10;
A(mask)                          % flat list of values > 10
A(A > 10) = 0;                   % threshold in-place

% reshape, permute, flip
B = reshape(A, 2, 8);
C = permute(A, [2 1]);           % transpose N-D
flip(A); flipud(A); fliplr(A);
repmat(A, 2, 3);                 % tile 2x3

稀疏矩阵

稀疏矩阵只存储非零元素——对于大部分为零的大型矩阵(例如,来自 PDE 离散化的矩阵)至关重要。运算在可能时保持稀疏性。反斜杠 S\b 使用稀疏直接求解器(UMFPACK)——对于大型稀疏系统,比 full()\b 快得多且更节省内存。spy 可视化稀疏模式。

matlab
% create sparse
S = sparse(1000, 1000);
S(1, 1) = 5;
S(500, 500) = 10;

% from triplets
i = [1 2 3 4];
j = [1 2 3 4];
v = [10 20 30 40];
S = sparse(i, j, v, 4, 4);

% sparse identity and diagonal
S = speye(1000);
S = spdiags(ones(1000, 1), 0, 1000, 1000);

% operations stay sparse
S = S + S';
S = S * S;
x = S \ b;                       % uses sparse solver

% convert
F = full(S);                     % sparse -> full
S = sparse(F);                   % full -> sparse
nnz(S)                           % count non-zeros
spy(S)                           % visualize sparsity

广播(隐式扩展)

自 R2016b 起,MATLAB 自动广播(类似 NumPy)——大小为 1 的维度扩展以匹配。在此之前,你需要 bsxfun。广播使代码更干净:M - mean(M, 2) 无需 repmat 即可对每行进行中心化。维度必须兼容(相等或其中一个为 1)。

matlab
% R2016b+ — automatic broadcasting
A = magic(3);                    % 3x3
b = [1 2 3];                     % 1x3

% older MATLAB: error (dims mismatch)
% modern MATLAB: b is broadcast across rows
C = A + b;                       % 3x3 result
C = A - b';
C = A .* b;

% common uses
x = (1:5)';                      % column
y = (1:5);                       % row
outer = x * y;                   % 5x5 outer product
grid = x + y;                    % 5x5 addition grid

% mean across rows
M = magic(5);
row_means = mean(M, 2);          % 5x1
centered = M - row_means;        % broadcast subtraction

% bsxfun (legacy, pre-R2016b)
C = bsxfun(@plus, A, b);         % same as A + b
20

元胞数组与结构体

元胞数组

元胞数组保存混合类型。使用 {} 访问内容(去掉元胞包装),使用 () 获取子元胞。cellfun 将函数应用于每个元胞——如果结果是异构的,传入 'UniformOutput', false。元胞数组是保存不同长度字符串的标准方式(在字符串数组出现之前)。

matlab
% heterogeneous container
C = {'hello', 42, [1 2 3], magic(3)};

% access
C{1}                             % 'hello' (contents)
C(1)                             % {1x1 cell} (cell)
C{4}(2, 2)                       % access inside

% build dynamically
C = {};
for k = 1:5
  C{k} = rand(k);
end

% multi-element
[a, b, c] = C{1:3};              % unpack
C{1:3}                           % comma-separated list

% cellfun
nums = {1, 2, 3, 4};
squared = cellfun(@(x) x^2, nums);
lengths = cellfun(@length, C);

% convert
cell([1 2 3])                    % {1, 2, 3}
cell2mat({1 2; 3 4})             % [1 2; 3 4]
mat2cell(magic(4), [2 2], [2 2]) % 2x2 cell of blocks

结构体数组

结构体分组任意类型的命名字段。结构体数组保存多条记录——{arr.field} 将一个字段跨所有元素收集到元胞中,[arr.field] 收集到常规数组(如果兼容)。嵌套字段使用点链。fieldnames 列出字段;rmfield 返回不带该字段的副本。

matlab
% scalar struct
s.name = 'Alice';
s.age = 30;
s.scores = [90 85 92];

% struct constructor
s = struct('name', 'Bob', 'age', 25, 'scores', {[80 70]});

% struct array
students(1).name = 'Alice';
students(1).age = 30;
students(2).name = 'Bob';
students(2).age = 25;

% access across array
names = {students.name};         % all names (cell)
ages = [students.age];           % all ages (vector)

% nested
s.course.code = 'CS101';
s.course.credits = 3;
s.course.instructor.name = 'Dr. Smith';

% field operations
fieldnames(s)                    % list fields
isfield(s, 'age')                % check field
rmfield(s, 'age')                % remove field
orderfields(s)                   % sort fields

表格(表格数据)

表格(R2013b+)是保存表格数据的现代方式——类似 pandas 中的 DataFrame。按名称(T.Age)或索引(T.(2))访问列。sortrows 按一列或多列排序。readtable/writetable 处理 CSV、Excel 等。summary 给出每列的统计信息。对于异构数据,优先使用表格而非原始矩阵。

matlab
% create table
Names = {'Alice'; 'Bob'; 'Carol'};
Age = [30; 25; 42];
Score = [90; 80; 95];
T = table(Names, Age, Score);

% access
T.Age                            % column as vector
T.(2)                            % column by index
T{1, 2}                          % row 1, col 2 (cell-style)
T(1:2, :)                        % first 2 rows

% add/remove columns
T.Grade = {'A'; 'B'; 'A'};
T.Grade = [];                    % remove column

% filtering
T(T.Age > 26, :)                 % rows where Age > 26
find(T.Age > 26);

% sorting
T = sortrows(T, 'Age');
T = sortrows(T, {'Age', 'Score'}, 'descend');

% summary
summary(T)
T.Properties.VariableNames

% read/write
T = readtable('data.csv');
writetable(T, 'out.csv')

时间表

时间表(R2016b+)是带行时间戳的表格。retime 重采样/聚合(例如,'hourly'、'daily' 或自定义 TimeStep)。synchronize 将多个时间表对齐到公共时间向量。lag/lead 移动列。比在矩阵中手动管理时间索引干净得多。

matlab
% create timetable with timestamps
Time = datetime(2024, 1, 1) + hours(0:23)';
Temp = 20 + 5 * randn(24, 1);
TT = timetable(Time, Temp);

% indexing by time
TT.timerange(datetime(2024,1,1,6,0,0), datetime(2024,1,1,12,0,0))
TT(datetime(2024,1,1,10,0,0), :) % row at specific time
TT('2024-01-01 10:00:00', :)

% resample / synchronize
TT_30min = retime(TT, 'regular', 'mean', 'TimeStep', minutes(30));
TT_hourly = retime(TT, 'hourly', 'mean');

% aggregate
TT_daily = retime(TT, 'daily', @mean);
TT_daily_max = retime(TT, 'daily', 'max');

% combine timetables
TT2 = synchronize(TT1, TT2, 'union');

% lagging
TT.PrevTemp = lag(TT.Temp, 1);

Map(字典)

containers.Map 是传统的哈希映射——适用于所有 MATLAB 版本但较慢且无类型。dictionary(R2022b+)是现代替代品:有类型、更快,并支持向量化查找。当你需要 O(1) 键查找而不是搜索结构体数组或元胞时使用 map。

matlab
% containers.Map (pre-R2022b)
m = containers.Map;
m('apple') = 1;
m('banana') = 2;
m('cherry') = 3;

% access
m('apple')                       % 1
m.Keys                           % {'apple', 'banana', 'cherry'}
m.Values                         % [1, 2, 3]
isKey(m, 'apple')                % true
remove(m, 'banana');

% iterate
keys = m.keys;
for k = 1:length(keys)
  fprintf('%s -> %d\n', keys{k}, m(keys{k}));
end

% R2022b+ dictionary (faster, typed)
d = dictionary({'apple', 'banana'}, [1, 2]);
d('cherry') = 3;
d('apple')                        % 1
keys(d); values(d)
21

优化

fmincon 约束优化

fmincon 是约束非线性最小化的主力。nonlcon 函数必须返回 [c, ceq],其中 c <= 0(不等式)和 ceq = 0(等式)。deal 是从匿名函数返回多个输出的干净方式。根据问题类型设置 Algorithm:'interior-point'(通用)、'sqp'(小/中问题,通常更快)。

matlab
% minimize objective with constraints
% min f(x) s.t. A*x <= b, Aeq*x = beq, lb <= x <= ub, c(x) <= 0, ceq(x) = 0

fun = @(x) (x(1) - 2)^2 + (x(2) - 3)^2;

% linear inequality: x1 + x2 <= 4
A = [1 1]; b = 4;
% linear equality: x1 - x2 = 0
Aeq = [1 -1]; beq = 0;
% bounds
lb = [0 0]; ub = [5 5];
% nonlinear: x1^2 + x2^2 >= 1 (so -(x1^2 + x2^2 - 1) <= 0)
nonlcon = @(x) deal(-(x(1)^2 + x(2)^2 - 1), []);

x0 = [1 1];
[x, fval, exitflag, output] = fmincon(fun, x0, A, b, Aeq, beq, lb, ub, nonlcon);

% options
opts = optimoptions('fmincon', 'Display', 'iter', ...
                    'Algorithm', 'interior-point');
[x, fval] = fmincon(fun, x0, A, b, Aeq, beq, lb, ub, nonlcon, opts);

fminunc 无约束优化

fminunc 最小化无约束非线性函数。提供梯度(通过 SpecifyObjectiveGradient)可显著提高速度和准确性。默认的 BFGS Hessian 近似适用于平滑问题;对于大问题,'lbfgs' 限制内存。检查 exitflag(>0 = 收敛)和 firstorderopt(应该很小)。

matlab
% unconstrained minimization
fun = @(x) 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2;  % Rosenbrock

x0 = [-1.2 1];
[x, fval, flag, out] = fminunc(fun, x0);

% with gradient (faster, more accurate)
syms x1 x2
f = 100*(x2 - x1^2)^2 + (1 - x1)^2;
grad = gradient(f, [x1, x2]);
fun_grad = matlabFunction(f, grad, 'Vars', {x1, x2});

opts = optimoptions('fminunc', 'SpecifyObjectiveGradient', true, ...
                    'Display', 'iter');
[x, fval] = fminunc(@(x) fun_grad(x(1), x(2)), x0, opts);

% check optimality
disp(out.firstorderopt)           % should be near 0

% Hessian option
opts.Hessian = 'bfgs';            % quasi-Newton (default)
opts.Hessian = 'lbfgs';           % for large sparse problems

linprog 线性规划

linprog 求解线性规划。对于整数/二进制变量,使用 intlinprog(替代已弃用的 bintprog)。intcon 列出哪些变量受整数约束。设置 lb=0、ub=1 用于二进制。对偶单纯形算法是默认值,对大多数问题最快。

matlab
% min f'*x s.t. A*x <= b, Aeq*x = beq, lb <= x <= ub

% example: min -x1 - 2*x2
%   s.t.  x1 + x2 <= 4
%          x1 + 3*x2 <= 6
%          x1, x2 >= 0
f = [-1; -2];
A = [1 1; 1 3];
b = [4; 6];
lb = [0; 0];

opts = optimoptions('linprog', 'Display', 'iter');
[x, fval, exitflag, output] = linprog(f, A, b, [], [], lb, [], opts);

% integer programming (intlinprog)
intcon = 1:2;                     % variables 1 and 2 are integers
[x, fval] = intlinprog(f, intcon, A, b, [], [], lb, []);

% binary variables: set lb=0, ub=1, and add to intcon
lb = [0; 0]; ub = [1; 1];
[x, fval] = intlinprog(f, intcon, A, b, [], [], lb, ub);

lsqcurvefit 与曲线拟合

lsqcurvefit 通过最小二乘法将参数模型拟合到数据。polyfit 是多项式的简单选择。对于 R²(决定系数),手动计算:1 - SSE/SST。Levenberg-Marquardt 算法适用于无约束问题;trust-region-reflective 处理边界。

matlab
% fit y = a*exp(b*x) to data
xdata = linspace(0, 5, 50)';
ydata = 2.5 * exp(-0.7 * xdata) + 0.05 * randn(50, 1);

model = @(p, x) p(1) * exp(p(2) * x);

x0 = [1, -1];
[params, resnorm, residual, exitflag] = lsqcurvefit(model, x0, xdata, ydata);

% with bounds
lb = [0, -5]; ub = [10, 0];
[params, resnorm] = lsqcurvefit(model, x0, xdata, ydata, lb, ub);

% polyfit for polynomials
p = polyfit(xdata, ydata, 3);     % cubic
yfit = polyval(p, xdata);

% fit with custom output
opts = optimoptions('lsqcurvefit', 'Display', 'off', ...
                    'Algorithm', 'levenberg-marquardt');
[params, resnorm] = lsqcurvefit(model, x0, xdata, ydata, [], [], opts);

% goodness of fit
sse = sum((ydata - model(params, xdata)).^2);
sst = sum((ydata - mean(ydata)).^2);
r2 = 1 - sse / sst;

全局优化

全局优化工具(在全局优化工具箱中)帮助处理局部求解器陷入困境的非凸问题。MultiStart 从许多随机起始点运行局部求解器。GlobalSearch 更智能——它过滤有前途的起始点。ga(遗传算法)和 simulannealbnd 是无导数的。patternsearch 适用于非平滑问题。

matlab
% MultiStart: run local solver from many points
fun = @(x) x(1)^2 + x(2)^2 + 10*sin(x(1)) + 10*sin(x(2));
ms = MultiStart('Display', 'iter');
opts = optimoptions('fmincon', 'Algorithm', 'interior-point');
problem = createOptimProblem('fmincon', 'objective', fun, ...
                            'x0', [0 0], 'lb', [-5 -5], 'ub', [5 5]);
[x, fval] = run(ms, problem, 50);  % 50 starting points

% GlobalSearch: smarter, fewer starts
gs = GlobalSearch;
[x, fval] = run(gs, problem);

% ga (genetic algorithm)
[x, fval] = ga(fun, 2, [], [], [], [], [-5 -5], [5 5]);

% simulannealbnd (simulated annealing)
[x, fval] = simulannealbnd(fun, [0 0], [-5 -5], [5 5]);

% patternsearch
[x, fval] = patternsearch(fun, [0 0]);
22

图像处理

读取和显示图像

imread 对大多数图像格式返回 uint8 数组。rgb2gray 将 RGB 转换为灰度。im2double 缩放到 [0, 1]——在浮点处理前使用它(而非 double())。imshow 自动缩放 double 图像:[0, 1] 是预期范围。imwrite 支持质量/压缩选项。

matlab
% read and display
img = imread('photo.jpg');
imshow(img);

% info
size(img)                         % rows x cols x channels
class(img)                        % usually uint8
imfinfo('photo.jpg')              % metadata

% convert types
gray = rgb2gray(img);             % RGB -> gray
img_double = im2double(img);      % uint8 [0,255] -> double [0,1]
img_uint8 = im2uint8(img_double);

% write
imwrite(gray, 'gray.png');
imwrite(img, 'compressed.jpg', 'Quality', 80);

% display multiple
figure;
subplot(1, 2, 1); imshow(img); title('Original');
subplot(1, 2, 2); imshow(gray); title('Grayscale');

% pixel info
impixelinfo;                      % interactive pixel values
img(100, 200, :)                  % pixel at (row, col)

滤波与卷积

imgaussfilt 是现代高斯模糊(替代 fspecial('gaussian') + imfilter)。medfilt2 是椒盐噪声的正确选择(均值滤波器只会使其模糊)。fspecial 创建常见核(sobel、prewitt、laplacian、gaussian、disk、motion)。imfilter 默认执行相关——传入 'conv' 进行真正的卷积。

matlab
img = imread('cameraman.tif');
img = im2double(img);

% Gaussian blur
blurred = imgaussfilt(img, 2);    % sigma = 2
blurred = imgaussfilt(img, 2, 'FilterSize', 7);

% median filter (great for salt-and-pepper noise)
noisy = imnoise(img, 'salt & pepper', 0.05);
denoised = medfilt2(noisy, [3 3]);

% custom kernel
h = fspecial('sobel');            % edge detection
edges = imfilter(img, h);
h = fspecial('laplacian', 0);
sharpened = img - imfilter(img, h);

% 2D convolution vs correlation
out_conv = imfilter(img, h, 'conv');
out_corr = imfilter(img, h, 'corr');  % default

% unsharp masking
sharp = imsharpen(img, 'Amount', 1.5, 'Radius', 2);

形态学运算

形态学运算作用于二值图像。腐蚀缩小物体;膨胀使它们增长。开(先腐蚀后膨胀)去除小噪声;闭(先膨胀后腐蚀)填充小间隙。strel 创建结构元素——disk/square/line/octagon。bwareaopen 去除小物体;imfill 填充孔;bwperim 提取边界。

matlab
bw = imread('text.png');
bw = imbinarize(bw);              % grayscale -> binary

% basic ops
eroded = imerode(bw, strel('square', 3));
dilated = imdilate(bw, strel('disk', 2));
opened = imopen(bw, strel('square', 5));
closed = imclose(bw, strel('square', 5));

% structuring elements
se = strel('square', 3);
se = strel('disk', 5);
se = strel('line', 10, 45);       % length 10, angle 45 deg
se = strel('octagon', 3);

% remove small objects
clean = bwareaopen(bw, 50);       % remove <50 pixels

% skeleton
skel = bwmorph(bw, 'skel', Inf);

% fill holes
filled = imfill(bw, 'holes');

% boundary
boundary = bwperim(bw);

边缘检测与分割

使用 'canny' 的 edge 是最鲁棒的边缘检测器(指定 [low high] 阈值和 sigma)。带 'adaptive' 的 imbinarize 处理不均匀光照。bwconncomp 查找连通分量;regionprops 提取测量值(Area、Centroid、BoundingBox 等)。watershed 分离接触的物体——在梯度上计算以找到边界。

matlab
img = imread('coins.png');
img = im2double(img);

% edges
edges_sobel = edge(img, 'sobel');
edges_canny = edge(img, 'canny', [0.1 0.2], 1.5);
edges_prewitt = edge(img, 'prewitt');

% thresholding
bw = imbinarize(img);
bw_otsu = imbinarize(img, 'adaptive');  % local threshold

% connected components
cc = bwconncomp(bw);
stats = regionprops(cc, 'Area', 'Centroid', 'BoundingBox');
areas = [stats.Area];
[~, idx] = sort(areas, 'descend');
biggest = stats(idx(1));

% watershed segmentation
grad = imgradient(img);
L = watershed(grad);
L(L == 0) = NaN;
imshow(img); hold on; imshow(L, []);

颜色与变换

rgb2hsv、rgb2lab 转换颜色空间——HSV 对颜色选择很直观;L*a*b* 将亮度与颜色分离(适用于色差)。fft2 + fftshift 将频谱居中以进行滤波。imresize/imrotate/imcrop 是几何运算——'bilinear'(默认)通常最好;'nearest' 最快但有块状效果。

matlab
img = imread('peppers.png');

% color space conversion
hsv = rgb2hsv(img);
lab = rgb2lab(img);
gray = rgb2gray(img);
rgb = hsv2rgb(hsv);

% extract channels
R = img(:, :, 1);
G = img(:, :, 2);
B = img(:, :, 3);

% Fourier transform
f = fft2(double(gray));
f = fftshift(f);                  % center zero freq
mag = log(1 + abs(f));
imshow(mag, []);

% inverse
f_filtered = f;
f_filtered(abs(f) < 100) = 0;    % low-pass filter
filtered = real(ifft2(ifftshift(f_filtered)));
imshow(filtered, []);

% resize, rotate
small = imresize(img, 0.5);
rotated = imrotate(img, 45, 'bilinear', 'crop');
cropped = imcrop(img, [50 50 200 150]);  % [x y w h]
23

GUI/App Designer

App Designer 基础

App Designer(R2016a+)是现代 GUI 工具,替代 GUIDE。组件通过 app.<Name> 访问。回调接收 (app, event)。自定义属性(在代码视图中)在回调之间共享状态。保存为 .mlapp(二进制)或导出为 .m。通过在命令窗口中输入应用程序名称运行。

matlab
% Open App Designer:
%   >> appdesigner
% Drag components from the left, set properties on the right.

% Callback structure (auto-generated):
function ButtonPushed(app, event)
    x = linspace(0, 2*pi, 100);
    plot(app.UIAxes, x, sin(x));
    app.ResultEditField.Value = 'Plot done';
end

% Access components via app.<ComponentName>
%   app.UIAxes, app.Button, app.EditField, app.Slider, ...

% Property panel: add custom properties
properties (Access = private)
    data;                          % shared between callbacks
end

% Startup callback:
function startupFcn(app)
    app.data = rand(10);
    app.Slider.Value = 50;
end

% Save as .mlapp, run with:
%   >> myApp  (if named myApp.mlapp)
% Or export to a standalone .m file.

使用 uifigure 的编程式 UI

uifigure(R2016b+)是现代编程式 UI 框架——支持 figure 不支持的现代小部件(gauge、knob、switch、tree)。通过 *Fcn 属性使用匿名函数 @(src, event) ... 设置回调。uiwait 阻塞直到图形关闭;uiresume 释放它。

matlab
% modern uifigure (R2016b+) — preferred
fig = uifigure('Name', 'My App', 'Position', [100 100 600 400]);

ax = uiaxes(fig, 'Position', [200 100 350 250]);
plot(ax, 1:10);

btn = uibutton(fig, 'Text', 'Plot', 'Position', [50 100 100 30]);
btn.ButtonPushedFcn = @(~,~) plot(ax, rand(1, 10));

slider = uislider(fig, 'Position', [50 200 100 3]);
slider.ValueChangedFcn = @(s,~) disp(s.Value);

% dropdown
dd = uidropdown(fig, 'Items', {'a', 'b', 'c'}, 'Position', [50 250 100 30]);
dd.ValueChangedFcn = @(s,~) fprintf('Selected: %s\n', s.Value);

% list box
lb = uilistbox(fig, 'Items', {'one', 'two', 'three'}, ...
               'Multiselect', 'on', 'Position', [50 50 100 80]);

% wait for user to close
uiwait(fig);

常见 UI 组件

现代 UI 组件:uieditfield(文本或数值)、uibuttongroup(管理单选按钮)、uicheckbox、uitable(绑定到表格)、uitabgroup/uitab(选项卡)。所有组件都将父级作为第一个参数,并使用名称-值对设置属性。回调在用户交互时触发;通过 source 参数访问新值。

matlab
fig = uifigure;

% label
lbl = uilabel(fig, 'Text', 'Enter value:', 'Position', [20 200 100 22]);

% edit field
ef = uieditfield(fig, 'numeric', 'Value', 42, 'Position', [130 200 100 22]);
ef.ValueChangedFcn = @(s,~) fprintf('New: %g\n', s.Value);

% button group with radio buttons
bg = uibuttongroup(fig, 'Title', 'Mode', 'Position', [20 100 200 80]);
r1 = uiradiobutton(bg, 'Text', 'A', 'Position', [10 40 100 22]);
r2 = uiradiobutton(bg, 'Text', 'B', 'Position', [10 10 100 22]);
r1.Value = true;

% check box
cb = uicheckbox(fig, 'Text', 'Enable', 'Position', [20 50 100 22]);

% table
tdata = table({'A'; 'B'}, [1; 2], 'VariableNames', {'Name', 'Value'});
uit = uitable(fig, 'Data', tdata, 'Position', [250 50 200 150]);

% tab group
tg = uitabgroup(fig);
t1 = uitab(tg, 'Title', 'Tab 1');
t2 = uitab(tg, 'Title', 'Tab 2');
plot(uiaxes(t1), 1:10);

对话框与提示

inputdlg 收集文本输入;questdlg 用于是/否/取消;listdlg 用于选择;uigetfile/uiputfile 用于文件选择器;msgbox/errordlg/warndlg 用于通知。fullfile 可移植地连接路径(比字符串拼接好)。始终检查用户是否取消(空返回或 ok == false)。

matlab
% input dialog
answer = inputdlg({'Name:', 'Age:'}, 'User Info', [1 50; 1 10]);
if ~isempty(answer)
    name = answer{1};
    age = str2double(answer{2});
end

% question dialog
btn = questdlg('Save changes?', 'Confirm', 'Yes', 'No', 'Cancel', 'Yes');
switch btn
    case 'Yes', save_data();
    case 'No',  % discard
    case 'Cancel', return;
end

% list dialog
[sel, ok] = listdlg('PromptString', 'Select items:', ...
                    'ListString', {'Apple', 'Banana', 'Cherry'}, ...
                    'SelectionMode', 'multiple');

% file dialogs
[file, path] = uigetfile('*.csv', 'Select CSV');
[file, path] = uiputfile('*.mat', 'Save as');
fullpath = fullfile(path, file);

% message dialog
msgbox('Done!', 'Info', 'help');
errordlg('Something went wrong', 'Error');
warndlg('Check this', 'Warning');

共享与部署

用于共享:.mlapp 文件需要 MATLAB;独立应用程序(通过 MATLAB Compiler)无需 MATLAB 运行但需要免费的 MATLAB Runtime;Web 应用程序通过 MATLAB Web App Server 在浏览器中运行。导出为 .m 可获得可读的源代码。打包为工具箱通过附加组件分发。

matlab
% Run as standalone app
%   1. In App Designer: Designer Tab > App Store Details > Save as .mlapp
%   2. Share the .mlapp file — others open it in MATLAB

% Create standalone app (requires MATLAB Compiler)
%   >> mcr.build('myApp.mlapp')        % R2024a+
%   or
%   >> deploytool                       % legacy

% Web App (requires MATLAB Web App Server)
%   >> compiler.build.webApp('myApp.mlapp')

% Export to code (readable .m)
%   In App Designer: Designer Tab > Export > Export to .m file

% Pack as toolbox (for sharing with colleagues)
%   >> matlab.addons.toolbox.packageToolbox('myApp.prj)

% Tips:
%   - Use try/catch in callbacks to avoid silent failures
%   - Set app.UIFigure.Name to identify your app
%   - Test on a clean MATLAB session before deploying
24

高级文件输入输出

低级文件输入输出

fopen 失败时返回 -1——始终检查。fgetl 读取一行但不包括换行符;fgets 保留它。fscanf 读取格式化数据;fread 读取二进制。fseek/ftell 导航。完成后始终 fclose(使用 onCleanup 以确保安全:c = onCleanup(@() fclose(fid));)。

matlab
fid = fopen('data.txt', 'r');   % r, w, a, r+, w+
if fid == -1; error('Cannot open file'); end

% read line by line
while ~feof(fid)
  line = fgetl(fid);              % without newline
  fprintf('%s\n', line);
end

% formatted read
% data.txt: "Alice 30 90.5"
A = fscanf(fid, '%s %d %f', [3 1]);

% formatted write
fprintf(fid, '%s, %d, %.2f\n', 'Bob', 25, 85.3);

% binary I/O
data = fread(fid, [10 5], 'double');  % 10x5 doubles
fwrite(fid, data, 'double');

% position
fseek(fid, 0, 'bof');             % beginning
fseek(fid, 0, 'eof');             % end
pos = ftell(fid);

fclose(fid);                      % ALWAYS close

用于混合数据的 textscan

textscan 比 fscanf 更灵活——处理混合类型、自定义分隔符,并返回列的元胞数组。'TreatAsEmpty' 将占位符转换为 NaN。'CollectOutput' 将相同类型的列分组到一个数组中。fileread 将整个文件作为字符串读取——对于小文件或正则表达式处理很方便。

matlab
fid = fopen('data.csv', 'r');

% skip header line
header = fgetl(fid);

% parse remaining
% Format: Alice,30,90.5,B+
C = textscan(fid, '%s %d %f %s', ...
             'Delimiter', ',', ...
             'MultipleDelimsAsOne', true, ...
             'TreatAsEmpty', {'NA', 'N/A'}, ...
             'HeaderLines', 0);
fclose(fid);

names = C{1}; ages = C{2}; scores = C{3}; grades = C{4};

% alternative: read whole file at once
str = fileread('data.txt');

% from string
C = textscan('1 2 3\n4 5 6', '%d %d %d');
% C{1} = [1; 4], C{2} = [2; 5], C{3} = [3; 6]

% collectoutput (group columns of same type)
C = textscan(fid, '%s %d %d %f', 'CollectOutput', true);
% C{2} = [ages, more_ints] as one matrix

MAT 文件与保存/加载

save/load 与 .mat 文件保留变量类型和结构。-v7.3 支持大于 2GB 的文件(是现代 MATLAB 中的默认值)。-append 添加变量而不重写。对于大文件,只按名称加载所需内容。对于文本导出,使用 -ascii(有限)或 writematrix/writetable 获得更多控制。

matlab
A = magic(5);
B = struct('name', 'Alice', 'age', 30);
C = rand(100);

% save variables
save('data.mat', 'A', 'B', 'C');
save('data.mat', 'A', 'B', '-v7.3');  % large files > 2GB
save('data.mat', '-append', 'C');     % add to existing

% load
loaded = load('data.mat');       % struct with variables
loaded.A
loaded.B.age

% or load into workspace
load('data.mat');                % A, B, C now in workspace

% partial load (huge files)
info = whos('-file', 'bigdata.mat');
loaded = load('bigdata.mat', 'A');  % only A

% save specific format
save('data.txt', 'A', '-ascii', '-double');
save('data.csv', 'A', '-ascii', '-delimiter', ',');

% compressed
save('data.mat', 'A', '-v7.3', '-nocompression');

HDF5 与科学格式

HDF5 是大型数值数据集的标准——支持分块、压缩和可扩展维度。带 start/count 的 h5read 让你读取切片而不加载整个文件。NetCDF 在气候/海洋科学中常见;FITS 在天文学中。MATLAB 还原生支持 TIFF、DICOM、音频和视频格式。

matlab
% HDF5 (great for large scientific datasets)
% write
h5create('data.h5', '/dataset1', [100 50 20]);
data = rand(100, 50, 20);
h5write('data.h5', '/dataset1', data);

% read
info = h5info('data.h5');
data = h5read('data.h5', '/dataset1');
partial = h5read('data.h5', '/dataset1', [1 1 1], [10 10 5]);

% append (extendable datasets)
h5create('data.h5', '/growable', [100 Inf], 'ChunkSize', [100 100]);
for k = 1:5
  h5write('data.h5', '/growable', rand(100, 100), [1 (k-1)*100+1]);
end

% NetCDF (climate/ocean data)
ncid = netcdf.open('data.nc', 'NC_NOWRITE');
varid = netcdf.inqVarID(ncid, 'temperature');
data = netcdf.getVar(ncid, varid);
netcdf.close(ncid);

% FITS (astronomy)
fitsdisp('image.fits');
data = fitsread('image.fits');

JSON 与 XML

jsonencode/jsondecode(R2016b+)原生处理 JSON。结构体变为 JSON 对象;元胞数组变为数组。对于 XML,xmlread 返回 Java DOM 对象——使用 Java 方法遍历。xmlwrite 将 DOM 序列化回文件。对于复杂的 XML,考虑第三方 xml2struct 或直接使用 DOM API。

matlab
% JSON (R2016b+)
data = struct('name', 'Alice', 'age', 30, 'scores', [90 80 85]);
txt = jsonencode(data, 'PrettyPrint', true);
disp(txt);

decoded = jsondecode(txt);
decoded.name                     % 'Alice'

% JSON with cell arrays for mixed types
data = struct('items', {{'apple', 42, [1 2 3]}});
txt = jsonencode(data);

% read JSON file
txt = fileread('config.json');
config = jsondecode(txt);

% XML
doc = xmlread('data.xml');
root = doc.getDocumentElement;
children = root.getChildNodes;
for k = 0:children.getLength - 1
  node = children.item(k);
  if node.getNodeType == doc.ELEMENT_NODE
    fprintf('%s: %s\n', node.getNodeName, char(node.getTextContent));
  end
end

% write XML
doc = com.mathworks.xml.XMLUtils.createDocument('root');
root = doc.getDocumentElement;
child = doc.createElement('item');
child.appendChild(doc.createTextNode('hello'));
root.appendChild(child);
xmlwrite('out.xml', doc);
25

并行计算

parfor 循环

parfor 在工作进程间并行运行循环迭代。迭代必须独立。变量分类为:切片变量(每次迭代触及唯一索引)、广播变量(只读)、归约变量(用 + 或 * 等关联运算组合)和临时变量(内部创建)。分类决定了允许什么。

matlab
% requires Parallel Computing Toolbox
% start pool
pool = gcp('nocreate');
if isempty(pool), parpool; end

% parfor: parallel for loop
N = 1000;
results = zeros(1, N);
parfor k = 1:N
  results(k) = some_expensive_function(k);
end

% constraints:
%   - iterations must be independent (no order dependency)
%   - body cannot contain break/return
%   - variables classified as sliced, broadcast, reduction, temp

% reduction variables
total = 0;
parfor k = 1:N
  total = total + compute(k);
end

% sliced variables (independent indexing)
data = rand(N, 100);
out = zeros(N, 1);
parfor k = 1:N
  out(k) = mean(data(k, :));
end

spmd 与分布式数组

spmd 在所有工作进程上运行相同代码,用 labindex 标识每个进程。用于工作进程通信的数据并行算法(例如,MPI 风格)。distributed 数组将大型矩阵分散到工作进程上——对它们的运算保持分布式;gather() 将结果带回客户端。Composite 存储每个工作进程的值。

matlab
% spmd: single program, multiple data
spmd
  % code runs on every worker
  % labindex: this worker's ID (1 to numlabs)
  % numlabs: total workers
  fprintf('Worker %d of %d\n', labindex, numlabs);

  % each worker computes a chunk
  local_data = rand(100, 1);
  local_sum = sum(local_data);
end

% combine results
total = sum([local_sum{:}]);

% distributed arrays (split across workers)
D = distributed.rand(10000, 10000);  % huge matrix
local_size = size(D, 'local')        % each worker's chunk
total_size = size(D)                  % logical total

% operations auto-distribute
S = D * D';
S_local = gather(S);                  % pull to client (if fits)

% Composite (cell-like, one per worker)
C = Composite();
spmd
  C{labindex} = magic(labindex + 1);
end
C{1}                              % access worker 1's value

gpuArray

gpuArray 将数据移至 GPU;对 gpuArray 的运算自动在 GPU 上运行。gather() 将数据带回。逐元素和矩阵乘法运算获得最大的加速;标量或分支代码则不会。gpuArray 上的 arrayfun 让你在 GPU 上运行自定义逐元素函数而无需编写 CUDA。

matlab
% requires GPU support (most NVIDIA GPUs)
% move data to GPU
A = gpuArray(rand(10000));
B = gpuArray(rand(10000));

% operations run on GPU
C = A * B;                        % still on GPU
D = sin(A) + cos(B);
E = sum(A, 1);

% bring back to CPU
C_cpu = gather(C);

% check GPU
gpuDevice                        % info about current GPU
gpuDeviceCount                   % number of available GPUs
gpuDevice(1)                     % select device 1

% element-wise ops are typically fastest on GPU
% matrix multiply also very fast (cuBLAS)

% custom kernels (PTX)
k = parallel.gpu.CUDAKernel('my_kernel.ptx', 'my_kernel.cu');
result = feval(k, A, B);

% arrayfun on GPU (element-wise custom functions)
f = @(x) x^2 + sin(x);
result = arrayfun(f, A);

batch 与作业

batch 在后台运行函数或脚本——适用于不想阻塞 MATLAB 会话的长作业。wait(job) 阻塞直到完成;fetchOutputs 检索结果。始终 delete(job) 以释放资源。'Pool', N 使用 N 个额外工作进程用于 batch 函数内部的 parfor。

matlab
% run a function in background
job = batch(@my_function, 0, {arg1, arg2});

% check status
job.State                        % 'queued', 'running', 'finished'
wait(job);                       % block until done

% get results
results = fetchOutputs(job);
delete(job);                     % clean up

% batch script
job = batch('my_script.m');

% with pool
job = batch(@my_func, 1, {x}, 'Pool', 4);  % 4 extra workers

% batch with attached files
job = batch(@my_func, 1, {x}, ...
            'AttachedFiles', {'data.mat', 'helper.m'}, ...
            'CurrentFolder', '/path/to/work');

% list jobs
jobs = findJob(pool);
for j = jobs
  fprintf('Job %d: %s\n', j.ID, j.State);
end

% parallel pool settings
parpool('local', 4);              % 4 workers
delete(gcp('nocreate'));          % shut down pool

性能提示

预分配数组(zeros/ones)——在循环中增长数组是 MATLAB 性能的头号杀手。向量化(sin(x) 而非循环)——更清晰且通常更快。JIT 使简单循环很快,但向量化在数学运算上仍然胜出。profile viewer 查找瓶颈。对超大数据使用单精度;为真正的热点编写 MEX 文件。

matlab
% 1. Preallocate arrays
% BAD
for k = 1:1000
  x(k) = k^2;                    % grows array each iteration
end

% GOOD
x = zeros(1, 1000);
for k = 1:1000
  x(k) = k^2;
end

% 2. Vectorize instead of looping
% BAD
for k = 1:length(x)
  y(k) = sin(x(k));
end

% GOOD
y = sin(x);                      % one vectorized call

% 3. Use JIT-friendly patterns
% simple loops are now fast (JIT), but vectorize for clarity

% 4. Profile to find bottlenecks
profile on;
my_function();
profile viewer;

% 5. Prefer single precision for huge data
A = rand(10000, 'single');       % half the memory

% 6. MEX for critical sections
% compile C code: mex my_func.c
26

面向对象

类定义

将 classdef 保存在名为 <ClassName>.m 的文件中。属性保存数据;方法定义行为。构造函数必须以类命名并处理 nargin==0(无参数调用时)。Dependent 属性在访问时通过 get.X 方法计算。disp 覆盖显示。静态方法不接收 obj。

matlab
% file: Point.m
classdef Point
  properties
    x = 0
    y = 0
  end

  properties (Dependent)
    r                              % computed on access
  end

  methods
    function obj = Point(x, y)
      if nargin > 0
        obj.x = x;
        obj.y = y;
      end
    end

    function r = get.r(obj)
      r = sqrt(obj.x^2 + obj.y^2);
    end

    function obj = move(obj, dx, dy)
      obj.x = obj.x + dx;
      obj.y = obj.y + dy;
    end

    function disp(obj)
      fprintf('Point(%.2f, %.2f), r=%.2f\n', obj.x, obj.y, obj.r);
    end
  end

  methods (Static)
    function p = origin()
      p = Point(0, 0);
    end
  end
end

Value 类与 Handle 类

Value 类在赋值时复制(类似 int 或 struct);handle 类按引用传递(类似 Java 对象)。对于可变对象(数据库连接、UI 组件),使用 handle。Value 类对于不可变数据更简单且更安全。Handle 类继承自 handle 并支持事件/监听器和 delete 析构函数。

matlab
% Value class (default) — copied on assignment
classdef VPoint
  properties; x; end
  methods
    function obj = VPoint(x); obj.x = x; end
    function obj = setX(obj, x); obj.x = x; end
  end
end

p = VPoint(1);
p2 = p;                           % copy
p2 = setX(p2, 5);
disp(p.x)                         % still 1 (unchanged)

% Handle class — passed by reference
classdef HPoint < handle
  properties; x; end
  methods
    function obj = HPoint(x); obj.x = x; end
    function setX(obj, x); obj.x = x; end   % no return needed
  end
end

h = HPoint(1);
h2 = h;                           % same object
h2.setX(5);
disp(h.x)                         % 5 (shared)

% handle class features:
%   - events and listeners
%   - destructor (delete method)
%   - copy() method

继承与多态

用 < 子类化。用 obj@SuperClass(args) 调用超类构造函数。多态自然工作——在基类型上调用方法,正确的覆盖会运行。MATLAB 支持多重继承(用 & 分隔超类),但只有一个可以是具体类;其余必须是接口。

matlab
% base class
classdef Animal
  properties; name; end
  methods
    function obj = Animal(name); obj.name = name; end
    function speak(obj)
      error('Abstract: subclass must override');
    end
    function describe(obj)
      fprintf('%s says: ', obj.name);
      obj.speak();
      fprintf('\n');
    end
  end
end

% subclass
classdef Dog < Animal
  methods
    function obj = Dog(name); obj = obj@Animal(name); end
    function speak(obj); fprintf('Woof'); end
  end
end

classdef Cat < Animal
  methods
    function obj = Cat(name); obj = obj@Animal(name); end
    function speak(obj); fprintf('Meow'); end
  end
end

% polymorphism
animals = {Dog('Rex'), Cat('Whiskers'), Dog('Buddy')};
for k = 1:length(animals)
  animals{k}.describe();
end

% multiple inheritance
classdef FlyingDog < Dog & IFlyable
  ...
end

事件与监听器

事件需要 handle 类。在 events 块中声明事件。notify 触发事件;addlistener 订阅。监听器可以是函数或匿名函数 @(src, event)。自定义事件数据子类化 event.EventData。当源对象被删除时监听器也被删除(或你可以显式删除它们)。

matlab
classdef Thermometer < handle
  properties
    temperature = 20
  end

  events
    temperatureChanged
    overheat
  end

  methods
    function set.temperature(obj, t)
      obj.temperature = t;
      notify(obj, 'temperatureChanged');
      if t > 100
        notify(obj, 'overheat');
      end
    end

    function obj = Thermometer()
      % add listener to own event
      addlistener(obj, 'overheat', @(s,e) disp('WARNING: too hot!'));
    end
  end
end

% usage
t = Thermometer();
lh = addlistener(t, 'temperatureChanged', @(s,e) ...
  fprintf('Now: %.1f\n', s.temperature));
lh2 = addlistener(t, 'overheat', @onOverheat);

t.temperature = 25;               % triggers temperatureChanged
t.temperature = 105;              % triggers both

% custom event data
classdef OverheatData < event.EventData
  properties; temp; end
end
% notify(obj, 'overheat', OverheatData(t));

枚举与属性

枚举类定义固定实例——适用于状态机、选项和类型。每个枚举值可以通过属性携带数据。属性特性控制访问:SetAccess=private 使其从外部只读;Constant 用于编译时常量;Hidden 从显示中隐藏;Access={?Class1, ?Class2} 限制为特定类。

matlab
% enumeration class
classdef Color
  enumeration
    Red [1 0 0]
    Green [0 1 0]
    Blue [0 0 1]
  end
  properties
    rgb
  end
  methods
    function obj = Color(rgb)
      obj.rgb = rgb;
    end
  end
end

c = Color.Red;
disp(c.rgb)                       % [1 0 0]

% switch on enum
switch c
  case Color.Red; disp('red');
  case Color.Green; disp('green');
end

% property attributes
classdef Account
  properties (SetAccess = private)
    balance = 0                   % readable outside, settable only inside
  end
  properties (Access = {?Account, ?Bank})
    internal_id                   % only Account and Bank classes
  end
  properties (Constant)
    PI = 3.14159                  % compile-time constant
  end
  properties (Hidden)
    cache                         % not shown by disp/struct
  end
end

这篇内容对您有帮助吗?