Hi, I am working on a problem where the differential equation \mathbf{x}'(t)=F(\mathbf{x}(t)) admits a periodic solution. For example:
The solution in this case is (x(t),y(t))= (\cos(t),\sin(t)) which has a period of 2\pi. The following code solves the ODE and more importantly, the solution sol
provides a good parametrization of the unit circle.
using DifferentialEquations
f(u,p,t) = [-u[2],u[1]]
tspan= (0.0,2π)
u0=[1.0,0.0]
prob=ODEProblem(f,u0,tspan)
sol=solve(prob,Tsit5(),reltol=1e-8,abstol=1e-8)
using Plots
plot(sol,linewidth=5,idxs=(1,2),label="")
My question: Say we did not know that the period is 2\pi. Is there a way to determine it?
I tried a naive approach (see below) and I was wondering if there is a better way to do it, maybe using DifferentialEquations.jl directly
Naive approach
Solve the ODE on a large interval, then find a solution guess
to \mathbf{x}(t)=\mathbf{x}_0. This solution is a multiple of the period, then we find the largest integer k such that guess/k
is a solution too, which gives us the period
using DifferentialEquations
f(u,p,t) = [-u[2],u[1]]
tspan= (0.0,2π)
u0=[1.0,0.0]
prob=ODEProblem(f,u0,tspan)
sol=solve(prob,Tsit5(),reltol=1e-8,abstol=1e-8)
#naive approach
big_tspan=(0.0,1000.0)
big_prob=ODEProblem(f,u0,big_tspan)
big_sol=solve(big_prob,Tsit5(),reltol=1e-8,abstol=1e-8)
using LinearAlgebra
#g(t)=0 when 𝐱(t)=𝐱(0)
g(t)=norm(big_sol(t)-u0)^2
#g'(t)= 2*sol'(t)*(sol(t)-u0)=2*f(sol(t))* (sol(t)-u0)
#The ODE is autonomous so f(x,p,t)=f(x,0,0)
gp(t)= 2*dot(f(big_sol(t),0.0,0.0), (big_sol(t)-u0))
#Newton's method
guess=big_tspan[2]/2 #initial guess
while norm(g(guess))>1e-8
guess=guess .- g(guess)/gp(guess)
end
#guess is a multiple of the period: guess= period*k (assume k<1000)
k_list=range(1,1000)
possible_periods= guess ./ k_list
k=findlast(g.(possible_periods) .< 1e-8)
period=guess/k
This returns a good approximation of the period: period-2\pi =8e-7
.