跳转至

函数基础

在 MATLAB 中,函数是组织和复用代码的基本单元。它们是执行特定任务的、独立的程序模块。通过将代码封装在函数中,可以极大地提高程序的可读性、可维护性和模块化程度。

函数的基本结构 (Anatomy of a Function)

一个标准的 MATLAB 函数定义在一个以 .m 为后缀的文件中,且文件名必须与函数名完全相同

  • 基本组成部分:

    1. function 关键字:必须是函数文件的第一行内容。
    2. 输出参数 (Outputs):[out1, out2, ...],定义函数返回的变量。如果是单个输出,方括号 [] 是可选的。
    3. 函数名 (Function Name):functionName,应与 .m 文件名匹配。
    4. 输入参数 (Inputs):(in1, in2, ...),定义调用函数时需要传入的变量。
    5. H1 行 (Help Text):函数定义行紧接着的、以 % 开头的连续注释行。当在命令行中使用 help functionName 时,MATLAB 会显示这部分内容。
    6. 函数体 (Body):实现函数具体功能的代码。
    7. end 关键字:标志着函数的结束。
  • 语法示例 (calculateStats.m):

    function [meanVal, stdVal] = calculateStats(dataVector)
    %CALCULATESTATS 计算向量的均值和标准差。
    %   [meanVal, stdVal] = calculateStats(dataVector) 接收一个数值向量
    %   dataVector,并返回其均值 meanVal 和标准差 stdVal。
    
        % 函数体开始
        n = length(dataVector);
        meanVal = sum(dataVector) / n;
        stdVal = sqrt(sum((dataVector - meanVal).^2) / n);
    
    end % 函数结束
    

函数的类型

MATLAB 中有多种定义和使用函数的方式。

主函数与局部函数 (Main and Local Functions)

  • 主函数:每个函数文件中的第一个函数,其名称与文件名相同。它可以被 MATLAB 路径下的其他脚本或函数调用。
  • 局部函数:在同一个文件中,位于主函数 end 关键字之后的其他函数。它们只能被该文件内的主函数或其他局部函数调用,有助于分解复杂任务。

  • 示例 (myAnalysis.m):

    function finalResult = myAnalysis(rawData)
        % 这是一个主函数
        disp('主函数 myAnalysis 正在执行...');
    
        % 调用文件内的局部函数
        normalizedData = normalize(rawData);
        finalResult = process(normalizedData);
    
        disp('主函数执行完毕。');
    end
    
    % --- 局部函数 ---
    function out = normalize(in)
        % 这是一个局部函数,只能被 myAnalysis 调用
        disp('局部函数 normalize 正在执行...');
        out = (in - min(in)) / (max(in) - min(in));
    end
    
    function res = process(data)
        % 这是另一个局部函数
        disp('局部函数 process 正在执行...');
        res = sum(data .^ 2);
    end
    

匿名函数 (Anonymous Functions)

  • 描述:一种不需要 .m 文件即可定义的、轻量级的单行函数。它通过函数句柄 (@) 来创建和引用。
  • 用途:非常适合定义简单的数学表达式,或作为参数传递给其他函数(如 integral, fminsearch 等)。
  • 语法:handle = @(input1, input2, ...) expression;
  • 示例:
    % 创建一个计算平方的匿名函数
    squareFunc = @(x) x.^2;
    
    % 使用句柄调用该函数
    result = squareFunc(5); % 结果是 25
    
    % 将匿名函数作为参数传递给 integral 函数,计算 x^2 在 [0, 1] 上的定积分
    integralResult = integral(squareFunc, 0, 1);
    

嵌套函数 (Nested Functions)

  • 描述:完全定义在另一个函数(父函数)内部的函数。嵌套函数最显著的特点是它可以访问和修改其父函数工作区中的变量。
  • 示例:
    function mainFunc
        % 父函数
        x = 10;
    
        % 调用嵌套函数
        nestedFunc; 
    
        function nestedFunc
            % 这是一个嵌套函数,它可以直接访问父函数的变量 x
            y = x + 5; % 直接使用 x
            disp(['嵌套函数计算结果: ', num2str(y)]); % 输出 15
        end
    end
    

输入与输出参数处理

