问题

有哪些让人相见恨晚的 MATLAB 命令?

回答
MATLAB 确实有很多强大且实用的命令,其中一些命令一旦掌握,就会让你觉得“相见恨晚”,极大地提升你的编程效率和代码质量。下面我将详细介绍一些我认为非常值得深入了解和使用的 MATLAB 命令,并附带详细的解释和示例。

核心理念:充分利用 MATLAB 的向量化和内置函数能力,避免显式循环。



1. `logical` / 逻辑索引(Logical Indexing)

相见恨晚原因: 告别繁琐的 `if` 语句和循环,用更简洁优雅的方式选择、修改或删除数据。这是 MATLAB 最核心的优势之一。

详细解释:
逻辑索引利用一个与原数组相同大小的逻辑数组(只包含 `true` 或 `false`)来选择原数组中的元素。当逻辑数组中对应位置为 `true` 时,原数组的该元素被选中;当为 `false` 时,则被忽略。

基本用法:

选择元素: `array(logical_array)`
修改元素: `array(logical_array) = new_value`
删除元素: `array(logical_array) = []` (注意:删除元素时可能会改变原数组的尺寸和索引,需谨慎使用)

常用生成逻辑数组的方法:

比较运算符: `>` (大于), `<` (小于), `>=` (大于等于), `<=` (小于等于), `==` (等于), `~=` (不等于)
逻辑运算符: `&` (逻辑与), `|` (逻辑或), `~` (逻辑非), `xor` (逻辑异或)
内置函数: `any()`, `all()`, `find()` (可以返回逻辑索引的线性索引值)

示例:

假设有一个数据数组 `data`,我们想找出所有大于 50 的元素,并将它们加倍。

```matlab
data = [10, 65, 20, 80, 35, 90, 45];

% 使用逻辑索引选择大于 50 的元素
greater_than_50_indices = data > 50;
selected_data = data(greater_than_50_indices) % selected_data 将是 [65, 80, 90]

% 将大于 50 的元素加倍
data(greater_than_50_indices) = data(greater_than_50_indices) 2;
% 或者更简洁地
data(data > 50) = data(data > 50) 2;
disp(data); % 输出: [10, 130, 20, 160, 35, 180, 45]

% 找到第一个大于 70 的元素的位置
first_gt_70_index = find(data > 70, 1); % find(condition, count)
if ~isempty(first_gt_70_index)
disp(['第一个大于 70 的元素在索引 ', num2str(first_gt_70_index), ',值为 ', num2str(data(first_gt_70_index))]);
else
disp('没有找到大于 70 的元素');
end
```

为什么相见恨晚?
在学习 MATLAB 初期,很多人习惯于用 `for` 循环来遍历数组,逐个检查条件。但一旦掌握了逻辑索引,你会发现这比循环快得多,代码也更简洁、可读性更强。例如,替代 `for` 循环的写法可能像这样:

```matlab
% 传统 for 循环 (效率低,代码冗长)
new_data = data;
for i = 1:length(data)
if data(i) > 50
new_data(i) = data(i) 2;
end
end
```
相比之下,逻辑索引的方式明显更优越。



2. `cellfun` 和 `structfun`

相见恨晚原因: 它们允许你将一个函数应用到 cell 数组或结构体数组的每个元素上,而无需编写显式的 `for` 循环。这在处理异构数据结构时尤为强大。

详细解释:

`cellfun(func, cell_array, ...)`: 将函数 `func` 应用到 `cell_array` 的每个单元格中。
`structfun(func, struct_array, ...)`: 将函数 `func` 应用到 `struct_array` 的每个字段值上。

`cellfun` 的常用参数:

`'UniformOutput'`: `'on'`(默认,如果函数返回单个值且输出类型一致则返回数组)或 `'off'`(返回一个 cell 数组,每个单元格是函数对对应 cell 单元格的输出)。
`'ErrorHandler'`: 指定当函数出错时如何处理,例如 `'error'`(默认)、`'continue'`。

示例 (`cellfun`):

假设有一个 cell 数组,其中包含不同类型的元素:

```matlab
my_cells = {1, 'hello', [3, 4], true, 5.6};

% 1. 获取每个单元格的类名
cell_types = cellfun(@class, my_cells, 'UniformOutput', false);
disp(cell_types); % 输出: {'double', 'char', 'double', 'logical', 'double'}

% 2. 计算包含数字的单元格元素的总和 (这里需要一点技巧,先用 isnumber 进行筛选)
numeric_cells = my_cells(cellfun(@isnumeric, my_cells)); % 找出数字类型的单元格
sum_of_numbers = sum(cell2mat(numeric_cells)); % 将数字 cell 转换成矩阵再求和
disp(['数字元素的总和: ', num2str(sum_of_numbers)]); % 输出: 数字元素的总和: 9.6 (1 + 3+4 + 5.6)

% 3. 将所有数值类型的单元格元素加倍 (这里需要一个匿名函数)
my_cells_doubled = cellfun(@(x) (isnumeric(x) ? x2 : x), my_cells, 'UniformOutput', false);
disp(my_cells_doubled); % 输出: {2, 'hello', [6, 8], true, 11.2}
```

