在 ODE 问题中使用复数返回不精确的错误

5 scientific-computing julia differentialequations.jl

我正在尝试使用 Julia 为 n-Machine 系统实现 Swing 方程。当我运行以下代码时,我收到此错误消息:

LoadError: InexactError: Float64(0.0 + 1.0im)
in expression starting at /home/Documents/first_try.jl:61
Swing_Equation(::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Float64) at complex.jl:37
ODEFunction at diffeqfunction.jl:219 [inlined]
initialize!
Run Code Online (Sandbox Code Playgroud)

出现问题是因为我正在使用du[3] = (u[3] * u[2]) * im它不能是一种Float64类型。当我删除im-时代码工作正常,但它不再是我想要实现的模型。

有什么方法可以解决我的问题?

using Plots
using DifferentialEquations
inspectdr()

# Constants
P_m0  = 0.3                      # constant Mechanical Power
P_emax = 1
H = 1.01                         # Inertia constant of the system
?_0 = asin(P_m0 / P_emax)        # angle of the system
?_0 = 1.0                        # initial angular velocity
M = 2 * H / ?_0
D = 0.9                          # Damping constant

u02 = [?_0;?_0]                  # Initial Conditions
tspan = (0.0,100.0)              # Time span to solve for
p = [M;P_m0;D]  
i = 3

function Swing_Equation(du,u,t,p)                # u[1] = angle ?
    du[1] = u[2]                                 # u[2] = angular velocity ?
    P_e = real(u[3] * conj(i))
    du[2] = (1 / M) * ( P_m0 - P_e - D * u[2])   # du[2] = angular acceleration
    du[3] = (u[3] * u[2]) * im
end

# solving the differential equations

prob2 = ODEProblem(Swing_Equation,u0,tspan,p)
print(prob2)
sol2 = solve(prob2)

# Visualizing the solutoins
plot(sol2; vars = 1, label = "?_kura", line = ("red"))
plot!(sol2; vars = 2, label = "?_kura", line = ("blue"))
gui()

plot(sol2,vars = (1,2),label="Kurmamoto" ,line = ("purple"))
xlabel!("?")
ylabel!("?")
gui()
Run Code Online (Sandbox Code Playgroud)

Eri*_*eim 5

问题很可能出在您的输入中。

prob2 = ODEProblem(Swing_Equation,u0,tspan,p)
Run Code Online (Sandbox Code Playgroud)

我猜在这部分你提供了一个Float64for数组u0?你的Swing_Equation然后接收u作为一种Array{Float64}类型。我怀疑这也意味着du是一样的。

这导致表达式

du[3] = (u[3] * u[2]) * im
Run Code Online (Sandbox Code Playgroud)

失败,因为您试图为其分配一个类型为 的Complex{Float64}数字。然后 Julia 将尝试执行一个du[3]Float64

convert(Float64, (u[3] * u[2]) * im)
Run Code Online (Sandbox Code Playgroud)

这将导致不精确错误,因为您无法将复数转换为浮点数。

解决方案是确保duu是复数,以便避免这种转换。解决这个问题的一种快速而肮脏的方法是编写:

prob2 = ODEProblem(Swing_Equation, collect(Complex{Float64}, u0),tspan,p)
Run Code Online (Sandbox Code Playgroud)

这将收集所有元素u0并创建一个新数组,其中每个元素都是Complex{Float64}. 但是,这假设是一维数组。我不知道你的情况。我自己不使用 ODE 求解器。

避免此类问题的一般建议

在您的代码中添加更多类型断言以确保获得您期望的输入类型。这将有助于捕捉这些类型的问题,并使您更容易看到正在发生的事情。

function Swing_Equation(du::AbstractArray{T}, u::AbstractArray{T}, t,p) where T<:Complex               # u[1] = angle ?
    du[1] = u[2] :: Complex{Float64}
    P_e = real(u[3] * conj(i))
    du[2] = (1 / M) * ( P_m0 - P_e - D * u[2])   # du[2] = angular acceleration
    du[3] = (u[3] * u[2]) * im
end
Run Code Online (Sandbox Code Playgroud)

请记住,与其他动态语言相比,Julia 在匹配类型方面要求更高。这就是赋予它性能的原因。

在这种情况下,为什么 Julia 与 Python 不同?

Julia 不会将 Python 之类的类型升级为任何合适的类型。数组是类型化的。它们不能包含 Python 和其他动态语言中的任何内容。例如,如果你创建了一个数组,其中每个元素都是一个整数,那么你不能在没有先显式转换为浮点数的情况下为每个元素分配浮点值。否则 Julia 必须通过抛出异常来警告你你会得到一个不准确的错误。

在 Python 中,这不是问题,因为数组中的每个元素都可以是不同的类型。如果您希望 Julia 数组中的每个元素都是不同的数字类型,那么您必须将数组创建为一种Array{Number}类型,但这些非常低效。

希望有帮助!

  • 感谢埃里克的广泛回答!这解决了我的问题,我现在对在 Julia 中使用类型有了更好的理解! (2认同)
  • 事实上,DifferentialEquations.jl 非常尊重您的类型选择,并且有充分的理由。在某些情况下,定义整数模拟是有意义的(Gillespie-SSA),或者使用 Float32 值(嵌入 ODE 中的神经网络)或任意精度等。因此,我们尊重并使用您设置为“u0”的任何类型作为键入状态。如果你想要它复杂,你就应该让它复杂。这绝对是一种情况,如果我们试图变得太聪明,我们就会破坏很多东西,所以这实际上取决于用户提供适当的输入。 (2认同)