可变数量的输入

  • 关键字:varargin (Variable-length Input Argument list)
  • 描述:varargin 允许函数接受任意数量的输入参数。在函数内部,varargin 是一个元胞数组 (Cell Array),包含了所有在常规输入参数之后传入的额外参数。
  • 示例:
    function plotWithStyle(x, y, varargin)
        % 绘制图形,并接受任意数量的'名称-值'对来设置样式
    
        plot(x, y); % 先绘制基本图形
    
        % varargin 是一个元胞数组,例如 {'Color', 'r', 'LineWidth', 2}
        % 使用 set 函数应用所有样式
        if ~isempty(varargin)
            set(gca, varargin{});
        end
    end
    
    % 调用示例:
    % x = 1:10; y = x.^2;
    % plotWithStyle(x, y, 'Color', 'r', 'LineWidth', 2, 'Marker', '*');
    

可变数量的输出

  • 关键字:varargout (Variable-length Output Argument list)
  • 描述:varargout 允许函数返回任意数量的输出参数。在函数内部,varargout 也是一个元胞数组,你需要按顺序为其元素赋值。
  • 示例:
    function [varargout] = multiStats(data)
        % 根据请求的输出数量,返回不同的统计值
    
        % nargout 是一个内置变量,表示调用者请求的输出参数数量
        if nargout >= 1
            varargout{1} = mean(data); % 第一个输出总是均值
        end
        if nargout >= 2
            varargout{2} = std(data);  % 第二个输出是标准差
        end
        if nargout >= 3
            varargout{3} = max(data);  % 第三个输出是最大值
        end
    end
    
    % 调用示例:
    myData = [1, 2, 3, 4, 5];
    [avg] = multiStats(myData); % 只获取均值
    [avg, s] = multiStats(myData); % 获取均值和标准差
    [avg, s, m] = multiStats(myData); % 获取全部三个值
    

arguments 块 (R2019b+)

  • 描述:这是现代 MATLAB 中用于输入参数验证的首选方法。它提供了一种清晰、结构化的方式来声明参数的类型、大小、默认值以及其他验证规则。
  • 示例:
    function result = advancedAdder(a, b, options)
        % 使用 arguments 块进行输入验证
        arguments
            a (1,1) double % a 必须是 1x1 的 double
            b (1,1) double {mustBeNumeric} % b 必须是数值类型
            options.Method string {mustBeMember(options.Method, ["add", "subtract"])} = "add" % options.Method 必须是 "add" 或 "subtract",默认值为 "add"
        end
    
        switch options.Method
            case "add"
                result = a + b;
            case "subtract"
                result = a - b;
        end
    end
    
    % 调用示例:
    advancedAdder(2, 3) % 结果是 5
    advancedAdder(10, 5, "Method", "subtract") % 结果是 5
    advancedAdder(2, [3,4]) % 这会因为 b 的大小不匹配而报错
    

函数工作区与变量作用域

函数工作区 (Function Workspace)

  • 描述:每个函数在被调用时,都会创建一个属于自己的、临时的、独立的工作区 (Workspace)。函数的输入参数、内部定义的变量都存在于这个工作区中。当函数执行结束时,这个工作区及其中的所有变量(除了返回的输出参数)都会被销毁。
  • 优点:这种隔离机制可以防止不同函数间的变量名冲突,避免了不必要的“副作用”,使代码更健壮。

persistent 变量

  • 描述:persistent 关键字用于声明一个持久变量。与普通变量不同,持久变量的值在函数调用结束后不会被销毁,而是会被保留下来,供下一次调用该函数时使用。
  • 用途:适用于需要“记住”上一次状态的场景,如实现计数器、缓存计算结果等。
  • 示例:
    function call_count = counter()
        % 声明一个持久变量
        persistent n_calls;
    
        if isempty(n_calls)
            % 第一次调用时,n_calls 是空的,需要初始化
            n_calls = 0;
        end
    
        n_calls = n_calls + 1;
        call_count = n_calls;
    end
    
    % 调用示例:
    counter() % 返回 1
    counter() % 返回 2
    counter() % 返回 3
    

global 变量

  • 描述:global 关键字用于声明一个全局变量。全局变量可以在所有声明了该变量的函数、脚本以及基础工作区之间共享数据。
  • 用途:用于在程序的多个、不方便通过参数传递的部分之间共享状态或数据。
  • 示例:
    % --- 在一个函数中设置全局变量 ---
    function setGlobalValue(val)
        global SHARED_DATA; % 声明
        SHARED_DATA = val;
        disp('全局变量已设置。');
    end
    
    % --- 在另一个函数中读取全局变量 ---
    function readGlobalValue()
        global SHARED_DATA; % 声明
        disp(['读取到的全局变量是: ', num2str(SHARED_DATA)]);
    end
    
    % 调用示例:
    setGlobalValue(100);
    readGlobalValue(); % 将会显示 100
    