示例 (`structfun`):

假设有一个结构体数组,每个结构体代表一个学生的信息:

```matlab
students = struct('name', {'Alice', 'Bob', 'Charlie'}, ...
'score', {95, 88, 92}, ...
'passed', {true, true, true});

% 1. 获取所有学生的姓名
student_names = structfun(@(x) x, students, 'UniformOutput', false);
% 或者更直接地
student_names_direct = {students.name};
disp(student_names_direct); % 输出: {'Alice', 'Bob', 'Charlie'}

% 2. 将所有学生的成绩加 5 分
students_updated = students;
students_updated = structfun(@(x) (isnumeric(x) ? x+5 : x), students_updated, 'ErrorHandler', 'continue');
% 注意: structfun 应用于 fields,这里我们希望对 'score' 字段操作,
% 但 structfun 会尝试对所有字段应用函数。
% 更精确的对特定字段操作通常结合点索引。
% 例如,对所有学生的 score 字段操作:
for i = 1:length(students)
students_updated(i).score = students_updated(i).score + 5;
end
disp(students_updated);
```
在上面的 `structfun` 例子中,`structfun` 并不像 `cellfun` 那样直观地应用于 特定字段,而是应用于 字段值。如果结构体有不同类型的字段,直接用 `structfun` 可能不如 `cellfun` 通用,因为 `structfun` 会尝试将函数应用到所有字段的值上。通常我们更倾向于直接使用点索引来访问和修改结构体数组的特定字段。

为什么相见恨晚?
在处理包含字符串、数值、逻辑值等的 cell 数组时,如果没有 `cellfun`,你可能需要写一个 `for` 循环来判断每个单元格的类型并进行相应操作。`cellfun` 大大简化了这个过程。对于结构体数组,`structfun` 也能提供便利,但通常 `for` 循环配合点索引(如 `{students.name}`)或 `arrayfun`(用于函数映射)可能更灵活。然而,理解 `cellfun` 和 `structfun` 的存在本身就是一种进步。



3. `arrayfun`

相见恨晚原因: 类似于 `cellfun`,但它主要用于将一个函数应用到数组的每个 元素 上(不是单元格),返回一个与输入数组相同维度的输出数组。特别适合对数值数组进行逐元素操作。

详细解释:
`arrayfun` 将函数 `func` 应用到输入数组 `A` 的每个元素上。它的行为与 `cellfun` 相似,但更侧重于数组操作。

常用参数:

`'UniformOutput'`: `'on'`(默认,如果函数返回单个值且输出类型一致则返回数组)或 `'off'`(返回一个 cell 数组)。

示例:

```matlab
A = [1, 2, 3, 4, 5];

% 1. 计算每个元素的平方
squared_A = arrayfun(@(x) x^2, A);
disp(squared_A); % 输出: [1, 4, 9, 16, 25]

% 2. 如果元素大于 3,则加 10,否则保持不变
modified_A = arrayfun(@(x) (x > 3 ? x + 10 : x), A);
disp(modified_A); % 输出: [1, 2, 3, 14, 15]

% 3. 使用 arrayfun 和逻辑索引结合 (虽然不如直接逻辑索引简洁,但展示了 arrayfun 的灵活性)
% 例如,将所有大于 3 的元素转换为字符串
string_A = arrayfun(@(x) (x > 3 ? num2str(x) : 'small'), A, 'UniformOutput', false);
disp(string_A); % 输出: {'small', 'small', 'small', '4', '5'}
```

为什么相见恨晚?
`arrayfun` 是向量化思维的另一种表达方式,特别是当你的函数不能直接向量化(例如,一个复杂的条件逻辑),或者你想让代码更清晰地表达“对每个元素执行此操作”时,`arrayfun` 就非常有用。虽然 MATLAB 的设计理念是鼓励你尽可能用内建的向量化函数(如 `sin`, `exp`, `+`, `` 等本身就支持数组操作的函数),但在某些复杂情况下,`arrayfun` 是一个不错的选择,避免了显式 `for` 循环。



4. `anonymous functions` (匿名函数)

相见恨晚原因: 它们允许你创建小型的、一次性的函数,无需定义一个完整的 `function` 文件。这在与 `cellfun`, `arrayfun`, `plot` 的回调函数等结合使用时极其方便。

详细解释:
匿名函数使用 `@(parameters) expression` 的语法创建。`parameters` 是函数的输入参数列表,`expression` 是函数的主体,它会返回一个值。

示例:

