MATLAB中如何调整现有拟合函数使其通过指定两点并保留原有形状
问题描述
假设我已有一个通过某数据集拟合得到的函数,我希望让该函数经过当前未穿过的两个不同点,同时函数其余部分适配这一改动并保留原有形态,效果示意如下:
我当前使用的是含11个系数的有理拟合(分子为5次多项式共6个系数,分母为5次多项式,最高次项系数固定为1,剩余5个自由系数)。如果有助于实现需求,我也可以更换拟合类型(多项式、正弦和等)。
我曾尝试随机修改两个系数来强制函数匹配两个新点,但得到的结果不符合预期。
当前我的拟合结果如下:

以下是通过Matlab cftool对Excel数据集进行有理拟合得到的代码:
p1 = 0.09503; p2 = 0.8033; p3 = 2.654; p4 = 4.375; p5 = 3.691; p6 = 1.221; q1 = 6.399; q2 = 21.65; q3 = 34.98; q4 = 29.02; q5 = 9.704; m = (x - 0.9857)./0.1235; y = (p1*m.^5 + p2*m.^4 + p3*m.^3 + p4*m.^2 + p5*m + p6) ./ (m.^5 + q1*m.^4 + q2*m.^3 + q3*m.^2 + q4*m + q5);
我需要让该函数经过(0.78, 0.002)和(1.05473536553, 9.869964329717e-2)两个点,同时保留原有形状。
解决方案
方法1:带约束的最小二乘重拟合(推荐,适配原有有理拟合形式)
你当前的有理函数共有11个自由参数,仅增加2个等式约束后仍有9个自由度,足够完整保留原始拟合的形态。
操作步骤:
- 先将两个目标点转换为归一化
m坐标:- 点1:
x=0.78,计算得m1 = (0.78-0.9857)/0.1235 ≈ -1.6656,目标y值为0.002 - 点2:
x=1.05473536553,计算得m2 = (1.05473536553-0.9857)/0.1235 ≈ 0.559,目标y值为0.0987
- 点1:
- 写出两个约束方程,形式为
分子(m_i) - y_i * 分母(m_i) = 0, i=1,2 - 将原始数据集、两个目标点(可给目标点设置10~100倍的高权重,保证强制穿过)代入带线性约束的最小二乘求解,直接得到新的p、q参数。
Matlab示例代码片段:
% 假设原始的x、y数据存在变量x_raw、y_raw里 m_raw = (x_raw - 0.9857)./0.1235; % 构造最小二乘系数矩阵C和目标向量d C = [m_raw.^5, m_raw.^4, m_raw.^3, m_raw.^2, m_raw, ones(size(m_raw)), ... -y_raw.*m_raw.^4, -y_raw.*m_raw.^3, -y_raw.*m_raw.^2, -y_raw.*m_raw, -y_raw]; d = y_raw.*m_raw.^5; % 定义约束矩阵A和b,满足A*params = b m1 = (0.78-0.9857)/0.1235; y1 = 0.002; m2 = (1.05473536553-0.9857)/0.1235; y2 = 9.869964329717e-2; A = [m1^5, m1^4, m1^3, m1^2, m1, 1, -y1*m1^4, -y1*m1^3, -y1*m1^2, -y1*m1, -y1; m2^5, m2^4, m2^3, m2^2, m2, 1, -y2*m2^4, -y2*m2^3, -y2*m2^2, -y2*m2, -y2]; b = [y1*m1^5; y2*m2^5]; % 用原始参数作为初始值,调用lsqlin求解 params0 = [0.09503,0.8033,2.654,4.375,3.691,1.221,6.399,21.65,34.98,29.02,9.704]; params = lsqlin(C,d,A,b,[],[],[],[],params0); % 提取新参数 p1_new = params(1); p2_new = params(2); p3_new = params(3); p4_new = params(4); p5_new = params(5); p6_new = params(6); q1_new = params(7); q2_new = params(8); q3_new = params(9); q4_new = params(10); q5_new = params(11);
方法2:低阶校正项适配(无需重拟合,改动最小)
如果不想修改原始拟合参数,可以在原始函数基础上叠加一个二阶校正项,保证校正项仅在目标点处补全差值,其余区域几乎无影响:
% 定义原始拟合函数 y0 = @(x) (p1*((x-0.9857)/0.1235).^5 + p2*((x-0.9857)/0.1235).^4 + p3*((x-0.9857)/0.1235).^3 + p4*((x-0.9857)/0.1235).^2 + p5*((x-0.9857)/0.1235) + p6) ./ (((x-0.9857)/0.1235).^5 + q1*((x-0.9857)/0.1235).^4 + q2*((x-0.9857)/0.1235).^3 + q3*((x-0.9857)/0.1235).^2 + q4*((x-0.9857)/0.1235) + q5); % 计算两个点的差值 x1 = 0.78; y1_target = 0.002; delta1 = y1_target - y0(x1); x2 = 1.05473536553; y2_target = 9.869964329717e-2; delta2 = y2_target - y0(x2); % 构造线性校正项,仅在两个目标点处有补偿 delta_y = @(x) delta1.*(x-x2)./(x1-x2) + delta2.*(x-x1)./(x2-x1); % 最终函数 y = @(x) y0(x) + delta_y(x);
内容的提问来源于stack exchange,提问作者stevederekson555
相关产品推荐
相关产品推荐

