---
layout: doc
title: MATLAB 基础与矩阵操作
breadcrumb: 基础与矩阵操作
description: MATLAB 界面基础指令、变量数据类型、矩阵定义、索引切片、点运算，以及学生成绩数据分析实践项目。
---

# MATLAB 基础与矩阵操作

本章介绍 MATLAB 的基础知识，包括界面操作、变量与数据类型、矩阵切片索引，以及常见的矩阵运算法则。

---

## 0. 常用基础函数（随机与取整）

在进行数据处理或矩阵操作时，经常需要生成随机数或对数值进行取整。以下是几个常用的基础函数：

### 0.1 随机数生成函数
*   **`rand` 函数**：生成 $0 \sim 1$ 之间均匀分布的随机浮点数。
    *   `rand()` 或 `rand(1)`：生成一个单个的随机标量。
    *   `rand(n)`：生成 $n \times n$ 的随机矩阵。
    *   `rand(m, n)`：生成 $m \times n$ 的随机矩阵。
*   **`randi` 函数**：生成均匀分布的伪随机整数。
    *   `randi(imax)`：生成 $1 \sim imax$ 之间的随机整数。
    *   `randi([imin, imax])`：生成 $imin \sim imax$ 之间的随机整数。
    *   `randi(imax, m, n)`：生成 $m \times n$ 大小的随机整数矩阵，取值范围为 $1 \sim imax$。或者使用 `randi([imin, imax], m, n)` 指定 $imin \sim imax$ 范围。

### 0.2 取整函数
MATLAB 提供了四种常见的取整函数，满足不同的取整需求：
*   **`round`**：四舍五入。例如 `round(3.4)` 结果为 3，`round(3.5)` 结果为 4。
*   **`ceil`**：向上取整（朝正无穷方向）。例如 `ceil(3.1)` 结果为 4，`ceil(-3.9)` 结果为 -3。
*   **`floor`**：向下取整（朝负无穷方向）。例如 `floor(3.9)` 结果为 3，`floor(-3.1)` 结果为 -4。
*   **`fix`**：向零取整（截断小数部分）。例如 `fix(3.9)` 结果为 3，`fix(-3.9)` 结果为 -3。

### 0.3 代码示例
下面是一些结合随机数生成与取整函数的简单代码示例，你可以直接在 MATLAB 命令行中尝试：

```matlab
% 1. 生成一个 3x3 的随机浮点数矩阵 (0~1之间)
A = rand(3)

% 2. 生成一个 2x4 的随机整数矩阵，范围在 10 到 50 之间
B = randi([10, 50], 2, 4)

% 3. 生成随机数并取整：生成 1x5 的随机浮点数 (0~10之间) 并四舍五入
C = rand(1, 5) * 10
C_rounded = round(C)

% 4. 向上取整和向下取整的对比
num = 5.3;
val_ceil = ceil(num)   % 结果为 6
val_floor = floor(num) % 结果为 5
```

---

## 1. 界面与常用基础命令

### 1.1 界面核心区域
*   **命令行窗口 (Command Window)**：交互式输入指令并实时显示结果的窗口，提示符为 `>>`。
*   **工作区 (Workspace)**：展示当前内存中已创建的所有变量名称、大小（Size）及数据类型（Class）。
*   **当前文件夹 (Current Folder)**：MATLAB 寻找和执行代码文件的默认路径，代码及数据文件需在此目录下。
*   **命令历史记录 (Command History)**：记录之前输入过的历史命令，按 `↑` 键可调出。

### 1.2 必备基础命令
在命令行或调试中使用以下指令，可以简化操作：

| 命令 | 功能说明 | 使用场景 |
| :--- | :--- | :--- |
| `clc` | 清除命令行窗口内容 | 清理控制台界面，不影响工作区变量。 |
| `clear` | 清空工作区变量 | 释放内存（如：`clear A` 清除变量 A）。 |
| `close all` | 关闭所有图窗 | 自动关闭所有当前打开的 Figure 绘图窗口。 |
| `who` / `whos` | 列出内存变量 | 查看当前变量，`whos` 包含大小与内存占用细节。 |
| `help [命令名]` | 命令行帮助 | 快速查看特定函数的语法结构与用法。 |
| `doc [命令名]` | 调出官方文档 | 在独立窗口中打开带有详尽示例的官方说明手册。 |

::: tip 授人以渔：如何探索未知的函数？
如果你只知道大概要干什么（比如“统计分析”），但不知道具体的函数名叫什么，该怎么办？
1. **利用 doc 分类浏览**：在命令行直接输入 `doc` 回车（不加任何参数），会打开官方文档主页。依次点击 **MATLAB -> Mathematics -> Data Analysis**，里面分门别类地列出了所有的基础统计与分析函数（如 `sum`、`mean`、`max`、`var` 等）。
2. **利用 lookfor 关键词搜索**：例如在命令行输入 `lookfor average`，MATLAB 会全局检索所有描述中带有 average 的函数，并提示你 `mean` 函数可以实现该功能。
:::