```matlab
% 定义一个简单的匿名函数
square = @(x) x.^2;
disp(square(5)); % 输出: 25

% 定义一个接收两个参数的匿名函数
add_vals = @(a, b) a + b;
disp(add_vals(3, 7)); % 输出: 10

% 在 plot 函数中使用匿名函数创建函数图像
x = pi:0.1:pi;
y = @(theta) sin(theta) . exp(abs(theta) / 5);
plot(x, y(x));
title('Sine wave with exponential decay');
xlabel('Theta');
ylabel('Amplitude');

% 结合 cellfun 使用匿名函数
my_cells = {1:5, 'hello', [10, 20]};
lengths = cellfun(@length, my_cells); % cellfun 接受函数句柄,这里 length 是内置函数
% 如果想对数值部分执行操作,可以使用匿名函数
add_five_to_numeric = @(c) (isnumeric(c) ? c + 5 : c);
result_cells = cellfun(add_five_to_numeric, my_cells, 'UniformOutput', false);
disp(result_cells); % 输出: { [6, 7, 8, 9, 10], 'hello', [15, 25] }
```

为什么相见恨晚?
匿名函数是 MATLAB 函数式编程的基石。它们让你的代码更加紧凑和模块化。你可以在一行代码中完成原本需要多行代码(包括 `function` 定义)才能实现的功能。这对于创建自定义绘图函数、数据处理的中间步骤或者作为其他高阶函数的参数,都极大地提升了效率和可读性。



5. `find` (高级用法)

相见恨晚原因: `find` 命令不仅仅是返回元素的索引,它能以多种方式帮助你理解和操作数据的“位置信息”,尤其是在结合逻辑索引和统计时。

详细解释:
`find(A)` 返回数组 `A` 中非零元素的线性索引。当 `A` 是逻辑数组时,它返回 `true` 元素的索引。

高级用法和技巧:

指定返回数量: `find(condition, k)` 返回前 `k` 个满足条件的元素的索引。
指定返回方向: `find(condition, k, 'last')` 返回最后 `k` 个满足条件的元素的索引。
结合维度信息: `[rows, cols] = find(A)` 当 `A` 是二维数组时,返回满足条件的元素的行索引和列索引。这比 `find(A)` 返回线性索引后,再通过 `ind2sub` 转换更直接。
与 `any()` 和 `all()` 结合: `any(find(condition))` 判断是否存在满足条件的元素,`length(find(condition))` 获取满足条件的元素数量。

示例:

```matlab
data = [0, 1, 0, 2, 0, 3, 0, 4];

% 1. 找到非零元素的索引
non_zero_indices = find(data);
disp(['非零元素的索引: ', num2str(non_zero_indices)]); % 输出: 非零元素的索引: 2 4 6 8

% 2. 找到大于 2 的元素,只返回第一个
first_gt_2_index = find(data > 2, 1);
if ~isempty(first_gt_2_index)
disp(['第一个大于 2 的元素在索引 ', num2str(first_gt_2_index)]); % 输出: 第一个大于 2 的元素在索引 6
else
disp('没有找到大于 2 的元素');
end

% 3. 找到所有大于 1 的元素的位置 (返回行和列)
matrix_data = [1, 0, 3; 0, 5, 0; 2, 0, 6];
[rows, cols] = find(matrix_data > 2);
disp('大于 2 的元素的行索引: '); disp(rows); % 输出: [1; 2; 3]
disp('大于 2 的元素的列索引: '); disp(cols); % 输出: [3; 2; 3]
% 此时,满足条件的元素是 matrix_data(rows, cols) 或者更直接地 matrix_data(sub2ind(size(matrix_data), rows, cols))

% 4. 计算非零元素的个数
num_non_zeros = length(find(data));
disp(['非零元素的个数: ', num2str(num_non_zeros)]); % 输出: 非零元素的个数: 4

% 5. 检查是否存在大于 5 的元素
has_gt_5 = any(find(data > 5)); % 或者更简洁: has_gt_5 = any(data > 5);
disp(['是否存在大于 5 的元素: ', num2str(has_gt_5)]); % 输出: 0 (false)
```

为什么相见恨晚?
`find` 命令的强大之处在于其灵活性。掌握 `find` 的各种参数后,你可以更精确地控制你想要找到的“位置”,并且能直接获取行/列索引,而无需额外的转换步骤。它常常与逻辑索引结合使用,是进行数据筛选和位置定位的利器。



6. `deal`

相见恨晚原因: 当你需要将一个变量的值分配给多个变量,或者将多个变量的值分配给一个列表时,`deal` 提供了一种简洁的方式。

详细解释:
`deal` 命令用于将输入参数分配给输出参数。它可以实现一对一、多对一或一对多的值传递。

基本用法:

一对多: `[a, b, c] = deal(value)` 将 `value` 分配给 `a`, `b`, `c`。
多对一: `result = deal(var1, var2, var3)` `result` 将是一个 cell 数组,包含 `var1`, `var2`, `var3` 的值。

示例:

