首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在朱莉娅中使用DifferentialEquations.jl处理不规则时间序列时,如何设置时间步长?

在朱莉娅中使用DifferentialEquations.jl处理不规则时间序列时,如何设置时间步长?
EN

Stack Overflow用户
提问于 2022-10-20 12:45:37
回答 1查看 152关注 0票数 1

利用谐振子的作用,在毫秒范围内由一个规则的时间序列w_i驱动微分方程。

代码语言:javascript
复制
ζ = 1/4pi                                           # damped ratio

function oscillator!(du,u,p,t)

      
           du[1] = u[2]                             # y'(t) = z(t)
           du[2] = -2*ζ*p(t)*u[2] - p(t)^2*u[1]     # z'(t) = -2ζw(t)z(t) -w(t)^2y(t)
       end
y0 = 0.0                                            # initial position
z0 = 0.0002                                         # initial speed
u0 = [y0, z0]                                       # initial state vector
tspan = (0.0,10)                                    # time interval

dt = 0.001                                          # timestep

w = t -> freq[Int(floor(t/dt))+1]                   # time series

prob = ODEProblem(oscillator!,u0,tspan,w)           # define ODEProblem

sol = solve(prob,DP5(),adaptive=false,dt=0.001)

当参数w_i是毫秒范围内的不规则时间序列时,如何设置时间步长。

代码语言:javascript
复制
date                    │  w  
────────────────────────┼───────
2022-09-26T00:00:00.023 │  4.3354
2022-09-26T00:00:00.125 │  2.34225
2022-09-26T00:00:00.383 │ -2.0312
2022-09-26T00:00:00.587 │ -0.280142 
2022-09-26T00:00:00.590 │  6.28319
2022-09-26T00:00:00.802 │  9.82271
2022-09-26T00:00:00.906 │ -5.21289
....................... |  ........
EN

回答 1

Stack Overflow用户

发布于 2022-10-20 22:48:12

虽然可以禁用自适应,即使可以强制任意步长,但这通常不是您想要做的,因为它极大地限制了解决方案的准确性。

相反,将参数内插,使其接受任何t值。幸运的是,这样做真的很简单!

代码语言:javascript
复制
using Interpolations

...

ts = [0, 0.1, 0.4, 1.0]
ws = [1.0, 2.0, 3.0, 4.0]
w = linear_interpolation(ts, ws)
tspan = first(ts), last(ts)

prob = ODEProblem(oscillator!, u0, tspan, w)
sol = solve(prob, DP5(), dt=0.001)

当然,它不需要是线性插值。

如果仍然需要在特定时间点保存解决方案,请查看saveat for solve。例如,使用插值中使用的ts保存解决方案:

代码语言:javascript
复制
sol = solve(prob, DP5(), dt=0.001, saveat=ts)

编辑:跟进评论:

从数学上讲,你总是对整个领域的w(t)做一些假设。没有“由时间序列驱动”这样的说法。

例如,您在这里选择的标准Runge方法将要求ODE函数位于h/2。为了获得更好的DP5(),将在更多的子步骤中对其进行评估。这当然是不可避免的,不管是否使用适应性。尝试将println(t)添加到ODE函数中,您将看到以下内容。

如果有人来自matlab的ode45,而不是说它仍然简单地使用自适应,而只是像saveat那样处理显式的时间步骤。当然,它还将在显式步骤之外的各种t上评估函数。

因此,即使在第一个示例中,也是在插值w。您正在制造一种奇怪的constant_interpolation类型(但是使用floor,它与浮点数相结合会引起其他问题,因为floor(n*dt/dt)可能会评估为nn-1)。

即使您要选择一种只在预定时间步骤(例如ExplicitEuler() )尝试计算的方法,您仍然在隐含地做出相同的假设,即w(t)在下一个时间步骤之前是常数。只是现在,您还从ODE集成中得到了一个更糟糕的解决方案。

如果前面的常量类型插值确实是在整个域中定义w(t)的方式(这就是您在floor(t/dt)中所做的),那么我们所拥有的是:

代码语言:javascript
复制
w = extrapolate(interpolate((ts,), ws, Gridded(Constant{Previous}())), Flat())

在数学上,我们根本不可能忽略整个时间步骤发生的事情,也没有理由将时间限制在我们的"load“函数的样本点上。这在任何数学意义上都是不自然的。u'(t)必须在我们集成的整个域上定义。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74140122

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档