跳转至

MATLAB 数据拟合

数据拟合是工程和科学分析中的一项基本任务,其目的是找到一个数学模型(通常是一个函数)来最佳地描述一组观测数据点。MATLAB 提供了从交互式工具到高级编程函数的全方位支持,能够处理从简单的线性回归到复杂非线性模型的各种拟合问题。

交互式拟合工具

Curve Fitter App (cftool) - 图形化曲线拟合工具

  • 功能 对于快速的数据探索和模型比较,曲线拟合 App (Curve Fitter) 是最高效的选择。它提供了一个完整的图形化界面,让你无需编写代码即可尝试多种模型、评估拟合质量并导出结果。
  • 启动方式
    1. 在 MATLAB App 选项卡中,找到并点击 Curve Fitter 图标。
    2. 在命令行窗口中输入 cftool
  • 核心优势
    • 无需编程: 完全通过图形界面操作。
    • 模型丰富: 内置大量常用拟合模型库(多项式、指数、高斯、傅里叶级数等)。
    • 实时反馈: 调整参数或模型后,拟合曲线和拟合优度统计数据会立即更新。
    • 代码生成: 完成拟合后,可以自动生成 MATLAB 函数来复现整个拟合过程,便于自动化处理。
  • 示例
    % 1. 创建一些示例数据
    x = linspace(0, 10, 101);
    y = 3*exp(-0.5*x) + 0.2*randn(size(x));
    
    % 2. 打开曲线拟合工具
    cftool(x, y);
    % 在弹出的窗口中,你可以选择不同的模型进行拟合,例如选择 'Exponential' 模型。
    

核心编程函数

polyfit - 拟合多项式曲线

  • 功能 找到一个 n 阶多项式的系数,使其在最小二乘意义下最佳地拟合一组给定的 (x, y) 数据点。
  • 数学原理: 最小二乘法 (Least Squares Method) polyfit 旨在找到一组多项式系数 \(\bm{p} = [p_1, p_2, \dots, p_{n+1}]\),使得模型预测值 \(y_\mr{model}(x_i) = p_1 x_i^n + p_2 x_i^{n-1} + \dots + p_{n+1}\) 与实际观测值 \(y_i\)(共 \(m\) 个数据)之间的残差平方和 (Sum of Squared Residuals, SSR) 最小:

    \[ \min_{\bm{p}} \sum_{i=1}^{m} \left[ y_i - y_\mr{model}(x_i) \right]^2 \]

    这是一个可以通过求解线性方程组 \(A^T A \bm{p} = A^T \mathbf{y}\) (正规方程) 来精确解决的问题。

  • 语法

    p = polyfit(x, y, n)
    [p, S] = polyfit(x, y, n)
    [p, S, mu] = polyfit(x, y, n)
    

  • 语法说明

    • p = polyfit(x, y, n): 返回一个行向量 p,其中包含 n 阶多项式的系数,按降幂排列。
    • S: 返回一个结构体,用于 polyval 计算误差估计。
    • mu: 返回一个二元向量 [mean(x), std(x)],用于中心化和缩放数据,以提高拟合的数值稳定性。
  • 示例

    % 1. 生成带噪声的数据
    x = linspace(0, 4*pi, 10);
    y = sin(x) + 0.15*randn(size(x));
    
    % 2. 使用 3 阶多项式进行拟合
    p = polyfit(x, y, 3); % p 是一个包含 4 个多项式系数的向量
    
    % 3. 在更密集的点上评估拟合出的多项式 (需要 polyval)
    x_fit = linspace(0, 4*pi, 100);
    y_fit = polyval(p, x_fit);
    
    % 4. 绘图
    figure;
    plot(x, y, 'ro', 'DisplayName', '原始数据');
    hold on;
    plot(x_fit, y_fit, 'b-', 'LineWidth', 2, 'DisplayName', '3阶多项式拟合');
    legend;
    title('polyfit 和 polyval 示例');
    

polyval - 评估多项式函数值

  • 功能polyfit 配套使用,计算由系数向量 p 定义的多项式在指定 x 值处的函数值。
  • 语法
    y = polyval(p, x)
    [y, delta] = polyval(p, x, S)
    
  • 语法说明

    • y = polyval(p, x): 计算多项式在 x 处的值。
    • [y, delta] = polyval(p, x, S): Spolyfit 返回的结构体,delta 是 50% 置信区间的预测误差。
  • 示例 (见 polyfit 示例)