```matlab
% 1. 将多个变量初始化为 0
a = 0; b = 0; c = 0;
% 使用 deal 可以简化为:
[a, b, c] = deal(0);
disp([a, b, c]); % 输出: 0 0 0

% 2. 交换两个变量的值
x = 10; y = 20;
% 传统方法:
temp = x; x = y; y = temp;
% 使用 deal:
[x, y] = deal(y, x);
disp([x, y]); % 输出: 20 10

% 3. 将函数返回的多个输出分配给变量
% 例如,假设有一个函数 myfunc 返回两个值
% [out1, out2] = myfunc(input);
% 使用 deal 也可以实现:
% [out1, out2] = deal(myfunc(input)); % 这里的 deal 并不直接适用于这种函数返回场景,
% deal 主要用于赋值,而不是作为函数调用的直接返回值分配器。
% 正确用法应是类似:
results_cell = deal(x, y, 'hello'); % results_cell = {20, 10, 'hello'}
disp(results_cell);
```

为什么相见恨晚?
在初始化变量、交换变量或将一组值分发给不同的变量时,`deal` 比显式的赋值语句更简洁。特别是在函数返回多个值且需要将它们分配到不同变量时,虽然直接赋值 `[var1, var2] = myFunc()` 是标准做法,但 `deal` 的概念可以帮助理解值传递。在某些循环或迭代场景下,`deal` 的多变量赋值能力会显得尤为方便。



7. `isempty`

相见恨晚原因: 这是一个非常基础但极其重要的命令,用于检查一个变量是否为空。在条件判断中,正确地使用 `isempty` 可以避免很多潜在的错误,尤其是当处理函数返回值、循环结果或用户输入时。

详细解释:
`isempty(A)` 返回 `true` 如果 `A` 是空数组(例如 `[]`, `{}`, `''`),否则返回 `false`。

常见误区和正确用法:

错误示范: `if A == []`,这在 `A` 是 `NaN` 或其他非空值时可能表现不正确。
正确用法: `if isempty(A)`

示例:

```matlab
% 1. 函数可能返回空数组
function output = find_first_positive(input_array)
positive_indices = find(input_array > 0);
if ~isempty(positive_indices)
output = input_array(positive_indices(1));
else
output = []; % 如果没有找到正数,返回空
end
end

my_data1 = [1, 2, 0, 5, 3];
result1 = find_first_positive(my_data1);
if isempty(result1)
disp('没有找到正数');
else
disp(['第一个正数是: ', num2str(result1)]); % 输出: 第一个正数是: 5
end

my_data2 = [1, 2, 0, 3];
result2 = find_first_positive(my_data2);
if isempty(result2)
disp('没有找到正数'); % 输出: 没有找到正数
else
disp(['第一个正数是: ', num2str(result2)]);
end

% 2. 检查用户输入是否为空
userInput = input('请输入一个值: ', 's');
if isempty(userInput)
disp('你没有输入任何东西!');
else
disp(['你输入了: ', userInput]);
end
```

为什么相见恨晚?
很多新手程序员会忽略空数组的情况,导致程序在遇到空数据时崩溃或产生意外结果。`isempty` 是处理这种情况的黄金标准。一旦你养成了在关键的条件判断中使用 `isempty` 的习惯,你的代码就会健壮得多。



8. `switch` 语句 (与 `ifelseifelse`) 的对比

相见恨晚原因: 当你需要根据一个变量的多个不同值执行不同的代码块时,`switch` 语句比冗长的 `ifelseifelse` 结构更清晰、更易读。

详细解释:
`switch` 语句评估一个表达式,并根据表达式的值与各个 `case` 语句中的常量进行匹配来执行相应的代码块。

语法:

```matlab
switch expression
case value1
% 代码块 1
case {value2a, value2b} % 可以匹配多个值
% 代码块 2
otherwise
% 默认代码块 (可选)
end
```

示例:

```matlab
command = 'plot'; % 假设这是一个从用户输入或配置文件读取的命令

switch lower(command) % 使用 lower() 使匹配不区分大小写
case 'plot'
disp('正在绘图...');
% plot(x, y);
case {'save', 'saveas'}
disp('正在保存文件...');
% save('data.mat');
case 'clear'
disp('正在清除变量...');
% clearvars;
otherwise
disp('未知命令!');
end
```

为什么相见恨晚?
在处理用户选择、状态机或者根据不同数据类型执行不同操作时,`switch` 是 `ifelseifelse` 的绝佳替代品。它结构清晰,易于扩展,并且比多个 `elseif` 块更容易理解和维护。尤其当 `case` 的值是枚举类型或固定的字符串时,`switch` 的优势更为明显。



9. `error`, `warning`, `disp` (诊断和信息传递)

相见恨晚原因: 掌握如何有效地使用这三个命令可以极大地改善你的调试过程和代码的可用性。它们是你与代码进行沟通的桥梁。

详细解释:

