You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

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

experimental and theoretical graphs

嗨,看你正在做阻尼振动的实验数据拟合,还打算用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

火山引擎 最新活动