### 🎯 闯关题目 1
1. **清理环境**：使用什么命令可以一键清空工作区中残留的所有变量，并清理命令行窗口的内容？
2. **文档查询**：如果你忘记了 `rand` 函数的具体用法，如何在 MATLAB 中快速调出它的官方文档？

<details>
<summary>查看答案</summary>

1. **清理环境**：连续执行 `clear`（清空工作区变量）和 `clc`（清理命令行窗口内容）即可。也可以写在一行：`clear; clc`。
2. **文档查询**：在命令行输入 `doc rand`，即可在独立窗口中打开官方的图文说明手册。

</details>

---

## 2. 变量与数据类型

### 2.1 变量命名规则
1.  变量名区分大小写（例如 `a` 与 `A` 代表不同变量）。
2.  必须以字母开头，后续可以由字母、数字或下划线 `_` 组成。
3.  不能占用系统保留关键字（如 `if`、`for`、`function` 等）。

### 2.2 常用数据类型
*   **数值型 (double)**：默认所有数字均为双精度浮点数。
*   **字符与字符串 (char / string)**：
    *   单引号 `'...'` 代表字符数组 (char)，例如 `'hello'`，大小为 1×5。
    *   双引号 `"..."` 代表字符串 (string)，例如 `"hello"`，大小为 1×1。
*   **逻辑型 (logical)**：取值为 `logical(1)` (true) 或 `logical(0)` (false)。

::: tip 提示：分号 `;` 的作用
*   命令末尾如果不加分号，计算结果会在命令行窗口中直接打印输出。
*   命令末尾如果加上分号，计算会被执行并保存结果，但在控制台不会产生任何输出。在编写 `.m` 代码文件时，建议每行命令都以分号结尾，防止垃圾信息刷屏。
:::

### 🎯 闯关题目 2
1. **命名判定**：以下哪些是合法的 MATLAB 变量名？`My_var1`、`2ndMatrix`、`_temp`、`matrix_A`。
2. **隐藏输出**：在命令行输入 `x = 10` 和 `y = 20;` 运行后，两者的表现有什么区别？
3. **逻辑隐式转换（进阶）**：如果在命令行中执行数学运算 `res = true + 5;`，MATLAB 会抛出类型不匹配的错误，还是会正常计算？如果正常计算，`res` 的结果是多少？此时它的数据类型（Class）会是 `logical` 还是 `double`？为什么？

<details>
<summary>查看答案</summary>

1. **命名判定**：
   - 合法：`My_var1`、`matrix_A`。
   - 不合法：`2ndMatrix`（不能以数字开头）、`_temp`（不能以下划线开头）。
2. **隐藏输出**：`x = 10` 运行后会在命令行打印出结果；`y = 20;` 带有分号，计算会静默执行并保存结果，但在控制台不会有任何打印输出。
3. **逻辑隐式转换（进阶）**：会正常计算。结果 `res` 为 `6`。数据类型会变为默认的 `double`。这是因为 MATLAB 遇到数学运算时，会将逻辑真值 `true` 视为数值 `1`，并依照精度就高原则转化为双精度浮点数进行加法运算。

</details>

---

## 3. 矩阵与数组操作

在 MATLAB 中，标量实际上被视作 1×1 的矩阵。

### 3.1 矩阵的创建方法

#### 1) 手动输入方式（使用方括号 `[]`）
*   **行向量**：元素之间用空格或逗号分隔。
    ```matlab
    row_vec = [1, 2, 3, 4]      % 1×4 行向量
    ```
*   **列向量**：元素之间用分号分隔。
    ```matlab
    col_vec = [1; 2; 3; 4]      % 4×1 列向量
    ```
*   **二维矩阵**：结合使用逗号（分列）与分号（分行）。
    ```matlab
    A = [1 2 3; 4 5 6; 7 8 9]   % 3×3 矩阵
    ```

#### 2) 等差数列方式（冒号算子 `:`）
*   语法：`首项 : 步长 : 末项`（步长为 1 时，可简写为 `首项:末项`）。
    ```matlab
    x = 1:2:9     % 生成行向量 [1, 3, 5, 7, 9]
    ```

#### 3) 等分区间方式 (`linspace`)
*   语法：`linspace(首项, 末项, 点的个数)`。适用于在特定区间内生成均匀分布的坐标点。
    ```matlab
    t = linspace(0, 2*pi, 100)  % 在 0 到 2*pi 之间等距离生成 100 个点
    ```