`disp(message)`: 显示消息,通常用于输出信息或调试。
`warning(message)`: 显示一个警告消息。这通常表示潜在的问题,但程序可以继续执行。
`error(message)`: 显示一个错误消息并终止程序的执行。用于表示程序无法继续的情况。

最佳实践和技巧:

使用 `message` 对象: 对于复杂的消息,使用 `message` 对象可以更好地控制格式化和本地化。
在函数中清晰地指出问题: `error` 和 `warning` 消息应该包含足够的信息,让用户知道哪里出了问题以及为什么。
结合函数名: 在函数内部,通常会包含函数名,例如 `error(['MyFunction:InvalidInput: ', 'Input array must be nonempty.']);`
使用 `trycatch` 块处理错误: 可以捕获由 `error` 命令抛出的错误,并执行自定义的错误处理逻辑。

示例:

```matlab
function process_data(data)
if isempty(data)
error('process_data:EmptyInput', '输入数据不能为空。'); % 终止执行,并提供错误信息
elseif ~isnumeric(data)
warning('process_data:NonNumericInput', '输入数据不是数值类型,结果可能不准确。'); % 发出警告,但继续执行
end

disp(['正在处理数据,大小为: ', num2str(size(data))]); % 显示处理信息

% 假设后续还有一些处理步骤...
processed_data = data 2;
disp('数据处理完成。');
end

% 示例调用
try
process_data([]); % 会触发 error
catch ME
fprintf('捕获到错误: %s ', ME.message); % 显示错误信息
end

try
process_data([1, 2; 3, 4]); % 会触发 disp
process_data([1, 'a'; 3, 4]); % 会触发 warning 和 disp
catch ME
fprintf('捕获到错误: %s ', ME.message);
end
```

为什么相见恨晚?
在开发的早期阶段,程序员往往只关注“让它跑起来”,但忽略了代码的健壮性和用户反馈。`disp` 用于输出中间结果,`warning` 和 `error` 则提供了清晰的错误处理机制。学会使用它们,你就能写出更易于调试、更用户友好的 MATLAB 程序。特别是 `trycatch` 结构,是构建健壮程序的关键。



10. `svd` / `qr` / `eig` 等线性代数函数

相见恨晚原因: 这些函数是矩阵分析和科学计算的核心。一旦你理解了它们背后的数学原理并知道如何使用它们,你就能解决许多更高级、更复杂的问题,比如数据降维、系统稳定性分析、图像处理等。

详细解释:

`svd(A)`: 计算矩阵 `A` 的奇异值分解 (Singular Value Decomposition)。它将任意矩阵分解为三个矩阵的乘积:$A = U Sigma V^T$。奇异值反映了矩阵的“重要性”或“能量”。
`qr(A)`: 计算矩阵 `A` 的 QR 分解。它将矩阵分解为正交矩阵 `Q` 和上三角矩阵 `R` 的乘积:$A = QR$。常用于求解线性最小二乘问题和计算特征值。
`eig(A)`: 计算矩阵 `A` 的特征值和特征向量。特征值和特征向量揭示了矩阵的线性变换特性。

应用场景:

`svd`: 主成分分析 (PCA) 用于降维,图像压缩,推荐系统。
`qr`: 求解线性方程组,最小二乘问题,数值稳定性高的算法。
`eig`: 稳定性分析(如控制系统),振动分析,图像识别中的特征提取。

示例 (`svd` for PCA 简化版):

假设我们有一个数据集,每行是一个样本,每列是一个特征。我们想用 PCA 来降维。

```matlab
% 创建一个示例数据集 (20个样本, 3个特征)
data = randn(20, 3);
% 给数据增加一些相关性
data(:, 2) = data(:, 1) 0.5 + randn(20, 1) 0.1;
data(:, 3) = data(:, 1) 1.2 + randn(20, 1) 0.2;

% 1. 中心化数据 (减去均值)
mean_data = mean(data, 1);
centered_data = data mean_data;

% 2. 计算协方差矩阵
cov_matrix = cov(centered_data); % 或者 centered_data' centered_data / (size(centered_data, 1) 1);

% 3. 计算协方差矩阵的特征值和特征向量 (也可以直接对 centered_data 使用 svd)
[V, D] = eig(cov_matrix); % V 是特征向量矩阵,D 是特征值对角矩阵

% 4. 将特征值按降序排序,并得到对应的特征向量
[~, sort_indices] = sort(diag(D), 'descend');
sorted_eigenvectors = V(:, sort_indices);
sorted_eigenvalues = diag(D);

% 5. 选择前 k 个主成分 (例如 k=2)
k = 2;
principal_components = sorted_eigenvectors(:, 1:k);

% 6. 将原始数据投影到主成分上进行降维
reduced_data = centered_data principal_components;

disp('原始数据维度: '); disp(size(data));
disp('降维后数据维度: '); disp(size(reduced_data));
```

