实验曲线与理论曲线拟合相关技术咨询(含拟合实现、完美拟合可行性及MSE计算)
实验曲线与理论曲线拟合相关技术咨询(含拟合实现、完美拟合可行性及MSE计算)

嗨,看你正在做阻尼振动的实验数据拟合,还打算用MSE提升精度,我来帮你逐个解答问题,结合你的代码说更清楚~
一、完美拟合真的能做到吗?
先说结论:几乎不可能实现完美拟合。原因很简单:
- 实验数据本身会带有测量误差、环境噪声,不可能完全符合理想的理论模型;
- 我们用的拟合模型(比如你用的阻尼余弦函数)是对真实系统的简化,真实系统可能存在非线性、未考虑的干扰因素,模型本身就和实际情况有偏差。
实际工作中,我们追求的是拟合曲线能准确反映数据的整体趋势,误差在可接受范围内就足够了。
二、怎么提升拟合的贴合度?
结合你的代码,给你几个实用建议:
- 优化初始参数(p0):你在
curve_fit里设置的初始参数p0=[0.12, gamma, 0]可以再优化,比如从实验峰值估算更准确的初始振幅,从衰减速率估算gamma的初始值,让初始值更接近真实解,能帮助拟合算法更快收敛到最优结果; - 确认模型合理性:确保你用的阻尼余弦模型完全匹配你的实验系统,如果实际系统存在非线性阻尼或者其他外力,可能需要调整模型结构;
- 数据预处理再细化:你已经做了偏移修正
y -= 0.2,这很好!另外可以检查数据里有没有异常值(比如偏离趋势过大的点),必要时可以剔除或者给这些点降低权重; - 尝试加权拟合:如果不同时间点的测量精度不一样,可以给
curve_fit传入sigma参数,让精度高的数据点在拟合时占更大权重。
三、MSE(均方误差)的计算方法
你代码里手动计算MSE的逻辑是对的,不过可以用numpy的函数简化成更直观的写法:
mse = np.mean((y - y_t_fit) ** 2)
这个计算和你手动展开的(np.sum(y**2) - 2 * np.sum(y * y_t_fit) + np.sum(y_t_fit**2)) / N结果完全一致,更易读。
MSE的含义就是每个实验数据点和拟合点的差值的平方的平均值,数值越小说明拟合效果越好。
你的拟合实现代码(整理版)
import numpy as np import matplotlib.pyplot as plt import pandas as pd from scipy.signal import find_peaks from scipy.optimize import curve_fit A = 0.12 b = 0.005 m = 1.0 k = 7.0 gamma = b / (2 * m) time = np.array([ 0.000, 0.034, 0.068, 0.101, 0.135, 0.169, 0.203, 0.236, 0.270, 0.304, 0.338, 0.372, 0.405, 0.439, 0.473, 0.507, 0.541, 0.574, 0.608, 0.642, 0.676, 0.709, 0.743, 0.777, 0.811, 0.845, 0.878, 0.912, 0.946, 0.980, 1.013, 1.047, 1.081, 1.115, 1.149, 1.182, 1.216, 1.250, 1.284, 1.317, 1.351, 1.385, 1.419, 1.453, 1.486, 1.520, 1.554, 1.588, 1.622, 1.655, 1.689, 1.723, 1.757, 1.790, 1.824, 1.858, 1.892, 1.926, 1.959, 1.993, 2.027, 2.061, 2.094, 2.128, 2.162, 2.196, 2.230, 2.263, 2.297, 2.331, 2.365, 2.398, 2.432, 2.466, 2.500, 2.534, 2.567, 2.601, 2.635, 2.669, 2.703, 2.736, 2.770, 2.804, 2.838, 2.871, 2.905, 2.939, 2.973, 3.007, 3.040, 3.074, 3.108, 3.142, 3.175, 3.209, 3.243 ]) y = np.array([ 0.309, 0.320, 0.326, 0.325, 0.321, 0.312, 0.299, 0.282, 0.266, 0.249, 0.230, 0.209, 0.187, 0.169, 0.154, 0.138, 0.126, 0.115, 0.107, 0.103, 0.102, 0.107, 0.111, 0.116, 0.128, 0.140, 0.153, 0.165, 0.177, 0.192, 0.203, 0.212, 0.221, 0.228, 0.235, 0.239, 0.239, 0.240, 0.236, 0.231, 0.224, 0.217, 0.210, 0.200, 0.189, 0.181, 0.174, 0.166, 0.159, 0.152, 0.149, 0.146, 0.145, 0.145, 0.147, 0.153, 0.157, 0.162, 0.167, 0.173, 0.180, 0.186, 0.191, 0.196, 0.199, 0.202, 0.205, 0.205, 0.204, 0.203, 0.201, 0.197, 0.193, 0.189, 0.186, 0.182, 0.178, 0.174, 0.171, 0.171, 0.168, 0.166, 0.165, 0.166, 0.166, 0.169, 0.172, 0.175, 0.177, 0.179, 0.182, 0.186, 0.186, 0.188, 0.190, 0.192, 0.192 ]) y -= 0.2 # 偏移修正 peaks, _ = find_peaks(y) periode = np.diff(time[peaks]) print("峰值索引:", peaks) print("峰值时间:", time[peaks]) print("峰值间周期:", periode) print("平均周期:", np.mean(periode)) # 计算阻尼角频率omega_d omega_d = 2 * np.pi / np.mean(periode) # 定义拟合用的阻尼余弦函数 def damped_cosine(t, A_fit, gamma_fit, phi_fit): return A_fit * np.exp(-gamma_fit * t) * np.cos(omega_d * t + phi_fit) # 执行曲线拟合,p0为初始参数猜测 popt, _ = curve_fit(damped_cosine, time, y, p0=[0.12, gamma, 0]) A_fit, gamma_fit, phi_fit = popt # 生成拟合曲线数据 y_t_fit = damped_cosine(time, A_fit, gamma_fit, phi_fit) # 绘图展示 plt.plot(time, y, label="Experiment") plt.plot(time[peaks], y[peaks], "ro", label="Max") plt.plot(time, y_t_fit, label="Fitting", linestyle="dashed") plt.xlabel("time (s)") plt.ylabel("y(t)") plt.title("阻尼振动曲线与拟合结果") plt.legend() plt.grid() plt.show() # 输出拟合参数 print(f"拟合振幅: {A_fit}") print(f"拟合gamma值: {gamma_fit}") print(f"拟合相位: {phi_fit}") # 计算MSE(均方误差) mse = np.mean((y - y_t_fit) ** 2) print(f"均方误差(MSE): {mse}")
备注:内容来源于stack exchange,提问作者Tengga Arlan