fit - 通用曲线拟合

  • 功能 最强大、最推荐的通用拟合函数 (需要 Curve Fitting Toolbox)。它支持大量的库模型(如多项式、高斯、指数、傅里叶级数等),并且可以轻松地拟合用户定义的非线性方程。

  • 数学原理 fit 函数根据指定的模型类型,使用不同的优化算法来最小化模型与数据之间的残差平方和。

    • 线性模型: 使用线性最小二乘法。
    • 非线性模型: 使用非线性最小二乘算法,如信赖域 (Trust-Region) 算法或 Levenberg-Marquardt 算法。这需要用户提供参数的初始猜测值 (StartPoint)。
  • 语法

    fitresult = fit(x, y, fitType)
    fitresult = fit([x, y], z, fitType) % 曲面拟合
    [fitresult, gof] = fit(x, y, fitType, fitOptions)
    

  • 语法说明

    • fitresult: 一个 cfit (曲线) 或 sfit (曲面) 对象,包含了所有拟合结果。
    • fitType: 指定模型类型。可以是库模型名称的字符串(如 'poly2', 'exp1', 'gauss1'),也可以是一个由 fittype 创建的自定义模型对象。
    • gof: 一个包含拟合优度统计量(如 R-square, SSE, RMSE)的结构体。
    • fitOptions: 一个由 fitoptions 函数创建的选项对象,用于设置算法、初始值等。
  • 示例 (自定义非线性拟合)

    % 1. 生成带噪声的数据
    x = (0:0.1:5)';
    y = 2*exp(-0.5*x) + 0.2*randn(size(x));
    
    % 2. 使用 fittype 定义自定义拟合模型
    % fittype 定义模型方程,'a', 'b' 是待拟合参数
    ft = fittype('a*exp(-b*x)', 'independent', 'x', 'dependent', 'y');
    
    % 3. 使用 fitoptions 设置算法选项,如起始点
    opts = fitoptions('Method', 'NonlinearLeastSquares');
    opts.StartPoint = [1 1]; % 猜测 a=1, b=1
    
    % 4. 使用 fit 函数进行拟合
    [fitresult, gof] = fit(x, y, ft, opts);
    
    % 5. 显示和绘制结果
    disp('拟合结果:');
    disp(fitresult);
    disp('拟合优度 (R-square):');
    disp(gof.rsquare);
    
    figure;
    plot(fitresult, x, y); % cfit 对象可以直接绘制
    legend('原始数据', '拟合曲线');
    title('fit 函数自定义模型拟合');
    

fittype - 创建自定义拟合模型

  • 功能fit 配套使用,通过一个字符串或匿名函数来定义一个可重用的拟合模型,特别是对于非线性方程。

  • 语法

    ft = fittype(expression)
    ft = fittype(fun)
    

  • 示例 (见 fit 示例)

lsqcurvefit - 非线性最小二乘拟合

  • 功能 求解非线性曲线拟合(最小二乘)问题 (需要 Optimization Toolbox)。它专门用于寻找参数 \(\bm{p}\),使得用户定义的函数 \(F(x, \bm{p})\) 与观测数据 \(y\)\(m\) 个数据)的残差平方和最小。

    \[ \min_{\bm{p}} \sum_{i=1}^{m} \left[ F(x_i, \bm{p}) - y_i \right]^2 \]
  • 数学原理 lsqcurvefit 使用迭代优化算法(如信赖域反射算法)来求解。从一个初始猜测值 \(\bm{p}_0\) 开始,算法在每一步迭代中寻找一个能使残差平方和下降的方向和步长,直到满足收敛条件。

  • 语法

    p = lsqcurvefit(fun, p0, xdata, ydata)
    p = lsqcurvefit(fun, p0, xdata, ydata, lb, ub, options)
    

  • 语法说明

    • fun: 一个函数句柄,形如 @(p, xdata),它接受参数 p 和自变量 xdata,并返回模型预测值。
    • p0: 参数的初始猜测值向量。
    • xdata, ydata: 观测数据。
    • lb, ub: 参数的下界和上界(可选)。
    • options: 优化选项(可选)。
  • 示例

    % 1. 定义要拟合的函数模型
    % p(1) -> a, p(2) -> lambda
    model_fun = @(p, x) p(1) * x .* exp(-p(2)*x);
    
    % 2. 生成带噪声的数据
    x_data = linspace(0, 5, 50);
    p_true = [3, 2]; % 真实参数
    y_data = model_fun(p_true, x_data) + 0.1*randn(size(x_data));
    
    % 3. 提供参数的初始猜测值
    p0 = [1, 1];
    
    % 4. 调用 lsqcurvefit
    p_fit = lsqcurvefit(model_fun, p0, x_data, y_data);
    
    % 5. 绘图比较
    y_fit = model_fun(p_fit, x_data);
    figure;
    plot(x_data, y_data, 'ko', 'DisplayName', '原始数据');
    hold on;
    plot(x_data, y_fit, 'r-', 'LineWidth', 2, 'DisplayName', 'lsqcurvefit 拟合');
    legend;
    title('lsqcurvefit 示例');
    disp('拟合出的参数 [a, lambda]:');
    disp(p_fit);