#### 4) 快捷生成函数
*   `zeros(r, c)`：生成 `r` 行 `c` 列的全零矩阵。
*   `ones(r, c)`：生成 `r` 行 `c` 列的全一矩阵。
*   `eye(n)`：生成 `n` 阶单位矩阵。
*   `rand(r, c)`：生成 $0 \sim 1$ 之间均匀分布的随机浮点数矩阵。
*   `randi([min, max], r, c)`：生成指定范围内的随机整数矩阵。

---

### 3.2 矩阵索引与切片

MATLAB 中的索引值是从 1 开始的（非零基索引）。

#### 3.2.1 访问特定元素
*   语法：`A(行索引, 列索引)`。
    ```matlab
    A = [10 20; 30 40];
    val = A(1, 2)  % 提取结果为 20
    ```

#### 3.2.2 切片取值（使用冒号 `:`）
冒号代表该维度上的所有元素。
*   `A(1, :)`：提取第一行的所有列（即整行提取）。
*   `A(:, 2)`：提取第二列的所有行（即整列提取）。
*   `A(1:2, 2:3)`：取第 1 至 2 行，第 2 至 3 列的子矩阵。
*   `A(end, :)`：关键字 `end` 代表行或列的最后一个索引值。

#### 3.2.3 矩阵元素修改
通过索引直接赋值：
```matlab
A = [1 2; 3 4];
A(2, 1) = 99;   % 矩阵 A 变为 [1 2; 99 4]
```

#### 3.2.4 逻辑索引 (Logical Indexing)
除了使用行号和列号，MATLAB 还支持**逻辑索引**。
对矩阵使用关系运算符（如 `>`、`<`、`==`）时，会生成一个由 0 和 1 组成的逻辑矩阵。将这个逻辑矩阵作为索引传入原矩阵，就能提取满足条件的元素。

**简单示例：提取及格的分数**
假设有一个包含学生成绩的行向量，我们要把其中及格（大于等于 60 分）的成绩提取出来：
```matlab
scores = [45, 88, 72, 59, 91];

% 1. 生成逻辑掩码
% 关系运算符 (>=) 本身就会直接返回逻辑型数组
% 这里显式嵌套一层 logical() 能够使类型转换的代码意图更加严谨和清晰
mask = logical(scores >= 60);  % mask 的结果为逻辑型：[0, 1, 1, 0, 1]

% 2. 使用掩码提取元素（即逻辑索引）
passed = scores(mask) % 提取结果为：[88, 72, 91]
```
**直接使用关系运算符配合 `logical()` 进行数据过滤** 是日常数据分析中最常用的方式。

---

### 3.3 矩阵运算：普通乘法与点运算

::: warning 注意事项
普通乘除幂是严格的**矩阵级代数运算**，必须满足矩阵相乘的尺寸要求；而带点号的乘除幂（`.*`、`./`、`.^`）是**元素级运算**，要求左右矩阵的维度完全相同。
:::

