【发布时间】:2018-06-07 18:50:23
【问题描述】:
我试图在海洋模型中描述 70 年代核试验引起的碳同位素扩散。 大气信号是一个强烈的尖峰信号,它会随着洋流被带到深处(更深的水流要慢得多)。
我的目标是检测浓度上升的开始和不同深度水平的上升速度。
我假设海洋中碳同位素的浓度表现为具有 3 段的分段线性函数:
- 一个恒定的初始值 (
b) 直到时间 (t_0) - 浓度随时间 (
t_0) 到 (t_1) 的线性增加,速率为m1。 - 浓度随时间线性下降 (
t_1),速率为m2
我在 python 中使用这段代码来表示函数:
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as sio
def piecewise_linear( t, t0, t1, b, m1, m2 ):
condlist = [ t < t0,
(t >= t0 ) & ( t < t1 ),
t >= t1
]
funclist = [lambda t: b,
lambda t: b + m1 * ( t - t0 ),
lambda t: b + m1 * ( t - t0 ) + m2 * ( t - t1 )
]
return np.piecewise( t, condlist, funclist )
对于给定的时间数组t,我希望能够适应此函数的两种“类型”:
- 完整的 3 段线,代表上层海洋,信号在此快速传播,尖峰被完全捕获。
- 一种特殊情况,在时间序列结束时浓度尚未达到峰值(这表示深海中的信号,需要很长时间才能传播信号)
举例
t = np.arange( 0, 15, 0.1 )
y_full = piecewise_linear( t, 5, 10, 2, 2, -4 )
y_cut = piecewise_linear( t, 5, 15, 2, 2, -4 )
plt.plot( t, y_full )
plt.plot( t, y_cut )
plt.legend( [ 'surface', 'deep ocean' ] )
对于第一种情况,当我在添加一些随机噪声后尝试将函数拟合到信号时,我得到了很好的结果:
noise = np.random.normal( 0, 1, len( y_full ) ) * 1
y = y_full
yy = y_full + noise
bounds = ( [ 0, 0, 0, 0, -np.inf ], [ np.inf, np.inf, np.inf, np.inf, 0 ] )
fit,_ = sio.curve_fit( piecewise_linear, t, yy, bounds=bounds )
print( fit )
y_fit = piecewise_linear( t, *tuple( fit ) )
plt.plot( t, yy, color='0.5' )
plt.plot( t, y_fit, linewidth=3 )
plt.plot( t, y, linestyle='--', linewidth=3 )
结果
>>[ 5.00001407 10.01945313 2.13055863 1.95208167 -3.95199719]
但是,当我尝试评估第二种情况(深海)时,我经常得到如下糟糕的结果:
noise = np.random.normal( 0, 1, len(y_full ) ) * 1#
y = y_cut
yy = y_cut+noise
bounds = ( [ 0, 0, 0, 0, -np.inf], [ np.inf, np.inf, np.inf, np.inf, 0 ] )
fit,_ = sio.curve_fit( piecewise_linear, t, yy, bounds=bounds )
print( fit )
y_fit = piecewise_linear( t, *tuple( fit ) )
plt.plot( t, yy, color='0.5' )
plt.plot( t, y_fit, linewidth=3 )
plt.plot( t, y, linestyle='--', linewidth=3 )
plt.legend( [ 'noisy data', 'fit', 'original' ] )
我明白了
>>[ 1.83838997 0.40000014 1.51810839 2.56982348 -1.0622842 ]
优化确定t_0大于t_1,这在这种情况下是没有意义的。
有没有办法将条件t_0 < t_1 构建到曲线拟合中?还是我必须测试,给出哪种类型的曲线,然后拟合两个不同的函数(3 段或 2 段分段线性函数)?
非常感谢任何帮助
【问题讨论】:
-
您可以快速测试一堵“砖墙”,如果找到给定条件,例如 t_0 > t_1,那么拟合函数会返回一个非常大的值 - 因此是一个非常大的错误。这种方法有些粗略,但通常作为一个实际问题起作用,并且具有易于编码和易于测试的优点。
-
... 或者,您可以更改参数化以便始终满足约束。
标签: python scipy curve-fitting