为什么相见恨晚?
很多初学者可能只关注 MATLAB 的绘图和基本数据操作。但一旦你开始接触信号处理、控制系统、机器学习或更高级的科学计算,线性代数函数就变得不可或缺。它们是解决复杂数学问题的基石,能够让你从根本上理解数据的结构和系统的特性。理解这些函数并学会应用它们,意味着你打开了 MATLAB 更广阔的应用领域。



总结:

掌握 MATLAB 的命令是一个循序渐进的过程。上面列出的这些命令,虽然有些看似基础(如 `isempty`),但它们是构建高效、健壮、可读性强的 MATLAB 代码的基石。而像 `cellfun`, `arrayfun`, 匿名函数以及高级线性代数函数,则能让你在解决复杂问题时事半功倍。

持续学习 MATLAB 的内置函数库,并时刻思考如何用向量化和内建函数代替显式循环,是让你不断发现“相见恨晚”的命令的关键。祝你在 MATLAB 的学习旅程中不断发现新的宝藏!

网友意见

user avatar

Matlab里面应该多用向量运算,把循环语句转变为向量运算会省很多时间,程序也更简洁易读。

比方说,一个名叫array数组里面,你要将里面大于1的都变成0,就不必用到循环:

array(array>1)=0;

把大于1小于3的变成0。

array(and(array>1,array<3))=0;

当然,还可以使用find,这个也很好用。

——————————————————————————————

另一个重要的技巧是delete/clf-plot-pause

用plot可以画图(注意记录句柄),然后用delete删掉特定图象,或用clf清图,再绘制,这可以在figure窗口产生动画。但是如果只plot,往往只会在全部程序执行结束时显示,这时候需要用pause让figure完成图像的更新。drawnow貌似也可以,但是我比较喜欢用pause,能够简单地控制动画的速度。

这会方便调试和展示。这个技巧尤其适合使用matlab的图形用户界面设计功能时构造一个显示运行状态等信息的figure。

——————————————————————————————

mathworks 有一个fig函数(不是系统自带的,是别人编写的),可以很容易地调整字体、尺寸以及绘图是否有边框等等,不必画出来再自己手动调整。这对于写论文的人来说会很方便。

这些年有太多人向我要这个文件了,我把程序贴在回答的最后了,大家自己用吧。

——————————————————————————————

善用eval,可以让你的程序的灵活度大大加强。尤其是在变量名的问题上。当然,这可能会对代码维护和调试带来麻烦。很多情况可以用其他方法代替。 @王备 指出了一个链接,值得一读Alternatives to the eval Function

——————————————————————————————

save、load可以将部分或全部变量、结构体等存入mat文件或从mat导入workspace

global可以将变量变为全局变量,在各函数之间共享。不过这不太好用,尽量慎用吧。

——————————————————————————————

exist可以检测某目标(如变量)是否存在,减少一些麻烦。

——————————————————————————————

surf、mesh都很漂亮,不过surf之后记得用shading interp,看起来更漂亮。

——————————————————————————————

对于一些重复性的矩阵赋值,比如:1、2、3、4、1、2、3、4

可以使用repmat,将一个矩阵重复扩展为更大的矩阵。

——————————————————————————————

很多函数都有高级的用法,当使用到了,但又觉得有点麻烦的时候,不妨help一下,看看其他的用法。

总而言之,还是多上网搜索,一般问题总有很好的答案。


——————————————————————————