谨慎使用全局变量

全局变量会破坏函数的封装性,使代码的依赖关系变得复杂和不明确,从而难以调试和维护。在绝大多数情况下,应优先考虑通过函数参数和返回值来传递数据。

常用Matlab函数分类

1. 矩阵与数组操作

  • zeros (Zeros array):创建全零、全一或单位矩阵。
  • ones (Ones array):创建全零、全一或单位矩阵。
  • eye (Identity matrix):创建全零、全一或单位矩阵。
  • rand (Uniformly distributed random numbers):生成均匀分布或正态分布的随机数矩阵。
  • randn (Normally distributed random numbers):生成均匀分布或正态分布的随机数矩阵。
  • size (Array size):获取矩阵的尺寸或数组的长度。
  • length (Length of vector):获取矩阵的尺寸或数组的长度。
  • reshape (Reshape array):改变矩阵的形状。
  • diag (Diagonal matrices and diagonals of matrix):提取或创建对角矩阵。

2. 数学运算

  • sin (Sine):基本的三角函数、指数和对数函数。
  • cos (Cosine):基本的三角函数、指数和对数函数。
  • tan (Tangent):基本的三角函数、指数和对数函数。
  • exp (Exponential):基本的三角函数、指数和对数函数。
  • log (Natural logarithm):基本的三角函数、指数和对数函数。
  • sqrt (Square root):计算平方根。
  • abs (Absolute value):计算绝对值或复数的模。
  • sum (Sum of array elements):计算数组元素的和或积。
  • prod (Product of array elements):计算数组元素的和或积。
  • mean (Average or mean value):计算平均值、标准差和方差。
  • std (Standard deviation):计算平均值、标准差和方差。
  • var (Variance):计算平均值、标准差和方差。
  • max (Maximum elements of an array):找到数组中的最大或最小元素。
  • min (Minimum elements of an array):找到数组中的最大或最小元素。

3. 线性代数

  • inv (Matrix inverse):计算矩阵的逆。
  • det (Matrix determinant):计算矩阵的行列式。
  • eig (Eigenvalues and eigenvectors):计算特征值和特征向量。
  • svd (Singular value decomposition):进行奇异值分解。
  • \ (Solve systems of linear equations):高效地求解线性方程组 Ax = b

4. 绘图与可视化

  • plot (2-D line plot):绘制二维线图。
  • scatter (Scatter plot):绘制散点图。
  • bar (Bar chart):绘制条形图。
  • histogram (Histogram plot):绘制直方图。
  • surf (Surface plot):绘制三维表面图或网格图。
  • mesh (Mesh plot):绘制三维表面图或网格图。
  • xlabel (x-axis label):添加坐标轴标签、标题和图例。
  • ylabel (y-axis label):添加坐标轴标签、标题和图例。
  • title (Add title to axes):添加坐标轴标签、标题和图例。
  • legend (Add legend to axes):添加坐标轴标签、标题和图例。

5. 数据分析与处理

  • fft (Fast Fourier transform):计算快速傅里叶变换。
  • ifft (Inverse fast Fourier transform):计算逆快速傅里叶变换。
  • interp1 (1-D data interpolation):一维数据插值。
  • polyfit (Polynomial curve fitting):多项式曲线拟合。
  • polyval (Polynomial evaluation):计算多项式的值。

6. 方程求解

  • solve (Solve algebraic equations):符号求解代数方程。
  • fzero (Find root of nonlinear function):求解单变量非线性函数的根。
  • ode45 (Solve nonstiff differential equations):求解非刚性常微分方程。

7. 流程控制 (语言结构)

  • if, elseif, else:条件判断结构。
  • for, while:循环结构。
  • switch, case:多分支选择结构。
  • function:定义函数。

8. 文件输入/输出

  • load (Load variables from file):加载和保存 .mat 格式的工作区变量。
  • save (Save workspace variables to file):加载和保存 .mat 格式的工作区变量。
  • readtable (Create a table from a file):读取和写入表格数据 (如 .csv 文件)。
  • writetable (Write a table to a file):读取和写入表格数据 (如 .csv 文件)。
  • fopen (Open file):底层的文件操作。
  • fprintf (Write data to text file):底层的文件操作。
  • fclose (Close file):底层的文件操作。