| 运算符 | 名称 | 代数含义与限制条件 | 示例 |
| :--- | :--- | :--- | :--- |
| `+` / `-` | 矩阵加减法 | 要求维度一致。各位置元素分别相加减。 | `C = A + B` |
| `*` | **矩阵乘法** | 经典线性代数矩阵乘法。要求 A 的列数等于 B 的行数。 | `C = A * B` |
| `.*` | **点乘 (元素乘)** | 要求维度完全一致。对应位置元素各自相乘。 | `C = A .* B` |
| `^` | 矩阵幂 | 要求 A 为方阵。表示多个 A 自乘。 | `C = A^2` |
| `.^` | 点幂 (元素幂) | 对矩阵中的每个元素独立求幂运算。不限形状。 | `C = A.^2` |
| `'` | 共轭转置 | 交换行列并对复数求共轭。 | `C = A'` |
| `.'` | 算术转置 | 仅交换行列，不求共轭。 | `C = A.'` |
| `\` | **左除 (反斜杠)** | 求解线性方程组 $Ax = B$，即 $x = A \backslash B$。比 `inv(A)*B` 更稳定。 | `x = A \ B` |

### 🎯 闯关题目 3
1. **生成等差数列**：如何使用冒号算子 `:` 生成一个从 0 开始，步长为 0.5，直到 5 结束的行向量？
2. **矩阵切片**：已知矩阵 `A = rand(5, 5)`，请写出提取 `A` 的第 2 到 4 行的第 3 列和第 5 列元素的表达式。
3. **逻辑索引**：给定向量 `v = [10, -5, 8, -2, 4]`，请写出一行代码，直接提取出 `v` 中所有大于 0 的元素。
4. **运算辨析**：现有行向量 `u = [1, 2, 3]` 和 `v = [4, 5, 6]`，执行 `u * v` 与 `u .* v` 时，哪一个会报错？为什么？

<details>
<summary>查看答案</summary>

1. **生成等差数列**：使用表达式 `0:0.5:5`。
2. **矩阵切片**：使用表达式 `A(2:4, [3, 5])`。
3. **逻辑索引**：使用表达式 `v(v > 0)` 即可。
4. **运算辨析**：`u * v` 会报错。因为 `*` 是矩阵乘法，要求前一个矩阵的列数等于后一个矩阵的行数（这里 `u` 的列数是 3，`v` 的行数是 1，维度不匹配）。而 `.*` 是点乘（元素乘），要求两矩阵形状完全相同，因此 `u .* v` 可以正常执行并得到 `[4, 10, 18]`。

</details>

---

## 4. 实践项目：学生成绩数据分析

本练习只需在命令行操作，主要用于熟悉矩阵的切片提取与逻辑索引。

### 4.1 项目描述

假设你是一位助教，拿到了班级 5 名学生在 3 门科目（数学、物理、编程）上的成绩单。请在 MATLAB 工作区中完成以下分析任务：

1. **录入成绩矩阵**：请根据下方给出的数据，在 MATLAB 中构建一个 5 行 3 列的矩阵 `grades`（每一行代表一名学生的 3 门成绩）：
   | 学生序号 | 数学 (第 1 列) | 物理 (第 2 列) | 编程 (第 3 列) |
   | :--- | :--- | :--- | :--- |
   | 1 | 78 | 85 | 90 |
   | 2 | 60 | 55 | 75 |
   | 3 | 92 | 88 | 95 |
   | 4 | 85 | 90 | 80 |
   | 5 | 50 | 65 | 59 |
2. **计算平均分**：提取数学（第 1 列）的成绩，计算全班的单科平均分。
   *(提示：你可以使用 MATLAB 的内置函数 `sum(向量)` 来对整列求和，或者直接使用 `mean(向量)` 求平均值)*
3. **逻辑筛选（难点）**：找出所有在“编程”科目（第 3 列）中得分超过 85 分的优秀分数，并将这些高分单独提取到一个列向量中。

### 4.2 动手实践

请先尝试自己在 MATLAB 工作区中一步步敲出命令并验证。本题参考代码已加密保护：

<div v-if="!isUnlocked" style="padding: 1rem; border: 1px solid var(--vp-c-divider); border-radius: 8px; margin-top: 1rem; background-color: var(--vp-c-bg-soft);">
  <p style="margin: 0 0 0.5rem 0; font-weight: bold;">🔒 输入密码解锁参考代码</p>
  <div style="display: flex; gap: 0.5rem; align-items: center;">
    <input type="password" v-model="pwd" @keyup.enter="checkPwd" placeholder="请输入助教提供的密码" style="padding: 0.3rem 0.6rem; border: 1px solid var(--vp-c-divider); border-radius: 4px; outline: none; background: var(--vp-c-bg); color: var(--vp-c-text-1); font-size: 0.9em; flex: 1; max-width: 200px;" />
    <button @click="checkPwd" style="padding: 0.3rem 0.8rem; background-color: var(--vp-c-brand); color: white; border-radius: 4px; cursor: pointer; font-size: 0.9em; font-weight: bold; border: none;">解锁</button>
  </div>
  <p v-if="errorMsg" style="color: var(--vp-c-danger-1, #e33); margin: 0.5rem 0 0 0; font-size: 0.9em;">{{ errorMsg }}</p>
</div>

<div v-if="isUnlocked">

```matlab
% 1. 录入矩阵（每一行代表一个学生的 3 门成绩）
grades = [
    78, 85, 90;
    60, 55, 75;
    92, 88, 95;
    85, 90, 80;
    50, 65, 59
];

% 2. 提取数据并计算
math_scores = grades(:, 1);             % 提取第 1 列（数学）
math_mean = sum(math_scores) / 5;       % 计算数学平均分 (也可直接使用 mean(math_scores))

% 3. 逻辑索引：筛选编程（第 3 列）大于 85 分的成绩
prog_scores = grades(:, 3);             % 先提取编程成绩列
excellent_mask = prog_scores > 85;      % 生成逻辑掩码（掩码为 5x1 逻辑数组）
excellent_prog = prog_scores(excellent_mask) % 使用掩码提取高分成绩
```

</div>

通过这个练习，你可以实际体验 MATLAB 中矩阵切片和逻辑索引的用法。

<script setup>
import { ref } from 'vue'

const pwd = ref('')
const isUnlocked = ref(false)
const errorMsg = ref('')

function checkPwd() {
  if (pwd.value === 'matlab2026') {
    isUnlocked.value = true
    errorMsg.value = ''
  } else {
    errorMsg.value = '密码错误！'
  }
}
</script>