最后把fig文件贴在这里

       function h = fig(varargin) % FIG - Creates a figure with a desired size, no white-space, and several other options. % %       All Matlab figure options are accepted.  %       FIG-specific options of the form FIG('PropertyName',propertyvalue,...)  %       can be used to modify the default behavior, as follows: % %       -'units'    : preferred unit for the width and height of the figure  %                      e.g. 'inches', 'centimeters', 'pixels', 'points', 'characters', 'normalized'  %                      Default is 'centimeters' % %       -'width'    : width of the figure in units defined by 'units' %                      Default is 14 centimeters %                      Note: For IEEE journals, one column wide standard is %                      8.5cm (3.5in), and two-column width standard is 17cm (7 1/16 in) % %       -'height'   : height of the figure in units defined by 'units' %                      Specifying only one dimension sets the other dimension %                      to preserve the figure's default aspect ratio.  % %       -'font'     : The font name for all the texts on the figure, including labels, title, legend, colorbar, etc. %                      Default is 'Times New Roman'  % %       -'fontsize' : The font size for all the texts on the figure, including labels, title, legend, colorbar, etc. %                      Default is 14pt %        %       -'border'   : Thin white border around the figure (compatible with export_fig -nocrop)  %                      'on', 'off' %                      Default is 'off'  % %   FIG(H) makes H the current figure.  %   If figure H does not exist, and H is an integer, a new figure is created with %   handle H. % %   FIG(H,...) applies the properties to the figure H. % %   H = FIG(...) returns the handle to the figure created by FIG. % % % Example 1: %   fig % % Example 2: %   h=fig('units','inches','width',7,'height',2,'font','Helvetica','fontsize',16) % % % Copyright  ?2012 Reza Shirvany,  matlab.sciences@neverbox.com  % Source:   http://www.mathworks.com/matlabcentral/fileexchange/30736 % Updated:   05/14/2012 % Version:   1.6.5  % %Revised by Zhe Leng 2012 Jul 10th, add set(H, 'PaperPositionMode', %'auto'); for consistency in the saved images files.        % default arguments width=14; font='Times New Roman'; fontsize=14;  units='centimeters'; bgcolor='w'; sborder='off'; flag=''; Pindex=[];  %%%%%%%%%%% process optional arguments optargin = size(varargin,2); if optargin>0  % check if a handle is passed in if isscalar(varargin{1}) && isnumeric(varargin{1})     flag=[flag '1'];     i=2;      if ishghandle(varargin{1})==1         flag=[flag 'i'];     end else     i=1; end  % get the property values while (i <= optargin)     if (strcmpi(varargin{i}, 'border'))         if (i >= optargin)             error('Property value required for: %s', num2str(varargin{i}));         else             sborder = varargin{i+1};flag=[flag 'b'];             i = i + 2;         end     elseif (strcmpi(varargin{i}, 'width'))         if (i >= optargin)             error('Property value required for: %s', num2str(varargin{i}));         else             width = varargin{i+1};flag=[flag 'w'];             i = i + 2;         end     elseif (strcmpi(varargin{i}, 'height'))         if (i >= optargin)             error('Property value required for: %s', num2str(varargin{i}));         else             height = varargin{i+1};flag=[flag 'h'];             i = i + 2;         end     elseif (strcmpi(varargin{i}, 'font'))         if (i >= optargin)             error('Property value required for: %s', num2str(varargin{i}));         else             font = varargin{i+1};flag=[flag 'f'];             i = i + 2;         end     elseif (strcmpi(varargin{i}, 'fontsize'))         if (i >= optargin)             error('Property value required for: %s', num2str(varargin{i}));         else            fontsize = varargin{i+1};flag=[flag 's'];             i = i + 2;         end     elseif (strcmpi(varargin{i}, 'units'))         if (i >= optargin)             error('Property value required for: %s', num2str(varargin{i}));         else             units = varargin{i+1};flag=[flag 'u'];             i = i + 2;         end     elseif (strcmpi(varargin{i}, 'color'))         if (i >= optargin)             error('Property value required for: %s', num2str(varargin{i}));         else             bgcolor = varargin{i+1};flag=[flag 'c'];             i = i + 2;         end     else         %other figure properties         if (i >= optargin)             error('A property value is missing.');         else         Pindex = [Pindex i i+1];         i = i + 2;         end     end  end  end  % We use try/catch to handle errors try  % creat a figure with a given (or new) handle if length(strfind(flag,'1'))==1     s=varargin{1};     if ishandle(s)==1     set(0, 'CurrentFigure', s);     else          figure(s);     end else     s=figure; end  flag=[flag 's'];  % set other figure properties if ~isempty(Pindex)     set(s,varargin{Pindex}); end  % set the background color set(s, 'color',bgcolor);  % set the font and font size set(s, 'DefaultTextFontSize', fontsize);  set(s, 'DefaultAxesFontSize', fontsize);  set(s, 'DefaultAxesFontName', font); set(s, 'DefaultTextFontName', font);  %%%%%%%%%%% set the figure size % set the root unit old_units=get(0,'Units'); set(0,'Units',units);  % get the screen size scrsz = get(0,'ScreenSize');  % set the root unit to its default value set(0,'Units',old_units);  % set the figure unit set(s,'Units',units);  set(s, 'PaperPositionMode', 'auto');  % get the figure's position pos = get(s, 'Position'); old_pos=pos; aspectRatio = pos(3)/pos(4);  % set the width and height of the figure if length(strfind(flag,'w'))==1 && length(strfind(flag,'h'))==1      pos(3)=width;     pos(4)=height; elseif isempty(strfind(flag,'h'))     pos(3)=width;     pos(4) = width/aspectRatio; elseif isempty(strfind(flag,'w')) && length(strfind(flag,'h'))==1     pos(4)=height;     pos(3)=height*aspectRatio;  end  % make sure the figure stays in the middle of the screen diff=old_pos-pos;   if diff(3)<0  pos(1)=old_pos(1)+diff(3)/2;      if pos(1)<0          pos(1)=0;      end  end  if diff(4)<0  pos(2)=old_pos(2)+diff(4);     if pos(2)<0          pos(2)=0;      end  end   % warning if the given width (or height) is greater than the screen size if pos(3)>scrsz(3) warning(['Maximum width (screen width) is reached! width=' num2str(scrsz(3)) ' ' units]); end  if pos(4)>scrsz(4) warning(['Maximum height (screen height) is reached! height=' num2str(scrsz(4)) ' ' units]); end  % apply the width, height, and position to the figure set(s, 'Position', pos); if strcmpi(sborder, 'off')     set(s,'DefaultAxesLooseInset',[0,0,0,0]); end        % handle errors catch ME     if isempty(strfind(flag,'i')) && ~isempty(strfind(flag,'s'))     close(s);     end    error(ME.message) end  s=figure(s); % return handle if caller requested it.   if (nargout > 0)         h =s;   end % % That's all folks! % %flag/1iwhfsucsb      

