diff --git a/flows.jl b/flows.jl new file mode 100644 index 0000000000000000000000000000000000000000..d785a113fc15371e6161dbf6ba06c7ded1db7203 --- /dev/null +++ b/flows.jl @@ -0,0 +1,562 @@ +using ForwardDiff +using OrdinaryDiffEq +#using DifferentialEquations + +# Alias for gradient and jacobian +grad(f, x) = ForwardDiff.gradient(f, x) +jac(f, x) = ForwardDiff.jacobian(f, x); + +# types of controls +@enum CONTROL umin=1 umax=2 usingular=3 uboundary=4 #uregular=5 + +# -------------------------------------------------------------------------------------------- +# Default options for flows +# -------------------------------------------------------------------------------------------- +function __abstol() + return 1e-10 +end + +function __reltol() + return 1e-10 +end + +function __saveat() + return [] +end + +# -------------------------------------------------------------------------------------------- +# Hamiltonian +# -------------------------------------------------------------------------------------------- +struct Hamiltonian f::Function end + +function (h::Hamiltonian)(x, p) # https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects + return h.f(x,p) +end + +# Flow from a Hamiltonian +function Flow(h::Hamiltonian) + + function rhs!(dz, z, dummy, t) + n = size(z, 1)÷2 + foo = z -> h(z[1:n], z[n+1:2*n]) + dh = grad(foo, z) + dz[1:n] = dh[n+1:2n] + dz[n+1:2n] = -dh[1:n] + end + + function f(tspan, x0, p0; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + z0 = [ x0 ; p0 ] + ode = ODEProblem(rhs!, z0, tspan) + sol = solve(ode, Tsit5(), abstol=abstol, reltol=reltol, saveat=saveat) + return sol + end + + function f(t0, x0, p0, tf; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + sol = f((t0, tf), x0, p0, abstol=abstol, reltol=reltol, saveat=saveat) + n = size(x0, 1) + return sol[1:n, end], sol[n+1:2*n, end] + end + + return f + +end; + +# -------------------------------------------------------------------------------------------- +# +# Single input and affine Mayer system +# +# -------------------------------------------------------------------------------------------- +struct SIMayer + f₀::Function + f₁::Function + control_bounds::Tuple{Number, Number} + constraint::Union{Function, Nothing} +end + +function __vector_fields(ocp::SIMayer) + f₀ = ocp.f₀ + f₁ = ocp.f₁ + return f₀, f₁ +end + +function __hamiltonian_lifts(ocp::SIMayer) + f₀ = ocp.f₀ + f₁ = ocp.f₁ + h₀(x, p) = p'*f₀(x) + h₁(x, p) = p'*f₁(x) + return h₀, h₁ +end + +function __min_control(ocp::SIMayer) + u(x, p) = ocp.control_bounds[1] +end + +function __max_control(ocp::SIMayer) + u(x, p) = ocp.control_bounds[2] +end + +function __singular_control(ocp::SIMayer) + + h₀, h₁ = __hamiltonian_lifts(ocp) + H₀₁ = Poisson(h₀, h₁) + H₀₀₁ = Poisson(h₀, H₀₁) + H₁₀₁ = Poisson(h₁, H₀₁) + us(x, p) = -H₀₀₁(x, p)/H₁₀₁(x, p) + + return us + +end + +function __boundary_control(ocp::SIMayer) + + f₀, f₁ = __vector_fields(ocp) + g = ocp.constraint + ub(x) = -Lie(f₀, g)(x) / Lie(f₁, g)(x) + + return ub + +end + +function __boundary_multiplier(ocp::SIMayer) + + f₀ = ocp.f₀ + f₁ = ocp.f₁ + h₀, h₁ = __hamiltonian_lifts(ocp) + H₀₁ = Poisson(h₀, h₁) + g = ocp.constraint + μb(x, p) = H₀₁(x, p) / Lie(f₁, g)(x) + + return μb + +end + +#function __gradient_constrain(ocp::SIMayer) +# g = ocp.constraint +# ∇g(x) = grad(g, x) +# return ∇g +#end + +function __hamiltonian_min(ocp::SIMayer) + h₀, h₁ = __hamiltonian_lifts(ocp) + u = __min_control(ocp) + h(x, p) = h₀(x, p) + u(x, p) * h₁(x, p) + return h +end + +function __hamiltonian_max(ocp::SIMayer) + h₀, h₁ = __hamiltonian_lifts(ocp) + u = __max_control(ocp) + h(x, p) = h₀(x, p) + u(x, p) * h₁(x, p) + return h +end + +function __hamiltonian_sing(ocp::SIMayer) + h₀, h₁ = __hamiltonian_lifts(ocp) + us = __singular_control(ocp) + h(x, p) = h₀(x, p) + us(x, p) * h₁(x, p) + return h +end + +function __hamiltonian_bound(ocp::SIMayer) + h₀, h₁ = __hamiltonian_lifts(ocp) + ub = __boundary_control(ocp) + μb = __boundary_multiplier(ocp) + g = ocp.constraint + h(x, p) = h₀(x, p) + ub(x) * h₁(x, p) + μb(x,p)*g(x) + return h +end + +function Hamiltonian(ocp::SIMayer, control::CONTROL) + if control==usingular + return Hamiltonian(__hamiltonian_sing(ocp)) + elseif control==umin + return Hamiltonian(__hamiltonian_min(ocp)) + elseif control==umax + return Hamiltonian(__hamiltonian_max(ocp)) + elseif control==uboundary + return Hamiltonian(__hamiltonian_bound(ocp)) + else + nothing + end +end; + +function Control(ocp::SIMayer, control::CONTROL) + if control==usingular + return __singular_control(ocp) + elseif control==umin + return __min_control(ocp) + elseif control==umax + return __max_control(ocp) + elseif control==uboundary + return __boundary_control(ocp) + else + nothing + end +end; + +function Multiplier(ocp::SIMayer) + return __boundary_multiplier(ocp) +end; + +# -------------------------------------------------------------------------------------------- +# +# Hamiltonian Vector Field +# +# -------------------------------------------------------------------------------------------- +struct HamiltonianVectorField f::Function end + +function (hv::HamiltonianVectorField)(x, p) # https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects + return hv.f(x,p) +end + +# Fonction permettant de calculer le flot d'un système hamiltonien +function Flow(hv::HamiltonianVectorField) + + function rhs!(dz, z, dummy, t) + n = size(z, 1)÷2 + dz[:] = hv(z[1:n], z[n+1:2*n]) + end + + function f(tspan, x0, p0; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + z0 = [ x0 ; p0 ] + ode = ODEProblem(rhs!, z0, tspan) + sol = solve(ode, Tsit5(), abstol=abstol, reltol=reltol, saveat=saveat) + return sol + end + + function f(t0, x0, p0, t; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + sol = f((t0, t), x0, p0; abstol=abstol, reltol=reltol, saveat=saveat) + n = size(x0, 1) + return sol[1:n, end], sol[n+1:2*n, end] + end + + return f + +end; + +# -------------------------------------------------------------------------------------------- +# +# Vector Field +# +# -------------------------------------------------------------------------------------------- +struct VectorField f::Function end + +function (vf::VectorField)(x) # https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects + return vf.f(x) +end + +# Flow of a vector field +function Flow(vf::VectorField) + + function rhs!(dx, x, dummy, t) + dx[:] = vf(x) + end + + function f(tspan, x0; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + ode = ODEProblem(rhs!, x0, tspan) + sol = solve(ode, Tsit5(), abstol=abstol, reltol=reltol, saveat=saveat) + return sol + end + + function f(t0, x0, t; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + sol = f((t0, t), x0; abstol=abstol, reltol=reltol, saveat=saveat) + n = size(x0, 1) + return sol[1:n, end] + end + + return f + +end; + +# -------------------------------------------------------------------------------------------- +# +# Pseudo Hamiltonian +# +# -------------------------------------------------------------------------------------------- +struct PseudoHamiltonian f::Function end + +function (h::PseudoHamiltonian)(x, p, u) # https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects + return h.f(x, p, u) +end + +function (h::PseudoHamiltonian)(x, p, p⁰, u) + return h.f(x, p, p⁰, u) +end + +# Flow from a pseudo-Hamiltonian +function Flow(H::PseudoHamiltonian; p⁰::Number=Inf) + + if p⁰==Inf + h = H.f + else + h(x, p, u) = H.f(x, p, p⁰, u) + end + + function ∂h∂z(z, u) + n = size(z, 1)÷2 + foo(z) = h(z[1:n], z[n+1:2*n], u) + return grad(foo, z) + end + + function ∂h∂u(z, u) + n = size(z, 1)÷2 + foo(u) = h(z[1:n], z[n+1:2*n], u) + return grad(foo, u) + end + + ∂h∂u(x, p, u) = ∂h∂u([x; p], u) + + ∂²h∂u²(z, u) = jac(u->∂h∂u(z, u), u) + ∂²h∂z∂u(z, u) = jac(u->∂h∂z(z, u), u) + + function rhs!(dw, w, λ, t) + # w = (z, u) = (x, p, u) + n, m = λ + z = w[1:2n] + u = w[2n+1:2n+m] + dh = ∂h∂z(z, u) + hv = [dh[n+1:2n]; -dh[1:n]] + dw[1:2n] = hv + dw[2n+1:2n+m] = -∂²h∂u²(z, u)\(∂²h∂z∂u(z, u)'*hv) + end + + function f(tspan, x0, p0, u0; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + w0 = [ x0 ; p0; u0 ] + λ = [size(x0, 1), size(u0, 1)] + ode = ODEProblem(rhs!, w0, tspan, λ) + sol = solve(ode, Tsit5(), abstol=abstol, reltol=reltol, saveat=saveat) + return sol + end + + function f(t0, x0, p0, u0, tf; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + sol = f((t0, tf), x0, p0, u0, abstol=abstol, reltol=reltol, saveat=saveat) + n = size(x0, 1) + return sol[1:n, end], sol[n+1:2n, end], sol[2n+1:end, end] + end + + return f, ∂h∂u + +end; + +# -------------------------------------------------------------------------------------------- +# +# Mayer +# +# -------------------------------------------------------------------------------------------- +struct Mayer f::Function end + +# Flow from Mayer system +Flow(Σu::Mayer) = Flow(PseudoHamiltonian((x, p, u) -> p'*Σu.f(x,u))); + +# -------------------------------------------------------------------------------------------- +# +# Lagrange +# +# -------------------------------------------------------------------------------------------- +struct Lagrange + f::Function + f⁰::Function +end + +# Flow from Lagrange system +Flow(Σu::Lagrange, p⁰::Number=-1.0) = Flow(PseudoHamiltonian((x, p, p⁰, u) -> p⁰*Σu.f⁰(x,u)+p'*Σu.f(x,u)), p⁰=p⁰); + +# -------------------------------------------------------------------------------------------- +# +# SIMayer +# +# -------------------------------------------------------------------------------------------- +function __flow(rhs!, tspan, x0, p0; abstol, reltol, saveat) + z0 = [ x0 ; p0 ] + n = size(x0, 1) + ode = ODEProblem(rhs!, z0, tspan, n) + sol = solve(ode, Tsit5(), abstol=abstol, reltol=reltol, saveat=saveat) + return sol +end + +function __flow(rhs!, t0, x0, p0, tf; abstol, reltol, saveat) + sol = __flow(rhs!, (t0, tf), x0, p0, abstol=abstol, reltol=reltol, saveat=saveat) + n = size(x0, 1) + return sol[1:n, end], sol[n+1:2n, end] +end + +function __dh(ocp::SIMayer) + + f₀ = ocp.f₀ + f₁ = ocp.f₁ + h₀(x, p) = p'*f₀(x) + h₁(x, p) = p'*f₁(x) + + function dh₀(x, p) + n = size(x, 1) + foo(z) = h₀(z[1:n], z[n+1:2n]) + return grad(foo, [x; p]) + end + + function dh₁(x, p) + n = size(x, 1) + foo(z) = h₁(z[1:n], z[n+1:2n]) + return grad(foo, [x; p]) + end + + return dh₀, dh₁ + +end + +function __FlowMIN(ocp::SIMayer) + + u_bounds = ocp.control_bounds + dh₀, dh₁ = __dh(ocp) + + function rhs!(dz, z, n, t) + x = z[1:n] + p = z[n+1:2n] + u = u_bounds[1] + dh0 = dh₀(x, p) + dh1 = dh₁(x, p) + hv0 = [dh0[n+1:2n]; -dh0[1:n]] + hv1 = [dh1[n+1:2n]; -dh1[1:n]] + dz[1:2n] = hv0 + u*hv1 + end + + function f(tspan, x0, p0; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + return __flow(rhs!, tspan, x0, p0, abstol=abstol, reltol=reltol, saveat=saveat) + end + + function f(t0, x0, p0, tf; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + return __flow(rhs!, t0, x0, p0, tf, abstol=abstol, reltol=reltol, saveat=saveat) + end + + return f + +end; + +function __FlowMAX(ocp::SIMayer) + + u_bounds = ocp.control_bounds + dh₀, dh₁ = __dh(ocp) + + function rhs!(dz, z, n, t) + x = z[1:n] + p = z[n+1:2n] + u = u_bounds[2] + dh0 = dh₀(x, p) + dh1 = dh₁(x, p) + hv0 = [dh0[n+1:2n]; -dh0[1:n]] + hv1 = [dh1[n+1:2n]; -dh1[1:n]] + dz[1:2n] = hv0 + u*hv1 + end + + function f(tspan, x0, p0; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + return __flow(rhs!, tspan, x0, p0, abstol=abstol, reltol=reltol, saveat=saveat) + end + + function f(t0, x0, p0, tf; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + return __flow(rhs!, t0, x0, p0, tf, abstol=abstol, reltol=reltol, saveat=saveat) + end + + return f + +end; + +function __us(ocp::SIMayer) + + f₀ = ocp.f₀ + f₁ = ocp.f₁ + h₀(x, p) = p'*f₀(x) + h₁(x, p) = p'*f₁(x) + + # singular control + H₀₁ = Poisson(h₀, h₁) + H₀₀₁ = Poisson(h₀, H₀₁) + H₁₀₁ = Poisson(h₁, H₀₁) + us(x, p) = -H₀₀₁(x, p)/H₁₀₁(x, p) + + return us + +end + +function __FlowSING(ocp::SIMayer) + + dh₀, dh₁ = __dh(ocp) + us = __us(ocp) + + function rhs!(dz, z, n, t) + x = z[1:n] + p = z[n+1:2n] + u = us(x, p) + dh0 = dh₀(x, p) + dh1 = dh₁(x, p) + hv0 = [dh0[n+1:2n]; -dh0[1:n]] + hv1 = [dh1[n+1:2n]; -dh1[1:n]] + dz[1:2n] = hv0 + u*hv1 + end + + function f(tspan, x0, p0; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + return __flow(rhs!, tspan, x0, p0, abstol=abstol, reltol=reltol, saveat=saveat) + end + + function f(t0, x0, p0, tf; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + return __flow(rhs!, t0, x0, p0, tf, abstol=abstol, reltol=reltol, saveat=saveat) + end + + return f, us + +end; + +function __u_μ_boundary(ocp::SIMayer) + f₀ = ocp.f₀ + f₁ = ocp.f₁ + h₀(x, p) = p'*f₀(x) + h₁(x, p) = p'*f₁(x) + H₀₁ = Poisson(h₀, h₁) + g = ocp.constraint + ub(x) = -Lie(f₀, g)(x) / Lie(f₁, g)(x) + μb(x, p) = H₀₁(x, p) / Lie(f₁, g)(x) + ∇g(x) = grad(g, x) + return ub, μb, ∇g +end + +function __FlowBOUND(ocp::SIMayer) + + dh₀, dh₁ = __dh(ocp) + ub, μb, ∇g = __u_μ_boundary(ocp) + + function rhs!(dz, z, n, t) + x = z[1:n] + p = z[n+1:2n] + u = ub(x) + μ = μb(x, p) + dh0 = dh₀(x, p) + dh1 = dh₁(x, p) + hv0 = [dh0[n+1:2n]; -dh0[1:n]] + hv1 = [dh1[n+1:2n]; -dh1[1:n]] + dz[1:2n] = hv0 + u*hv1 + dz[n+1:2n] = dz[n+1:2n] - μ*∇g(x) + end + + function f(tspan, x0, p0; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + return __flow(rhs!, tspan, x0, p0, abstol=abstol, reltol=reltol, saveat=saveat) + end + + function f(t0, x0, p0, tf; abstol=__abstol(), reltol=__reltol(), saveat=__saveat()) + return __flow(rhs!, t0, x0, p0, tf, abstol=abstol, reltol=reltol, saveat=saveat) + end + + return f, ub, μb + +end; + +function Flow(ocp::SIMayer, control::CONTROL) + if control==usingular + return __FlowSING(ocp) + elseif control==umin + return __FlowMIN(ocp) + elseif control==umax + return __FlowMAX(ocp) + elseif control==uboundary + return __FlowBOUND(ocp) + else + nothing + end +end; diff --git a/minimum-time-orbital-transfer.ipynb b/minimum-time-orbital-transfer.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..dee2087226353838fc0850817928ba04999a8611 --- /dev/null +++ b/minimum-time-orbital-transfer.ipynb @@ -0,0 +1,803 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "baa07c4f-8a11-49d2-b052-e64d34594294", + "metadata": {}, + "source": [ + "# Orbital transfer in minimum time\n", + "\n", + "* Author: Olivier Cots\n", + "* Date: 05/06/2022\n", + "* For the \"Maison de Fermat\"" + ] + }, + { + "cell_type": "markdown", + "id": "b32c3c7c-dcc2-4dd9-9143-b4daf05f1c88", + "metadata": {}, + "source": [ + "We consider the orbital transfer in minimum time of a satellite around the Earth, \n", + "from an initial elliptic orbit to a circular target orbit.\n", + "This optimal control problem can be written in the form\n", + "\n", + "$$\n", + "\\left\\lbrace\n", + "\\begin{array}{l}\n", + " \\min J(x, u, t_f) = t_f \\\\[1.0em]\n", + " \\ \\ \\dot{x}_{1}(t) = ~ x_{3}(t) \\\\\n", + " \\ \\ \\dot{x}_{2}(t) = ~ x_{4}(t) \\\\\n", + " \\ \\ \\dot{x}_{3}(t) = -\\dfrac{\\mu\\, x_{1}(t)}{r^{3}(t)} + u_{1}(t) \\\\\n", + " \\ \\ \\dot{x}_{4}(t) = -\\dfrac{\\mu\\, x_{2}(t)}{r^{3}(t)}+u_{2}(t), ~~ ||u(t)|| \\leq \\gamma_\\mathrm{max}, ~~ t \\in [0,t_f] ~~ \\text{a. e}, ~~ u(t) = (u_1(t),u_2(t)), \\\\[1.0em]\n", + " \\ \\ x_{1}(0)=x_{0,1}, ~~ x_{2}(0)=x_{0,2}, ~~ x_{3}(0)=x_{0,3}, ~~ x_{4}(0)=x_{0,4}, \\\\\n", + " \\ \\ r^2(t_f) = r_{f}^2, ~~ x_{3}(t_f)=-\\sqrt{\\dfrac{\\mu}{r_{f}^{3}}}x_{2}(t_f), ~~ x_{4} (t_f)= \\sqrt{\\dfrac{\\mu}{r_{f}^{3}}}x_{1}(t_f), \\\\\n", + "\\end{array}\n", + "\\right.\n", + "$$\n", + "\n", + "where $r(t)=\\sqrt{x_{1}^{2}(t)+x_{2}^{2}(t)}$.\n", + "The chosen units are the kilometer for distances et the hour for the times. We set the following parameters:\n", + " \n", + "$$\n", + "\\mu=5.1658620912 \\times 10^{12} \\ \\mathrm{km}^{3}.\\mathrm{h}^{-2}, \\quad r_{f} = 42165 \\ \\mathrm{km}.\n", + "$$\n", + "\n", + "The parameter $\\gamma_\\mathrm{max}$ depends on the maximal thrust $F_\\mathrm{max}$ according to\n", + "\n", + "$$\n", + "\\gamma_\\mathrm{max} = \\frac{F_\\mathrm{max}\\times 3600^2}{m} \n", + "$$\n", + "\n", + "where $m$ is the mass of the satellite that we fix to $m=2000\\ \\mathrm{kg}$." + ] + }, + { + "cell_type": "markdown", + "id": "a552de56-944a-412b-97b4-a71c52123786", + "metadata": {}, + "source": [ + "## Packages" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "104fc457-beaa-4783-8ce2-bb32ff0ab9e3", + "metadata": {}, + "outputs": [], + "source": [ + "using MINPACK # fsolve\n", + "using LinearAlgebra # norm" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0995cf52-227b-4c1f-88cd-ec3f6bcde259", + "metadata": {}, + "outputs": [], + "source": [ + "include(\"flows.jl\");\n", + "include(\"plottings.jl\");" + ] + }, + { + "cell_type": "markdown", + "id": "9b5d4e41-f03e-4e62-9970-8c0c24642119", + "metadata": {}, + "source": [ + "## Constants of the problems" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f39bc943-a1d2-47a7-81ea-3d766c9d11a6", + "metadata": {}, + "outputs": [], + "source": [ + "x0 = [-42272.67, 0, 0, -5796.72] # état initial\n", + "μ = 5.1658620912*1e12\n", + "rf = 42165.0 ;\n", + "F_max = 20.0 #100.0\n", + "γ_max = F_max*3600.0^2/(2000.0*10^3)\n", + "t0 = 0.0\n", + "rf3 = rf^3 ;\n", + "α = sqrt(μ/rf3);" + ] + }, + { + "cell_type": "markdown", + "id": "80679ed8-77de-43aa-b542-6a5f7733e86b", + "metadata": {}, + "source": [ + "## The Hamiltonian system" + ] + }, + { + "cell_type": "markdown", + "id": "2139105f-a494-4692-8225-46c165e1fae0", + "metadata": {}, + "source": [ + "The pseudo-Hamiltonian is\n", + "\n", + "$$\n", + "H(x, p, u) = p_{1}x_3 + p_{2}x_4 + p_{3}\\left(-\\dfrac{\\mu\\, x_{1}}{r^{3}} + u_{1}\\right) + p_{4}\\left(-\\dfrac{\\mu\\, x_{2}}{r^{3}} + u_{2}\\right)\n", + "$$\n", + "\n", + "and the pseudo-Hamiltonian system is given by\n", + "\n", + "$$\n", + " \\vec{H}(x, p, u) = \\left(\\frac{\\partial H}{\\partial p}(x, p, u), \n", + " -\\frac{\\partial H}{\\partial x}(x, p, u) \\right)\n", + "$$\n", + "\n", + "where \n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "\\frac{\\partial H}{\\partial p}(x, p, u) &= \\left( x_3, x_4, -\\dfrac{\\mu\\, x_{1}}{r^{3}} + u_{1}, -\\dfrac{\\mu\\, x_{2}}{r^{3}} + u_{2}\\right), \\\\\n", + "\\frac{\\partial H}{\\partial x}(x, p, u) &= \\left(\\left(\\frac{\\mu}{r^3} - \\frac{3\\mu x_1^2}{r^5}\\right)p_3 + \\frac{3\\mu x_1x_2}{r^5}p_4, \\frac{3\\mu x_1x_2}{r^5}p_3 + \\left(\\frac{\\mu}{r^3} + \\frac{3\\mu x_2^2}{r^5}\\right)p_4, p_1, p_2\\right).\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "The maximization condition from the Pontryagin Maximum Principle gives the maximizing control\n", + "(we assume that $(p_3,p_4)$ never vanishes) :\n", + "\n", + "$$\n", + " u(x(t),p(t)) = \\frac{\\gamma_\\mathrm{max}}{\\sqrt{p_3^2(t)+p_4^2(t)}}(p_3(t),p_4(t)).\n", + "$$\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "650273cc-a4fc-46f9-ba02-a65f1a57ed90", + "metadata": {}, + "outputs": [], + "source": [ + "# Maximizing control\n", + "function control(p)\n", + " u = zeros(eltype(p),2)\n", + " u[1] = p[3]*γ_max/norm(p[3:4])\n", + " u[2] = p[4]*γ_max/norm(p[3:4])\n", + " return u\n", + "end;\n", + "\n", + "# Maximized Hamiltonian\n", + "function hfun(x, p)\n", + " u = control(p)\n", + " nor = norm(x[1:2]); nor3 = nor^3\n", + " h = p[1]*x[3] + p[2]*x[4] + p[3]*(-μ*x[1]/nor3 + u[1]) + p[4]*(-μ*x[2]/nor^3 + u[2])\n", + " return h\n", + "end;\n", + "\n", + "# Hamiltonian system\n", + "function hv(x, p)\n", + " n = size(x, 1)\n", + " hv = zeros(eltype(x), 2*n)\n", + " x_1 = x[1]; x_2 = x[2]; x_3 = x[3]; x_4 = x[4]\n", + " p_1 = p[1]; p_2 = p[2]; p_3 = p[3]; p_4 = p[4]\n", + " norme = norm(x[1:2]); r3 = norme^3; r5 = norme^5\n", + " u = control(p)\n", + " hv[1] = x_3;\n", + " hv[2] = x_4\n", + " hv[3] = -μ*x_1/r3 + u[1]\n", + " hv[4] = -μ*x_2/r3 + u[2]\n", + " hv[5] = μ*((1/r3 - (3*x_1^2)/r5)*p_3 - ((3*x_1*x_2)/r5)*p_4)\n", + " hv[6] = μ*(-((3*x_1*x_2)/r5)*p_3 + (1/r3 - (3*x_2^2)/r5)*p_4)\n", + " hv[7] = -p_1\n", + " hv[8] = -p_2\n", + " return hv\n", + "end;\n", + "\n", + "f = Flow(HamiltonianVectorField(hv));" + ] + }, + { + "cell_type": "markdown", + "id": "6bda152c-5c5f-4de3-aad9-6e7b0f7975f4", + "metadata": {}, + "source": [ + "## The shooting function" + ] + }, + { + "cell_type": "markdown", + "id": "7a35da8c-771e-4e57-8413-fc615d140474", + "metadata": {}, + "source": [ + "We introduce\n", + "$\n", + " \\alpha := \\sqrt{\\frac{\\mu}{r_f^3}}.\n", + "$\n", + "The final condition can be written $c(x(t_f)) = 0$, with $c \\colon \\mathbb{R}^4 \\to \\mathbb{R}^3$\n", + "given by\n", + "\n", + "$$\n", + " c(x) := (r^2(x) - r_f^2, ~~ x_{3} + \\alpha\\, x_{2}, ~~ x_{4} - \\alpha\\, x_{1}).\n", + "$$\n", + "\n", + "The final time being free, we get the condition at the final time\n", + "\n", + "$$\n", + " H(x(t_f), p(t_f), u(t_f)) = -p^0 = 1. \\quad \\text{(cas normal)}\n", + "$$\n", + "\n", + "Besides, the transversality condition\n", + "\n", + "$$\n", + "p(t_f) = c'(x(t_f))^T \\lambda, ~~ \\lambda \\in \\mathbb{R}^3,\n", + "$$\n", + "\n", + "leads to\n", + "\n", + "$$\n", + "\\Phi(x(t_f), p(t_f)) := x_2(t_f) \\Big( p_1(t_f) + \\alpha\\, p_4(t_f) \\Big) - x_1(t_f) \\Big( p_2(t_f) - \\alpha\\, p_3(t_f) \\Big) = 0.\n", + "$$\n", + "\n", + "Considering the limit conditions, the final condition on the pseudo-Hamiltonian and the transversality condition,\n", + "the shooting function is given by\n", + "\n", + "\\begin{equation*}\n", + " \\begin{array}{rlll}\n", + " S \\colon & \\mathbb{R}^5 & \\longrightarrow & \\mathbb{R}^5 \\\\\n", + " & (p_0, t_f) & \\longmapsto &\n", + " S(p_0, t_f) := \\begin{pmatrix}\n", + " c(x(t_f, x_0, p_0)) \\\\[0.5em]\n", + " \\Phi(z(t_f, x_0, p_0)) \\\\[0.5em]\n", + " H(z(t_f, x_0, p_0), u(z(t_f, x_0, p_0))) - 1\n", + " \\end{pmatrix}\n", + " \\end{array}\n", + "\\end{equation*}\n", + "\n", + "where $z(t_f, x_0, p_0)$ is the solution at time $t_f$ of the feedback pseudo-Hamiltonian system (that is the \n", + "pseudo-Hamiltonian system with the maximizing control), starting at time $t_0$ from $(x_0, p_0)$. We recall that\n", + "we note $z=(x, p)$." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4deeb191-35a8-4f5b-9dca-efa1e7b1ac8b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iter f(x) inf-norm Step 2-norm Step time\n", + "------ -------------- -------------- --------------\n", + " 1 7.026435e+00 0.000000e+00 5.059817\n", + " 2 7.334182e-03 4.372294e-11 16.066451\n", + " 3 3.692279e-03 1.109605e-11 0.018698\n", + " 4 9.853102e-08 1.134859e-11 0.022441\n", + " 5 1.590524e-08 8.354949e-22 0.019856\n", + "Results of Nonlinear Solver Algorithm\n", + " * Algorithm: Modified Powell (User Jac, Expert)\n", + " * Starting Point: [-0.0013615, -7.34989e-6, -5.359923e-5, -0.00858271, 59.8551668]\n", + " * Zero: [-0.0013615711107251762, -7.349896988606744e-6, -5.35992371862138e-5, -0.008582713089817779, 59.85516688789379]\n", + " * Inf-norm of residuals: 0.000000\n", + " * Convergence: true\n", + " * Message: algorithm estimates that the relative error between x and the solution is at most tol\n", + " * Total time: 21.195272 seconds\n", + " * Function Calls: 5\n", + " * Jacobian Calls (df/dx): 1\n" + ] + }, + { + "data": { + "text/plain": [ + "Transfert(59.85516688789379, [-0.0013615711107251762, -7.349896988606744e-6, -5.35992371862138e-5, -0.008582713089817779])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Données pour la trajectoire durant le transfert\n", + "mutable struct Transfert\n", + " duration\n", + " initial_adjoint\n", + "end\n", + "\n", + "# Fonction de tir\n", + "function shoot(p0, tf)\n", + " \n", + " # Integration\n", + " xf, pf = f(t0, x0, p0, tf)\n", + " \n", + " # Conditions\n", + " s = zeros(eltype(p0), 5)\n", + " s[1] = norm(xf[1:2]) - rf\n", + " s[2] = xf[3] + α*xf[2]\n", + " s[3] = xf[4] - α*xf[1]\n", + " s[4] = xf[2]*(pf[1] + α*pf[4]) - xf[1]*(pf[2] - α*pf[3])\n", + " s[5] = hfun(xf, pf) - 1\n", + " \n", + " return s\n", + "\n", + "end;\n", + "\n", + "# Initial guess\n", + "#y_guess = [1.0323e-4, 4.915e-5, 3.568e-4, -1.554e-4, 13.4] # for F_max = 100N\n", + "ξ_guess = [-0.0013615, -7.34989e-6, -5.359923e-5, -0.00858271, 59.8551668] # for F_max = 20N\n", + "\n", + "# Solve\n", + "foo(ξ) = shoot(ξ[1:4], ξ[5])\n", + "jfoo(ξ) = ForwardDiff.jacobian(foo, ξ)\n", + "foo!(s, ξ) = ( s[:] = foo(ξ); nothing )\n", + "jfoo!(js, ξ) = ( js[:] = jfoo(ξ); nothing )\n", + "\n", + "nl_sol = fsolve(foo!, jfoo!, ξ_guess, show_trace=true); println(nl_sol)\n", + "\n", + "# Retrieves solution\n", + "if nl_sol.converged\n", + " p0_sol = nl_sol.x[1:4]\n", + " tf_sol = nl_sol.x[5]\n", + " transfert_data = Transfert(tf_sol, p0_sol);\n", + "else\n", + " error(\"Not converged\")\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "ae9cd7d1-97b2-465f-8f05-f2eeea9b1def", + "metadata": {}, + "source": [ + "## Pre and post-transfer" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "73dcf5ff-4ff2-4894-9407-720bed9b4983", + "metadata": {}, + "outputs": [], + "source": [ + "# Kepler's law\n", + "function kepler(x)\n", + " n = size(x, 1)\n", + " dx = zeros(eltype(x), n)\n", + " x1 = x[1]\n", + " x2 = x[2]\n", + " x3 = x[3]\n", + " x4 = x[4]\n", + " dsat = norm(x[1:2]); r3 = dsat^3;\n", + " dx[1] = x3\n", + " dx[2] = x4\n", + " dx[3] = -μ*x1/r3\n", + " dx[4] = -μ*x2/r3\n", + " return dx\n", + "end\n", + "\n", + "f0 = Flow(VectorField(kepler));" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "04f4e32f-ce8a-4e1a-90a1-b3dc0af2a956", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iter f(x) inf-norm Step 2-norm Step time\n", + "------ -------------- -------------- --------------\n", + " 1 3.021414e-07 0.000000e+00 3.061420\n", + " 2 6.839400e-10 1.399191e-13 4.821815\n", + "Results of Nonlinear Solver Algorithm\n", + " * Algorithm: Modified Powell (User Jac, Expert)\n", + " * Starting Point: [6738.200652584018, 1.3618799608695503e-21, 2.8839710428042565e-7, 36366.2117341436, 5.302395297743802]\n", + " * Zero: [6738.200652696158, 2.2925434185945747e-21, 1.4403503883997278e-7, 36366.211733817254, 5.302395297772681]\n", + " * Inf-norm of residuals: 0.000000\n", + " * Convergence: true\n", + " * Message: algorithm estimates that the relative error between x and the solution is at most tol\n", + " * Total time: 7.883518 seconds\n", + " * Function Calls: 2\n", + " * Jacobian Calls (df/dx): 1\n" + ] + }, + { + "data": { + "text/plain": [ + "PreTransfert(10.604790595545362, [-42272.67, 0.0, 0.0, -5796.72])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# On cherche le point le plus proche de la Terre sur l'orbite initiale\n", + "# Ce sera le point de départ de la pré-mission\n", + "# On cherche aussi le temps\n", + "\n", + "# données pour la trajectoire pré-transfert\n", + "mutable struct PreTransfert\n", + " duration\n", + " initial_point\n", + "end\n", + "\n", + "# Fonction de tir\n", + "function depart(xp, tp)\n", + " \n", + " # Integration\n", + " x0_ = f0(0.0, xp, tp)\n", + " \n", + " # Conditions\n", + " s = zeros(eltype(xp), 5)\n", + " s[1] = xp[2]\n", + " s[2] = x0_[1] - x0[1]\n", + " s[3] = x0_[2] - x0[2]\n", + " s[4] = x0_[3] - x0[3]\n", + " s[5] = x0_[4] - x0[4]\n", + " \n", + " return s\n", + "\n", + "end;\n", + "\n", + "# Itéré initial\n", + "ξ_guess = [6738.200652584018, 1.3618799608695503e-21, 2.8839710428042565e-7, 36366.2117341436, 5.302395297743802]\n", + "\n", + "# Solve\n", + "foo(ξ) = depart(ξ[1:4], ξ[5])\n", + "jfoo(ξ) = ForwardDiff.jacobian(foo, ξ)\n", + "foo!(s, ξ) = ( s[:] = foo(ξ); nothing )\n", + "jfoo!(js, ξ) = ( js[:] = jfoo(ξ); nothing )\n", + "\n", + "nl_sol = fsolve(foo!, jfoo!, ξ_guess, show_trace=true); println(nl_sol)\n", + "\n", + "# Retrieves solution\n", + "if nl_sol.converged\n", + " x_pre_transfert = x0\n", + " t_pre_transfert = 2.0*nl_sol.x[5]\n", + " pre_transfert_data = PreTransfert(t_pre_transfert, x_pre_transfert);\n", + "else\n", + " error(\"Not converged\")\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "00a00a7d-a161-4327-9ea3-f8e4a34bfb77", + "metadata": {}, + "outputs": [], + "source": [ + "# données pour la trajectoire post-transfert\n", + "mutable struct PostTransfert\n", + " duration\n", + "end\n", + "\n", + "t_post_transfert = 20.0\n", + "\n", + "post_transfert_data = PostTransfert(t_post_transfert);" + ] + }, + { + "cell_type": "markdown", + "id": "0686c07f-aea9-405a-95bd-af42f09370b6", + "metadata": {}, + "source": [ + "## Animation" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "e61c1bee-88b4-4b57-8a09-1249f31978e0", + "metadata": {}, + "outputs": [], + "source": [ + "function animation(pre_transfert_data, transfert_data, post_transfert_data; fps=10, nFrame=200)\n", + " \n", + " # pré-transfert\n", + " t_pre_transfert = pre_transfert_data.duration\n", + " x_pre_transfert = pre_transfert_data.initial_point\n", + " \n", + " # transfert\n", + " p0_transfert = transfert_data.initial_adjoint\n", + " tf_transfert = transfert_data.duration\n", + " \n", + " # post-trasfert\n", + " t_post_transfert = post_transfert_data.duration\n", + " \n", + " # On calcule les orbites initiale et finale\n", + " r0 = norm(x0[1:2])\n", + " v0 = norm(x0[3:4])\n", + " a = 1.0/(2.0/r0-v0*v0/μ)\n", + " t1 = r0*v0*v0/μ - 1.0;\n", + " t2 = (x0[1:2]'*x0[3:4])/sqrt(a*μ);\n", + " e_ellipse = norm([t1 t2])\n", + " p_orb = a*(1-e_ellipse^2);\n", + " n_theta = 151\n", + " Theta = range(0.0, stop=2*pi, length=n_theta)\n", + " X1_orb_init = zeros(n_theta)\n", + " X2_orb_init = zeros(n_theta)\n", + " X1_orb_arr = zeros(n_theta)\n", + " X2_orb_arr = zeros(n_theta)\n", + "\n", + " for i in 1:n_theta\n", + " theta = Theta[i]\n", + " r_orb = p_orb/(1+e_ellipse*cos(theta));\n", + " # Orbite initiale\n", + " X1_orb_init[i] = r_orb*cos(theta);\n", + " X2_orb_init[i] = r_orb*sin(theta);\n", + " # Orbite finale\n", + " X1_orb_arr[i] = rf*cos(theta) ;\n", + " X2_orb_arr[i] = rf*sin(theta);\n", + " end\n", + " \n", + " # Centre de la fenêtre\n", + " cx = 40000\n", + " cy = -7000\n", + "\n", + " # Taille de la fenêtre\n", + " w = 1600\n", + " h = 900\n", + " ρ = h/w\n", + " \n", + " # Limites de la fenêtre\n", + " ee = 0.5\n", + " xmin = minimum([X1_orb_init; X1_orb_arr]); xmin = xmin - ee * abs(xmin);\n", + " xmax = maximum([X1_orb_init; X1_orb_arr]); xmax = xmax + ee * abs(xmax);\n", + " ymin = minimum([X2_orb_init; X2_orb_arr]); ymin = ymin - ee * abs(ymin);\n", + " ymax = maximum([X2_orb_init; X2_orb_arr]); ymax = ymax + ee * abs(ymax);\n", + " \n", + " Δy = ymax-ymin\n", + " Δx = Δy/ρ\n", + " Δn = Δx - (xmax-xmin)\n", + " xmin = xmin - Δn/2\n", + " xmax = xmax + Δn/2\n", + " \n", + " # Trajectoire pré-transfert\n", + " traj_pre_transfert = f0((0.0, t_pre_transfert), x_pre_transfert)\n", + " times_pre_transfert = traj_pre_transfert.t\n", + " n_pre_transfert = size(times_pre_transfert, 1)\n", + " x1_pre_transfert = [traj_pre_transfert[1, j] for j in 1:n_pre_transfert ]\n", + " x2_pre_transfert = [traj_pre_transfert[2, j] for j in 1:n_pre_transfert ]\n", + " v1_pre_transfert = [traj_pre_transfert[3, j] for j in 1:n_pre_transfert ]\n", + " v2_pre_transfert = [traj_pre_transfert[4, j] for j in 1:n_pre_transfert ] \n", + " \n", + " # Trajectoire pendant le transfert\n", + " traj_transfert = f((t0, tf_transfert), x0, p0_transfert)\n", + " times_transfert = traj_transfert.t\n", + " n_transfert = size(times_transfert, 1)\n", + " x1_transfert = [traj_transfert[1, j] for j in 1:n_transfert ]\n", + " x2_transfert = [traj_transfert[2, j] for j in 1:n_transfert ]\n", + " v1_transfert = [traj_transfert[3, j] for j in 1:n_transfert ]\n", + " v2_transfert = [traj_transfert[4, j] for j in 1:n_transfert ]\n", + " u_transfert = zeros(2, length(times_transfert))\n", + " for j in 1:n_transfert\n", + " u_transfert[:,j] = control(traj_transfert[5:8, j])\n", + " end\n", + "\n", + " # post-transfert\n", + " x_post_transfert = traj_transfert[:,end]\n", + "\n", + " # Trajectoire post-transfert\n", + " traj_post_transfert = f0((0.0, t_post_transfert), x_post_transfert)\n", + " times_post_transfert = traj_post_transfert.t\n", + " n_post_transfert = size(times_post_transfert, 1)\n", + " x1_post_transfert = [traj_post_transfert[1, j] for j in 1:n_post_transfert ]\n", + " x2_post_transfert = [traj_post_transfert[2, j] for j in 1:n_post_transfert ]\n", + " v1_post_transfert = [traj_post_transfert[3, j] for j in 1:n_post_transfert ]\n", + " v2_post_transfert = [traj_post_transfert[4, j] for j in 1:n_post_transfert ] \n", + "\n", + " # Angles de rotation du satellite pendant le pré-transfert\n", + " θ0 = atan(u_transfert[2, 1], u_transfert[1, 1])\n", + " θ_pre_transfert = range(π/2, mod(θ0, 2*π), length=n_pre_transfert)\n", + "\n", + " # Angles de rotation du satellite pendant le transfert\n", + " θ_transfert = atan.(u_transfert[2, :], u_transfert[1, :])\n", + "\n", + " # Angles de rotation du satellite pendant le post-transfert\n", + " θ1 = atan(u_transfert[2, end], u_transfert[1, end])\n", + " θ2 = atan(-x2_post_transfert[end], -x1_post_transfert[end])\n", + " θ_post_transfert = range(mod(θ1, 2*π), mod(θ2, 2*π), length=n_post_transfert)\n", + "\n", + " # Etoiles\n", + " Δx = xmax-xmin\n", + " Δy = ymax-ymin \n", + " ρ = Δy/Δx\n", + " S = stars(ρ)\n", + "\n", + " # nombre total d'images\n", + " nFrame = min(nFrame, n_pre_transfert+n_transfert+n_post_transfert);\n", + " \n", + " # Pour l'affichage de la trajectoire globale\n", + " times = [times_pre_transfert[1:end-1];\n", + " times_pre_transfert[end].+times_transfert[1:end-1];\n", + " times_pre_transfert[end].+times_transfert[end].+times_post_transfert[1:end]]\n", + " x1 = [x1_pre_transfert[1:end-1]; x1_transfert[1:end-1]; x1_post_transfert[:]]\n", + " x2 = [x2_pre_transfert[1:end-1]; x2_transfert[1:end-1]; x2_post_transfert[:]]\n", + " v1 = [v1_pre_transfert[1:end-1]; v1_transfert[1:end-1]; v1_post_transfert[:]]\n", + " v2 = [v2_pre_transfert[1:end-1]; v2_transfert[1:end-1]; v2_post_transfert[:]]\n", + " θ = [ θ_pre_transfert[1:end-1]; θ_transfert[1:end-1]; θ_post_transfert[:]]\n", + "\n", + " # plot thrust on/off\n", + " th = [BitArray(zeros(n_pre_transfert-1)); \n", + " BitArray(ones(n_transfert-1));\n", + " BitArray(zeros(n_post_transfert))]\n", + " \n", + " # plot trajectory\n", + " pt = [BitArray(ones(n_pre_transfert-1)); \n", + " BitArray(ones(n_transfert-1));\n", + " BitArray(zeros(n_post_transfert))]\n", + " \n", + " # Contrôle sur la trajectoire totale\n", + " u_total = hcat([zeros(2, n_pre_transfert-1), \n", + " u_transfert[:, 1:n_transfert-1],\n", + " zeros(2, n_post_transfert)]...)\n", + "\n", + " # temps total\n", + " temps_transfert_global = times[end]\n", + "\n", + " # pas de temps pour le transfert global\n", + " if nFrame>1\n", + " Δt = temps_transfert_global/(nFrame-1)\n", + " else\n", + " Δt = 0.0\n", + " end\n", + " \n", + " # opacités des orbites initiale et finale\n", + " op_initi = [range(0.0, 1.0, length=n_pre_transfert-1);\n", + " range(1.0, 0.0, length=n_transfert-1);\n", + " zeros(n_post_transfert)]\n", + " op_final = [zeros(n_pre_transfert-1);\n", + " range(0.0, 1.0, length=n_transfert-1);\n", + " range(1.0, 0.0, length=int(n_post_transfert/4));\n", + " zeros(n_post_transfert-int(n_post_transfert/4))]\n", + " \n", + " # animation\n", + " anim = @animate for i ∈ 1:nFrame\n", + " \n", + " # Δt : pas de temps\n", + " # time_current : temps courant de la mission totale à l'itération i\n", + " # i_current : indice tel que times[i_current] = time_current\n", + " # w, h : width, height de la fenêtre\n", + " # xmin, xmax, ymin, ymax : limites des axes du plot principal\n", + " # X1_orb_init, X2_orb_init : coordonnées de l'orbite initiale\n", + " # X1_orb_arr, X2_orb_arr : coordonnées de l'orbite finale\n", + " # cx, cy : coordonées du centre de l'affichage du tranfert\n", + " # S : data pour les étoiles\n", + " # Δx, Δy : xmax-xmin, ymax-ymin\n", + " # times : tous les temps de la mission complète, ie pre-transfert, transfert et post-transfert\n", + " # x1, x2 : vecteur de positions du satellite\n", + " # θ : vecteur d'orientations du satellite\n", + " # th : vecteur de booléens - thrust on/off\n", + " # u_total : vecteur de contrôles pour toute la mission\n", + " # F_max, γ_max : poussée max\n", + " # subplot_current : valeur du subplot courant\n", + " # cam_x, cam_y : position de la caméra\n", + " # cam_zoom : zoom de la caméra\n", + " \n", + " cam_x = cx\n", + " cam_y = cy\n", + " cam_zoom = 1\n", + " \n", + " time_current = (i-1)*Δt\n", + " i_current = argmin(abs.(times.-time_current))\n", + " \n", + " px = background(w, h, xmin, xmax, ymin, ymax, \n", + " X1_orb_init, X2_orb_init, X1_orb_arr, X2_orb_arr,\n", + " cx, cy, S, Δx, Δy, cam_x, cam_y, cam_zoom, \n", + " op_initi[i_current], op_final[i_current], times, time_current)\n", + "\n", + " trajectoire!(px, times, x1, x2, θ, th, time_current, cx, cy, pt) \n", + " \n", + " subplot_current = 2\n", + " subplot_current = panneau_control!(px, time_current, times, u_total, \n", + " F_max, γ_max, subplot_current)\n", + " \n", + " #subplot_current = panneau_information!(px, subplot_current, time_current, \n", + " # i_current, x1, x2, v1, v2, θ, F_max, tf_transfert, X1_orb_init, \n", + " # X2_orb_init, X1_orb_arr, X2_orb_arr)\n", + " \n", + " end\n", + "\n", + " display(plot(px))\n", + " # enregistrement\n", + " #gif(anim, \"transfert-temps-min-original.mp4\", fps=fps);\n", + " #gif(anim, \"transfert-temps-min.gif\", fps=fps);\n", + " \n", + "end;" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a23d5c91-72e5-4a93-b689-8227887f0551", + "metadata": {}, + "outputs": [ + { + "ename": "LoadError", + "evalue": "Cannot convert Measures.AbsoluteLength to series data for plotting", + "output_type": "error", + "traceback": [ + "Cannot convert Measures.AbsoluteLength to series data for plotting", + "", + "Stacktrace:", + " [1] error(s::String)", + " @ Base ./error.jl:33", + " [2] _prepare_series_data(x::Measures.AbsoluteLength)", + " @ RecipesPipeline ~/opt/miniconda3/envs/julia/share/julia/packages/RecipesPipeline/kJPXU/src/series.jl:8", + " [3] _series_data_vector(x::Measures.AbsoluteLength, plotattributes::Dict{Symbol, Any})", + " @ RecipesPipeline ~/opt/miniconda3/envs/julia/share/julia/packages/RecipesPipeline/kJPXU/src/series.jl:35", + " [4] macro expansion", + " @ ~/opt/miniconda3/envs/julia/share/julia/packages/RecipesPipeline/kJPXU/src/series.jl:135 [inlined]", + " [5] apply_recipe(plotattributes::AbstractDict{Symbol, Any}, #unused#::Type{RecipesPipeline.SliceIt}, x::Any, y::Any, z::Any)", + " @ RecipesPipeline ~/opt/miniconda3/envs/julia/share/julia/packages/RecipesBase/qpxEX/src/RecipesBase.jl:289", + " [6] _process_userrecipes!(plt::Any, plotattributes::Any, args::Any)", + " @ RecipesPipeline ~/opt/miniconda3/envs/julia/share/julia/packages/RecipesPipeline/kJPXU/src/user_recipe.jl:36", + " [7] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)", + " @ RecipesPipeline ~/opt/miniconda3/envs/julia/share/julia/packages/RecipesPipeline/kJPXU/src/RecipesPipeline.jl:70", + " [8] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)", + " @ Plots ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/plot.jl:208", + " [9] plot(args::Any; kw::Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}})", + " @ Plots ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/plot.jl:91", + " [10] plot", + " @ ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/plot.jl:85 [inlined]", + " [11] animation(pre_transfert_data::PreTransfert, transfert_data::Transfert, post_transfert_data::PostTransfert; fps::Int64, nFrame::Int64)", + " @ Main ./In[9]:208", + " [12] top-level scope", + " @ In[10]:4", + " [13] eval", + " @ ./boot.jl:373 [inlined]", + " [14] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)", + " @ Base ./loading.jl:1196" + ] + } + ], + "source": [ + "nFrame = 1; fps = 1\n", + "#nFrame = 10; fps = 1\n", + "#nFrame = 2000; fps = 20\n", + "animation(pre_transfert_data, transfert_data, post_transfert_data, nFrame=nFrame, fps=fps)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "acc4155b-8c6a-4e06-a823-8c22fd9ff72a", + "metadata": {}, + "outputs": [], + "source": [ + "if nFrame == 2000\n", + " convert = `ffmpeg -y -i transfert-temps-min-original.mp4 -vf format=yuv420p transfert-temps-min.mp4`\n", + " run(convert)\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c663a64a-1e53-43ba-8fbf-86fb073cc526", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.7.3", + "language": "julia", + "name": "julia-1.7" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/plottings.jl b/plottings.jl new file mode 100644 index 0000000000000000000000000000000000000000..6c475c7d9c828d553821cd622858278288f79478 --- /dev/null +++ b/plottings.jl @@ -0,0 +1,449 @@ +using Plots +using Plots.PlotMeasures +using SparseArrays +using Printf + +# Preliminaries +int(x) = floor(Int, x); +rayon_Terre = 6371; +sc_sat = 1000; # scaling for the satellite + +# -------------------------------------------------------------------------------------------- +# +# Satellite +# +# -------------------------------------------------------------------------------------------- +# Corps du satellite +@userplot SatBody +@recipe function f(cp::SatBody) + x, y = cp.args + seriestype --> :shape + fillcolor --> :goldenrod1 + linecolor --> :goldenrod1 + x, y +end + +@userplot SatLine +@recipe function f(cp::SatLine) + x, y = cp.args + linecolor --> :black + x, y +end + +# Bras du satellite +@userplot SatBras +@recipe function f(cp::SatBras) + x, y = cp.args + seriestype --> :shape + fillcolor --> :goldenrod1 + linecolor --> :white + x, y +end + +# panneau +@userplot PanBody +@recipe function f(cp::PanBody) + x, y = cp.args + seriestype --> :shape + fillcolor --> :dodgerblue4 + linecolor --> :black + x, y +end + +# flamme +@userplot Flamme +@recipe function f(cp::Flamme) + x, y = cp.args + seriestype --> :shape + fillcolor --> :darkorange1 + linecolor --> false + x, y +end + +function satellite!(pl; subplot=1, thrust=false, position=[0;0], scale=1, rotate=0) + + # Fonctions utiles + R(θ) = [ cos(θ) -sin(θ) + sin(θ) cos(θ)] # rotation + T(x, v) = x.+v # translation + H(λ, x) = λ.*x # homotéthie + SA(x, θ, c) = c .+ 2*[cos(θ);sin(θ)]'*(x.-c).*[cos(θ);sin(θ)]-(x.-c) # symétrie axiale + + # + O = position + Rθ = R(rotate) + + # Paramètres + α = π/10.0 # angle du tube, par rapport à l'horizontal + β = π/2-π/40 # angle des bras, par rapport à l'horizontal + Lp = scale.*1.4*cos(α) # longueur d'un panneau + lp = scale.*2.6*sin(α) # largueur d'un panneau + + # Param bras du satellite + lb = scale.*3*cos(α) # longueur des bras + eb = scale.*cos(α)/30 # demi largeur des bras + xb = 0.0 + yb = scale.*sin(α) + + # Paramètres corps du satellite + t = range(-α, α, length=50) + x = scale.*cos.(t); + y = scale.*sin.(t); + Δx = scale.*cos(α) + Δy = scale.*sin(α) + + # Paramètres flamme + hF = yb # petite hauteur + HF = 2*hF # grande hauteur + LF = 5.5*Δx # longueur + + # Dessin bras du satellite + M = T(Rθ*[ [xb-eb, xb+eb, xb+eb+lb*cos(β), xb-eb+lb*cos(β), xb-eb]'; + [yb, yb, yb+lb*sin(β), yb+lb*sin(β), yb]'], O); + satbras!(pl, M[1,:], M[2,:], subplot=subplot) + M = T(Rθ*[ [xb-eb, xb+eb, xb+eb+lb*cos(β), xb-eb+lb*cos(β), xb-eb]'; + -[yb, yb, yb+lb*sin(β), yb+lb*sin(β), yb']'], O); + satbras!(pl, M[1,:], M[2,:], subplot=subplot) + + # Dessin corps du satellite + M = T(Rθ*[ x'; y'], O); satbody!(pl, M[1,:], M[2,:], subplot=subplot) # bord droit + M = T(Rθ*[-x'; y'], O); satbody!(pl, M[1,:], M[2,:], subplot=subplot) # bord gauche + M = T(Rθ*[scale.*[-cos(α), cos(α), cos(α), -cos(α)]' + scale.*[-sin(α), -sin(α), sin(α), sin(α)]'], O); + satbody!(pl, M[1,:], M[2,:], subplot=subplot) # interieur + + M = T(Rθ*[ x'; y'], O); satline!(pl, M[1,:], M[2,:], subplot=subplot) # bord droit + M = T(Rθ*[-x'; y'], O); satline!(pl, M[1,:], M[2,:], subplot=subplot) # bord gauche + M = T(Rθ*[ x'.-2*Δx; y'], O); satline!(pl, M[1,:], M[2,:], subplot=subplot) # bord gauche (droite) + M = T(Rθ*[ scale.*[-cos(α), cos(α)]'; + scale.*[ sin(α), sin(α)]'], O); + satline!(pl, M[1,:], M[2,:], subplot=subplot) # haut + M = T(Rθ*[ scale.*[-cos(α), cos(α)]'; + -scale.*[ sin(α), sin(α)]'], O); + satline!(pl, M[1,:], M[2,:], subplot=subplot) # bas + + # Panneau + ep = (lb-3*lp)/6 + panneau = [0 Lp Lp 0 + 0 0 lp lp] + + ey = 3*eb # eloignement des panneaux au bras + vy = [cos(β-π/2); sin(β-π/2)] .* ey + v0 = [0; yb] + v1 = 2*ep*[cos(β); sin(β)] + v2 = (3*ep+lp)*[cos(β); sin(β)] + v3 = (4*ep+2*lp)*[cos(β); sin(β)] + + pa1 = T(R(β-π/2)*panneau, v0+v1+vy); pa = T(Rθ*pa1, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + pa2 = T(R(β-π/2)*panneau, v0+v2+vy); pa = T(Rθ*pa2, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + pa3 = T(R(β-π/2)*panneau, v0+v3+vy); pa = T(Rθ*pa3, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + + pa4 = SA(pa1, β, [xb; yb]); pa = T(Rθ*pa4, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + pa5 = SA(pa2, β, [xb; yb]); pa = T(Rθ*pa5, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + pa6 = SA(pa3, β, [xb; yb]); pa = T(Rθ*pa6, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + + pa7 = SA(pa1, 0, [0; 0]); pa = T(Rθ*pa7, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + pa8 = SA(pa2, 0, [0; 0]); pa = T(Rθ*pa8, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + pa9 = SA(pa3, 0, [0; 0]); pa = T(Rθ*pa9, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + + pa10 = SA(pa7, -β, [xb; -yb]); pa = T(Rθ*pa10, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + pa11 = SA(pa8, -β, [xb; -yb]); pa = T(Rθ*pa11, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + pa12 = SA(pa9, -β, [xb; -yb]); pa = T(Rθ*pa12, O); panbody!(pl, pa[1,:], pa[2,:], subplot=subplot) + + # Dessin flamme + if thrust + origin = T(Rθ*[Δx, 0.0], O) + thrust = Rθ*[8000, 0.0] + quiver!(pl, [origin[1]], [origin[2]], color=:red, + quiver=([thrust[1]], [thrust[2]]), linewidth=1, subplot=subplot) + end + +end; + +# -------------------------------------------------------------------------------------------- +# +# Stars +# +# -------------------------------------------------------------------------------------------- +@userplot StarsPlot +@recipe function f(cp::StarsPlot) + xo, yo, Δx, Δy, I, A, m, n = cp.args + seriestype --> :scatter + seriescolor --> :white + seriesalpha --> A + markerstrokewidth --> 0 + markersize --> 2*I[3] + xo.+I[2].*Δx./n, yo.+I[1].*Δy./m +end + +mutable struct Stars + s + i + m + n + a +end + +# Etoiles +function stars(ρ) + n = 200 # nombre de colonnes + m = int(ρ*n) # nombre de lignes + d = 0.03 + s = sprand(m, n, d) + i = findnz(s) + s = dropzeros(s) + # alpha + amin = 0.6 + amax = 1.0 + Δa = amax-amin + a = amin.+rand(length(i[3])).*Δa + return Stars(s, i, m, n, a) +end; + +# -------------------------------------------------------------------------------------------- +# +# Trajectory +# +# -------------------------------------------------------------------------------------------- +@userplot TrajectoryPlot +@recipe function f(cp::TrajectoryPlot) + t, x, y, tf = cp.args + n = argmin(abs.(t.-tf)) + inds = 1:n + seriescolor --> :white + linewidth --> range(0.0, 3.0, length=n) + seriesalpha --> range(0.0, 1.0, length=n) + aspect_ratio --> 1 + label --> false + x[inds], y[inds] +end + +function trajectoire!(px, times, x1, x2, θ, thrust, t_current, cx, cy, pt) + + i_current = argmin(abs.(times.-t_current)) + + # Trajectoire + if t_current>0 && pt[i_current] + trajectoryplot!(px, times, cx.+x1, cy.+x2, t_current) + end + + # Satellite + satellite!(px, position=[cx+x1[i_current]; cy+x2[i_current]], scale=sc_sat, + rotate=θ[i_current], thrust=thrust[i_current]) + +end; + +# -------------------------------------------------------------------------------------------- +# +# Background +# +# -------------------------------------------------------------------------------------------- +# Décor +function background(w, h, xmin, xmax, ymin, ymax, + X1_orb_init, X2_orb_init, X1_orb_arr, X2_orb_arr, + cx, cy, S, Δx, Δy, cam_x, cam_y, cam_zoom, opi, opf, times, time_current) + + # Fond + px = plot(background_color=:gray8, legend = false, aspect_ratio=:equal, + size = (w, h), framestyle = :none, + left_margin=-25mm, bottom_margin=-10mm, top_margin=-10mm, right_margin=-10mm, + xlims=(xmin, xmax), ylims=(ymin, ymax) #, + #camera=(0, 90), xlabel = "x", ylabel= "y", zlabel = "z", right_margin=25mm + ) + + # Etoiles + starsplot!(px, xmin, ymin, Δx, Δy, S.i, S.a, S.m, S.n) + + starsplot!(px, xmin-Δx, ymin-Δy, Δx, Δy, S.i, S.a, S.m, S.n) + starsplot!(px, xmin, ymin-Δy, Δx, Δy, S.i, S.a, S.m, S.n) + starsplot!(px, xmin, ymin+Δy, Δx, Δy, S.i, S.a, S.m, S.n) + starsplot!(px, xmin-Δx, ymin, Δx, Δy, S.i, S.a, S.m, S.n) + starsplot!(px, xmin+Δx, ymin, Δx, Δy, S.i, S.a, S.m, S.n) + starsplot!(px, xmin-Δx, ymin+Δy, Δx, Δy, S.i, S.a, S.m, S.n) + starsplot!(px, xmin, ymin+Δy, Δx, Δy, S.i, S.a, S.m, S.n) + starsplot!(px, xmin+Δx, ymin+Δy, Δx, Δy, S.i, S.a, S.m, S.n) + + # Orbite initiale + nn = length(X2_orb_init) + plot!(px, cx.+X1_orb_init, cy.+X2_orb_init, color = :olivedrab1, linewidth=2, alpha=opi) + + # Orbite finale + nn = length(X2_orb_init) + plot!(px, cx.+X1_orb_arr, cy.+X2_orb_arr, color = :turquoise1, linewidth=2, alpha=opf) + + # Terre + θ = range(0.0, 2π, length=100) + rT = rayon_Terre #- 1000 + xT = cx .+ rT .* cos.(θ) + yT = cy .+ rT .* sin.(θ) + nn = length(xT) + plot!(px, xT, yT, color = :dodgerblue1, seriestype=:shape, linewidth=0) + + # Soleil + i_current = argmin(abs.(times.-time_current)) + e = π/6 + β = range(π/4+e, π/4-e, length=length(times)) + ρ = sqrt((0.8*xmax-cx)^2+(0.8*ymax-cy)^2) + cxS = cx + ρ * cos(β[i_current]) + cyS = cy + ρ * sin(β[i_current]) + θ = range(0.0, 2π, length=100) + rS = 2000 + xS = cxS .+ rS .* cos.(θ) + yS = cyS .+ rS .* sin.(θ) + plot!(px, xS, yS, color = :gold, seriestype=:shape, linewidth=0) + + # Point de départ + #plot!(px, [cx+x0[1]], [cy+x0[2]], seriestype=:scatter, color = :white, markerstrokewidth=0) + + # Cadre + #plot!(px, [xmin, xmax, xmax, xmin, xmin], [ymin, ymin, ymax, ymax, ymin], color=:white) + + # Angle + #plot!(px, camera=(30,90)) + + return px + +end; + +function panneau_control!(px, time_current, times, u, F_max, γ_max, subplot_current) + + # We set the (optional) position relative to top-left of the 1st subplot. + # The call is `bbox(x, y, width, height, origin...)`, + # where numbers are treated as "percent of parent". + Δt_control = 2 #0.1*times[end] + + xx = 0.08 + yy = 0.1 + plot!(px, times, F_max.*u[1,:]./γ_max, + inset = (1, bbox(xx, yy, 0.2, 0.15, :top, :left)), + subplot = subplot_current, + bg_inside = nothing, + color=:red, legend=:true, yguidefontrotation=-90, yguidefonthalign = :right, + xguidefontsize=14, legendfontsize=14, + ylims=(-F_max,F_max), + xlims=(time_current-Δt_control, time_current+1.0*Δt_control), + ylabel="u₁ [N]", label="" + ) + + plot!(px, + [time_current, time_current], [-γ_max,γ_max], + subplot = subplot_current, label="") + + plot!(px, times, F_max.*u[2,:]./γ_max, + inset = (1, bbox(xx, yy+0.2, 0.2, 0.15, :top, :left)), + #ticks = nothing, + subplot = subplot_current+1, + bg_inside = nothing, + color=:red, legend=:true, yguidefontrotation=-90, yguidefonthalign = :right, + xguidefontsize=14, legendfontsize=14, + ylims=(-F_max,F_max), + xlims=(time_current-Δt_control, time_current+1.0*Δt_control), + ylabel="u₂ [N]", xlabel="temps [h]", label="" + ) + + plot!(px, + [time_current, time_current], [-γ_max,γ_max], + subplot = subplot_current+1, label="") + + return subplot_current+2 +end; + + +function panneau_information!(px, subplot_current, time_current, i_current, + x1, x2, v1, v2, θ, F_max, tf_transfert, X1_orb_init, X2_orb_init, X1_orb_arr, X2_orb_arr) + + # panneaux information + xx = 0.06 + yy = 0.3 + plot!(px, + inset = (1, bbox(xx, yy, 0.2, 0.15, :bottom, :left)), + subplot = subplot_current, + bg_inside = nothing, legend=:false, + framestyle=:none + ) + + a = 0.0 + b = 0.0 + Δtxt = 0.3 + + txt = @sprintf("Temps depuis départ [h] = %3.2f", time_current) + annotate!(px, subplot = subplot_current, a, b+2*Δtxt, txt, + annotationcolor=:white, annotationfontsize=14, + annotationhalign=:left) + + txt = @sprintf("Vitesse satellite [km/h] = %5.2f", sqrt(v1[i_current]^2+v2[i_current]^2)) + annotate!(px, subplot = subplot_current, a, b+Δtxt, txt, + annotationcolor=:white, annotationfontsize=14, + annotationhalign=:left) + + txt = @sprintf("Distance à la Terre [km] = %5.2f", sqrt(x1[i_current]^2+x2[i_current]^2)-rayon_Terre) + annotate!(px, subplot = subplot_current, a, b, txt, + annotationcolor=:white, annotationfontsize=14, + annotationhalign=:left) + + txt = @sprintf("Poussée maximale [N] = %5.2f", F_max) + annotate!(px, subplot = subplot_current, a, b-2*Δtxt, txt, + annotationcolor=:white, annotationfontsize=14, + annotationhalign=:left) + + txt = @sprintf("Durée du transfert [h] = %5.2f", tf_transfert) + annotate!(px, subplot = subplot_current, a, b-3*Δtxt, txt, + annotationcolor=:white, annotationfontsize=14, + annotationhalign=:left) + + subplot_current = subplot_current+1 + plot!(px, + inset = (1, bbox(0.3, 0.03, 0.5, 0.1, :top, :left)), + subplot = subplot_current, + bg_inside = nothing, legend=:false, aspect_ratio=:equal, + xlims=(-4, 4), + framestyle=:none + ) + + s1 = "Transfert orbital du satellite autour de la Terre\n" + s2 = "de l'orbite elliptique vers l'orbite circulaire\n" + s3 = "en temps minimal" + txt = s1 * s2 * s3 + annotate!(px, subplot = subplot_current, 0, 0, txt, + annotationcolor=:white, annotationfontsize=18, + annotationhalign=:center) + + rmax = 3*maximum(sqrt.(X1_orb_init.^2+X2_orb_init.^2)) + plot!(px, subplot = subplot_current, + 0.04.+X1_orb_init./rmax, X2_orb_init./rmax.-0.03, + color = :olivedrab1, linewidth=2) + + rmax = 7*maximum(sqrt.(X1_orb_arr.^2+X2_orb_arr.^2)) + plot!(px, subplot = subplot_current, + 3.3.+X1_orb_arr./rmax, X2_orb_arr./rmax.-0.03, + color = :turquoise1, linewidth=2) + + satellite!(px, subplot=subplot_current, + position=[0.67; 0.28], scale=0.08, + rotate=π/2) + + # Terre + θ = range(0.0, 2π, length=100) + rT = 0.1 + xT = 3.55 .+ rT .* cos.(θ) + yT = 0.28 .+ rT .* sin.(θ) + plot!(px, subplot=subplot_current, xT, yT, color = :dodgerblue1, seriestype=:shape, linewidth=0) + + subplot_current = subplot_current+1 + xx = 0.0 + yy = 0.02 + plot!(px, + inset = (1, bbox(xx, yy, 0.12, 0.05, :bottom, :right)), + subplot = subplot_current, + bg_inside = nothing, legend=:false, + framestyle=:none + ) + + s1 = "Réalisation : Olivier Cots (2022)" + txt = s1 + annotate!(px, subplot = subplot_current, 0, 0, txt, + annotationcolor=:gray, annotationfontsize=8, annotationhalign=:left) + + return subplot_current+1 + +end; \ No newline at end of file diff --git a/transfert-temps-min.ipynb b/transfert-temps-min.ipynb index 9f622f93ea9902b2bb45f060c63e1f907bc2abe1..cbf9553ed4f8c5f0a0e657642950b6b08b233a6b 100644 --- a/transfert-temps-min.ipynb +++ b/transfert-temps-min.ipynb @@ -61,7 +61,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -81,7 +81,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -97,7 +97,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -114,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -193,7 +193,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -354,7 +354,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -403,7 +403,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -430,7 +430,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -504,7 +504,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -661,7 +661,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ @@ -690,7 +690,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "metadata": {}, "outputs": [], "source": [ @@ -927,7 +927,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": {}, "outputs": [], "source": [ @@ -952,9 +952,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iter f(x) inf-norm Step 2-norm \n", + "------ -------------- --------------\n", + " 0 8.710000e+01 NaN\n", + " 1 4.664840e+01 2.860952e+02\n", + " 2 3.948627e-02 1.733579e+00\n", + " 3 1.210757e-05 1.418640e-01\n", + " 4 3.710738e-10 3.830941e-07\n", + "\n", + "Final solution:\n", + "[6738.200652737065, 1.5644718641515079e-24, 1.1947020276724434e-9, 36366.21173381801, 5.302395297764675]\n" + ] + } + ], "source": [ "# On cherche le point le plus proche de la Terre sur l'orbite initiale\n", "# Ce sera le point de départ de la pré-mission\n", @@ -1048,7 +1065,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": {}, "outputs": [], "source": [ @@ -1144,9 +1161,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iter f(x) inf-norm Step 2-norm \n", + "------ -------------- --------------\n", + " 0 7.026523e+00 NaN\n", + " 1 7.334383e-03 6.609950e-06\n", + " 2 1.068202e-08 6.699837e-06\n", + " 3 6.846676e-09 1.949020e-11\n", + "\n", + "Final solution:\n", + "[-0.0013615711124372242, -7.349896979829465e-6, -5.359923708254862e-5, -0.008582713096395626, 59.85516689032128]\n" + ] + } + ], "source": [ "# Données pour la trajectoire durant le transfert\n", "mutable struct Transfert\n", @@ -1203,7 +1236,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "metadata": {}, "outputs": [], "source": [ @@ -1226,9 +1259,50 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "LoadError", + "evalue": "MethodError: no method matching process_annotation(::Plots.Subplot{Plots.GRBackend}, ::Float64)\n\u001b[0mClosest candidates are:\n\u001b[0m process_annotation(::Plots.Subplot, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any\u001b[39m) at ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/components.jl:618\n\u001b[0m process_annotation(::Plots.Subplot, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any\u001b[39m, \u001b[91m::Any\u001b[39m) at ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/components.jl:618\n\u001b[0m process_annotation(::Plots.Subplot, \u001b[91m::Union{Symbol, Tuple, AbstractVector{Symbol}}\u001b[39m, \u001b[91m::Any\u001b[39m) at ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/components.jl:632\n\u001b[0m ...", + "output_type": "error", + "traceback": [ + "MethodError: no method matching process_annotation(::Plots.Subplot{Plots.GRBackend}, ::Float64)\n\u001b[0mClosest candidates are:\n\u001b[0m process_annotation(::Plots.Subplot, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any\u001b[39m) at ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/components.jl:618\n\u001b[0m process_annotation(::Plots.Subplot, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any\u001b[39m, \u001b[91m::Any\u001b[39m) at ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/components.jl:618\n\u001b[0m process_annotation(::Plots.Subplot, \u001b[91m::Union{Symbol, Tuple, AbstractVector{Symbol}}\u001b[39m, \u001b[91m::Any\u001b[39m) at ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/components.jl:632\n\u001b[0m ...", + "", + "Stacktrace:", + " [1] _update_subplot_periphery(sp::Plots.Subplot{Plots.GRBackend}, anns::Vector{Any})", + " @ Plots ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/args.jl:1928", + " [2] _update_subplot_args(plt::Plots.Plot{Plots.GRBackend}, sp::Plots.Subplot{Plots.GRBackend}, plotattributes_in::Dict{Symbol, Any}, subplot_index::Int64, remove_pair::Bool)", + " @ Plots ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/args.jl:2061", + " [3] _subplot_setup(plt::Plots.Plot{Plots.GRBackend}, plotattributes::Dict{Symbol, Any}, kw_list::Vector{Dict{Symbol, Any}})", + " @ Plots ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/pipeline.jl:290", + " [4] plot_setup!(plt::Plots.Plot{Plots.GRBackend}, plotattributes::Dict{Symbol, Any}, kw_list::Vector{Dict{Symbol, Any}})", + " @ Plots ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/pipeline.jl:151", + " [5] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)", + " @ RecipesPipeline ~/opt/miniconda3/envs/julia/share/julia/packages/RecipesPipeline/kJPXU/src/RecipesPipeline.jl:87", + " [6] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)", + " @ Plots ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/plot.jl:208", + " [7] #plot!#152", + " @ ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/plot.jl:198 [inlined]", + " [8] #annotate!#525", + " @ ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/Plots.jl:249 [inlined]", + " [9] panneau_information!(px::Plots.Plot{Plots.GRBackend}, subplot_current::Int64, time_current::Float64, i_current::Int64, x1::Vector{Float64}, x2::Vector{Float64}, v1::Vector{Float64}, v2::Vector{Float64}, θ::Vector{Float64}, F_max::Float64, tf_transfert::Float64, X1_orb_init::Vector{Float64}, X2_orb_init::Vector{Float64}, X1_orb_arr::Vector{Float64}, X2_orb_arr::Vector{Float64})", + " @ Main ./In[27]:63", + " [10] macro expansion", + " @ ./In[29]:202 [inlined]", + " [11] macro expansion", + " @ ~/opt/miniconda3/envs/julia/share/julia/packages/Plots/GGa6i/src/animation.jl:208 [inlined]", + " [12] animation(pre_transfert_data::PreTransfert, transfert_data::Transfert, post_transfert_data::PostTransfert; fps::Int64, nFrame::Int64)", + " @ Main ./In[29]:162", + " [13] top-level scope", + " @ In[35]:3", + " [14] eval", + " @ ./boot.jl:373 [inlined]", + " [15] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)", + " @ Base ./loading.jl:1196" + ] + } + ], "source": [ "#nFrame = 10; fps = 1\n", "nFrame = 2000; fps = 20\n", @@ -1237,9 +1311,87 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ffmpeg version 5.0.1 Copyright (c) 2000-2022 the FFmpeg developers\n", + " built with Apple clang version 13.0.0 (clang-1300.0.29.30)\n", + " configuration: --prefix=/usr/local/Cellar/ffmpeg/5.0.1_3 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox\n", + " libavutil 57. 17.100 / 57. 17.100\n", + " libavcodec 59. 18.100 / 59. 18.100\n", + " libavformat 59. 16.100 / 59. 16.100\n", + " libavdevice 59. 4.100 / 59. 4.100\n", + " libavfilter 8. 24.100 / 8. 24.100\n", + " libswscale 6. 4.100 / 6. 4.100\n", + " libswresample 4. 3.100 / 4. 3.100\n", + " libpostproc 56. 3.100 / 56. 3.100\n", + "Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'transfert-temps-min-original.mp4':\n", + " Metadata:\n", + " major_brand : isom\n", + " minor_version : 512\n", + " compatible_brands: isomiso2avc1mp41\n", + " encoder : Lavf58.76.100\n", + " Duration: 00:01:30.70, start: 0.000000, bitrate: 284 kb/s\n", + " Stream #0:0[0x1](und): Video: h264 (High 4:4:4 Predictive) (avc1 / 0x31637661), yuv444p(progressive), 1600x900, 283 kb/s, 20 fps, 20 tbr, 10240 tbn (default)\n", + " Metadata:\n", + " handler_name : VideoHandler\n", + " vendor_id : [0][0][0][0]\n", + "Stream mapping:\n", + " Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))\n", + "Press [q] to stop, [?] for help\n", + "[libx264 @ 0x7fde1b529080] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2\n", + "[libx264 @ 0x7fde1b529080] profile High, level 4.0, 4:2:0, 8-bit\n", + "[libx264 @ 0x7fde1b529080] 264 - core 164 r3095 baee400 - H.264/MPEG-4 AVC codec - Copyleft 2003-2022 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=20 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00\n", + "Output #0, mp4, to 'transfert-temps-min.mp4':\n", + " Metadata:\n", + " major_brand : isom\n", + " minor_version : 512\n", + " compatible_brands: isomiso2avc1mp41\n", + " encoder : Lavf59.16.100\n", + " Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p(tv, progressive), 1600x900, q=2-31, 20 fps, 10240 tbn (default)\n", + " Metadata:\n", + " handler_name : VideoHandler\n", + " vendor_id : [0][0][0][0]\n", + " encoder : Lavc59.18.100 libx264\n", + " Side data:\n", + " cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A\n", + "frame= 1814 fps= 66 q=-1.0 Lsize= 3013kB time=00:01:30.55 bitrate= 272.6kbits/s speed=3.31x \n", + "video:2991kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.723257%\n", + "[libx264 @ 0x7fde1b529080] frame I:8 Avg QP:15.52 size: 64104\n", + "[libx264 @ 0x7fde1b529080] frame P:544 Avg QP:20.28 size: 2445\n", + "[libx264 @ 0x7fde1b529080] frame B:1262 Avg QP:26.77 size: 966\n", + "[libx264 @ 0x7fde1b529080] consecutive B-frames: 4.1% 6.6% 8.1% 81.1%\n", + "[libx264 @ 0x7fde1b529080] mb I I16..4: 7.9% 64.6% 27.5%\n", + "[libx264 @ 0x7fde1b529080] mb P I16..4: 0.3% 0.4% 0.2% P16..4: 3.5% 0.7% 0.5% 0.0% 0.0% skip:94.4%\n", + "[libx264 @ 0x7fde1b529080] mb B I16..4: 0.0% 0.1% 0.0% B16..8: 4.0% 0.5% 0.1% direct: 0.1% skip:95.1% L0:46.8% L1:51.5% BI: 1.7%\n", + "[libx264 @ 0x7fde1b529080] 8x8 transform intra:56.6% inter:26.6%\n", + "[libx264 @ 0x7fde1b529080] coded y,uvDC,uvAC intra: 15.0% 5.8% 4.9% inter: 0.5% 0.3% 0.2%\n", + "[libx264 @ 0x7fde1b529080] i16 v,h,dc,p: 58% 39% 3% 0%\n", + "[libx264 @ 0x7fde1b529080] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 56% 5% 39% 0% 0% 0% 0% 0% 0%\n", + "[libx264 @ 0x7fde1b529080] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 48% 19% 16% 3% 3% 3% 3% 3% 3%\n", + "[libx264 @ 0x7fde1b529080] i8c dc,h,v,p: 91% 6% 3% 0%\n", + "[libx264 @ 0x7fde1b529080] Weighted P-Frames: Y:0.0% UV:0.0%\n", + "[libx264 @ 0x7fde1b529080] ref P L0: 67.7% 2.4% 19.2% 10.8%\n", + "[libx264 @ 0x7fde1b529080] ref B L0: 78.1% 17.9% 4.0%\n", + "[libx264 @ 0x7fde1b529080] ref B L1: 94.6% 5.4%\n", + "[libx264 @ 0x7fde1b529080] kb/s:270.10\n" + ] + }, + { + "data": { + "text/plain": [ + "Process(`\u001b[4mffmpeg\u001b[24m \u001b[4m-y\u001b[24m \u001b[4m-i\u001b[24m \u001b[4mtransfert-temps-min-original.mp4\u001b[24m \u001b[4m-vf\u001b[24m \u001b[4mformat=yuv420p\u001b[24m \u001b[4mtransfert-temps-min.mp4\u001b[24m`, ProcessExited(0))" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "convert = `ffmpeg -y -i transfert-temps-min-original.mp4 -vf format=yuv420p transfert-temps-min.mp4`\n", "if nFrame > 1\n",