You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带振幅与偏移约束的正弦曲线拟合优化及异常排查

Fixing Constrained Sine Curve Fitting Issues

Let's break down what's going wrong with your fitting and fix it step by step:

Core Problems in Your Current Setup

  1. Misunderstanding of Sine Parameter Relationships
    You want the fitted curve's minimum to match your raw data's minimum, and offset c=0—but your constraint logic for amplitude A is inverted. For the function A*sin(wt+phi)+c:

    • When c=0, the curve's minimum is -|A| (if A is positive) or A (if A is negative). Your raw data's minimum is -12.08, so setting A = min(s) (a negative value) forces the curve's minimum to be A (matching your raw data) but makes the curve's maximum -A (~12.08)—way higher than your raw data's max of ~0.9. This is why your fit only matches at the minimum.
  2. Incorrect Constraint Bounds
    Your param_bounds locks A in a narrow negative range around min(s). Since this range is incompatible with your raw data's upper values, the optimizer can't adjust other parameters (like frequency) to fit the rest of the curve.

  3. Missing Variable Assignment
    Your code comments out A, w, phi, c = popt, which would cause errors when calculating f, T, and s_fit.

Corrected Solution

Here's the revised code with fixes for constraints, initial guesses, and optimizer settings:

import matplotlib.pyplot as plt
from matplotlib.ticker import FormatStrFormatter
import numpy as np
from scipy.optimize import curve_fit

# Raw data
t = np.array([313.544, 313.545, 313.546, 313.547, 313.548, 313.549, 313.55, 
              313.551, 313.552, 313.553, 313.554, 313.555, 313.556, 313.557, 
              313.558, 313.559, 313.56, 313.561, 313.562, 313.563, 313.564, 
              313.565, 313.566, 313.567])
s = np.array([0.911188, -0.43135, -1.80997, -3.27816, -4.85784, -6.59428, 
              -8.2214, -9.53617, -10.6892, -11.6003, -12.0844, -12.0524, 
              -11.9749, -11.4891, -10.6131, -9.49873, -8.1154, -6.41442, 
              -5.09357, -3.99165, -2.72991, -1.71446, -0.56306, 0.440741])

# FFT-based frequency guess (this part was correct)
ff = np.fft.fftfreq(len(t), (t[1]-t[0]))
fa = abs(np.fft.fft(s, len(t)))
pos_amax = np.argmax(fa[1:])+1
ff_max = abs(ff[pos_amax])

# Corrected initial guesses
min_s = np.min(s)
A_guess = -min_s  # Amplitude equals absolute value of raw data's minimum
c_guess = 0.0
f_guess = np.array([A_guess, 2*np.pi*ff_max, 0., c_guess])

# Sinusoid function (unchanged)
def sin_func(t, A, w, phi, c):
    return A * np.sin(w*t + phi) + c

# Corrected bounds: lock A to |min_s|, lock c to near 0
tolerance = 1e-6
param_bounds = (
    [A_guess - tolerance, -np.inf, -np.inf, -tolerance],
    [A_guess + tolerance, np.inf, np.inf, tolerance]
)

# Use TRF method for better constraint handling
popt, pcov = curve_fit(
    sin_func, t, s, 
    p0=f_guess, 
    bounds=param_bounds, 
    maxfev=10000000,
    method='trf'
)

# Assign fitted parameters
A, w, phi, c = popt
f = w/(2.*np.pi)
T = 1000/f

# Generate fitted curve
s_fit = A * np.sin(w*t + phi) + c

# Plotting
plt.rcParams['figure.figsize'] =10, 5
fig, ax = plt.subplots()
plt.plot(t, s, "b", label="Original Data")
plt.plot(t, s_fit, 'k--', label="Constrained Fit")

ax.set(xlabel='Time', ylabel='Amplitude')
ax.xaxis.set_major_formatter(FormatStrFormatter('%.2f'))
ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))
ax.grid()

# Add fit info
ausgabe = ("Sinus-Fit Results \nAmplitude = {:.2f} \nPeriod = {:.2f} ms \nOffset = {:.4f}".format(A, abs(T), c))
plt.text(0.795, 0.7, ausgabe, family="sans-serif", fontsize=10, ha='left', va='top', transform=fig.transFigure)

# Adjust plot position to fit text
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.85, box.height])

plt.legend()
plt.show()

Key Improvements

  1. Fixed Constraint Logic
    We now lock A to the absolute value of your raw data's minimum, so the fitted curve's minimum (-A + c) matches min(s) when c≈0. This aligns the curve's amplitude with your data's range.

  2. Better Optimizer Choice
    Using method='trf' (trust-region-reflective algorithm) instead of the default lm (Levenberg-Marquardt) gives more stable results when handling strict boundary constraints.

  3. Corrected Initial Guess
    Setting A_guess = -min(s) gives the optimizer a starting point that aligns with your constraints, preventing it from getting stuck in invalid parameter ranges.

Additional Notes

If you truly meant "amplitude equals raw data's minimum" (a negative value, which is non-standard), you'll need to re-evaluate your constraint's validity—it will force the curve's maximum to be much higher than your raw data, making a good fit impossible. The solution above assumes you wanted the fitted curve's minimum to match your raw data's minimum (a much more common use case).

内容的提问来源于stack exchange,提问作者smi242

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 20:19:07