用法是这样:

你可以先用fig生成一个画图窗口(同时设置其显示方式),然后再用plot画。

也可以用h=fig(……)来生成一个画图窗口并获得其句柄,然后后续用plot(h,……)来画图

还可以用H=plot(……)来画图,然后用fig(H,……)来设置一个已经存在的画图窗口的显示方式。

user avatar
  • 1.对两路信号作图时,可用 linkaxes 同步x轴,以便之后手动放大同步查看局部细节,例如:
       ax(1) = subplot(2,1,1) plot(time,signal1) ax(2) = subplot(2,1,2) plot(time,signal2)    linkaxes (ax,'x')      

当然你也可以同步y轴:linkaxes (ax,'y') ,甚至两轴都同步:linkaxes (ax,'xy') 。


--------- 更新1---------

  • 2. 相信很多人都知道hold on指令能用于作重叠的曲线图,但当两曲线值域相差太大时,以至于不能更好地展示彼此的细节,可考虑用如下方法(MATLAB 2016a 开始支持,低版本的用plotyy):
       plot(time,signal1) yyaxis right      % 用右边的y轴展示 plot(time,signal2)     

偷一张MATLAB官网的图来展示一下效果(侵删)。此方法跟前面的linkaxes有些相似,然而linkaxes能展示多个曲线。linkaxes适合用于自己查看分析,本方法适合作报告节省空间。


  • 3.很多人提到多行注释 ctrl + R 。但其缺点是不能折叠。利用如下格式,可使注释后的内容折叠起来。
                %{          可折叠的注释区域          %}            

--------- 更新2---------

  • 4. 获取当前路径:path = pwd; 。获取当前路径所有文件及文件夹的名字:names = ls ;其实要想具体一点,用dir代替ls会更好:files = dir;

--------- 更新3---------

  • 5. 用 deal() 让初始化更简洁。

合并内容相同的初始化:

       % 假如要初始化A,B,C和D为3*4阶矩阵,平常我们会用如下代码 A = zeros(3,4); B = zeros(3,4); C = zeros(3,4); D = zeros(3,4);  % 利用deal()改造后,简洁相当多 [A,B,C,D] = deal(zeros(3,4));     

当然,初始化的内容不一定都相同,但是仍然可以缩成一行

       % 如以下例子 A = zeros(3,4); B = []; C = ones(2); D = cell(2);  % 可以用deal()改造,只是长一点 [A,B,C,D] = deal(zeros(3,4),[],ones(2),cell(2));     

初始化结构体数组,当行数特别多时,优势明显

       % 正常方法初始化3行,两个field的结构体数组: inl = {0, 0, 0};  % 必须得元胞数组,有些麻烦 s = struct('f1',inl,'f2',inl);  % 用deal改进 [s(1:3).f1,s(1:3).f2] = deal(0);  % 如果内容不一样,就每个field分开来 [s(1:3).f1] = deal(0); [s(1:3).f2] = deal(zeros(3));  % 把3改成任意行数n     

--------- 更新4---------

  • 6. 大家觉不觉得每次用plot作图返回的窗口都好小,每次都要手动按右上角的框框放大,贼烦~以下命令实现自动放大
       % 以下代码实现自动放大 fig = figure; fig.Position = get(0,'ScreenSize');  % fig.Position这种操作好像MATLAB 2012还是2013之后才有的,忘记了,低版本用set吧 % % % % 我是分界线 % % % % plot(1:10)  % 随便做个图查看效果 zoom on  % 顺手加个放大,省得点工具栏     

--------- 更新5---------

  • 7. 这个可能很多人知道,但是真的很好用。用‘end’检索最后一位元素
       % 正常方法获取向量V最后一位元素 N = length(V); last = V(N);  % 用end的话方便很多 last = V(end);  % 还可以这样 test1 = V(end-1);   % 倒数第二个 test2  = V(1:end/2);  % 获取一半(奇数长度会有警告)     

矩阵的用法差不多,就不举例了


  • 8. 前面有人说过 dbstop if error。如果再配合两把宝剑,会更好用:dbup 和 dbdown。

这两个命令在程序错误并断点之后在命令行输入,用于在workspace间切换查看变量调试。dbup是跳到上层workspace,dbdown是返回。

类似的话题

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有