Ok, now open loop is working, sc mass changed to state, and other updates
This commit is contained in:
@@ -2,6 +2,7 @@ stages:
|
|||||||
- test
|
- test
|
||||||
|
|
||||||
unit-test-job:
|
unit-test-job:
|
||||||
|
timeout: 2h
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
- apt-get update
|
- apt-get update
|
||||||
@@ -15,4 +16,8 @@ unit-test-job:
|
|||||||
- julia/plots/find_closest_test.html
|
- julia/plots/find_closest_test.html
|
||||||
- julia/plots/mbh_nominal.html
|
- julia/plots/mbh_nominal.html
|
||||||
- julia/plots/mbh_best.html
|
- julia/plots/mbh_best.html
|
||||||
|
- julia/plots/mbh_sun_initial.html
|
||||||
|
- julia/plots/mbh_sun_solved.html
|
||||||
|
- julia/plots/inner_loop_before.html
|
||||||
|
- julia/plots/inner_loop_after.html
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# DEFINING CONSTANTS
|
# DEFINING CONSTANTS
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
export μs, G, GMs, μ, rs, as, es, AU
|
export μs, G, GMs, μ, rs, as, es, AU, ids
|
||||||
|
|
||||||
# Gravitational Constants
|
# Gravitational Constants
|
||||||
μs = Dict(
|
μs = Dict(
|
||||||
@@ -84,17 +84,17 @@ export μs, G, GMs, μ, rs, as, es, AU
|
|||||||
|
|
||||||
# These are just the colors for plots
|
# These are just the colors for plots
|
||||||
const p_colors = Dict(
|
const p_colors = Dict(
|
||||||
"Sun" => :Electric,
|
"Sun" => "Electric",
|
||||||
"Mercury" => :heat,
|
"Mercury" => "heat",
|
||||||
"Venus" => :turbid,
|
"Venus" => "turbid",
|
||||||
"Earth" => :Blues,
|
"Earth" => "Blues",
|
||||||
"Moon" => :Greys,
|
"Moon" => "Greys",
|
||||||
"Mars" => :Reds,
|
"Mars" => "Reds",
|
||||||
"Jupiter" => :solar,
|
"Jupiter" => "solar",
|
||||||
"Saturn" => :turbid,
|
"Saturn" => "turbid",
|
||||||
"Uranus" => :haline,
|
"Uranus" => "haline",
|
||||||
"Neptune" => :ice,
|
"Neptune" => "ice",
|
||||||
"Pluto" => :matter)
|
"Pluto" => "matter")
|
||||||
|
|
||||||
const ids = Dict(
|
const ids = Dict(
|
||||||
"Sun" => 10,
|
"Sun" => 10,
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ function conv_T(Tm::Vector{Float64},
|
|||||||
Ta::Vector{Float64},
|
Ta::Vector{Float64},
|
||||||
Tb::Vector{Float64},
|
Tb::Vector{Float64},
|
||||||
init_state::Vector{Float64},
|
init_state::Vector{Float64},
|
||||||
m::Float64,
|
|
||||||
craft::Sc,
|
craft::Sc,
|
||||||
time::Float64,
|
time::Float64,
|
||||||
μ::Float64)
|
μ::Float64)
|
||||||
@@ -109,7 +108,7 @@ function conv_T(Tm::Vector{Float64},
|
|||||||
si*sθ si*cθ ci ]
|
si*sθ si*cθ ci ]
|
||||||
Tx, Ty, Tz = DCM*thrust_rθh
|
Tx, Ty, Tz = DCM*thrust_rθh
|
||||||
|
|
||||||
state = prop_one([Tx, Ty, Tz], state, craft, μ, time/n)[1]
|
state = prop_one([Tx, Ty, Tz], state, copy(craft), μ, time/n)
|
||||||
push!(Txs, Tx)
|
push!(Txs, Tx)
|
||||||
push!(Tys, Ty)
|
push!(Tys, Ty)
|
||||||
push!(Tzs, Tz)
|
push!(Tzs, Tz)
|
||||||
|
|||||||
@@ -5,16 +5,13 @@ export nlp_solve, mass_est
|
|||||||
function mass_est(T)
|
function mass_est(T)
|
||||||
ans = 0
|
ans = 0
|
||||||
n = Int(length(T)/3)
|
n = Int(length(T)/3)
|
||||||
for i in 1:n
|
for i in 1:n ans += norm(T[i,:]) end
|
||||||
ans += norm(T[i,:])
|
|
||||||
end
|
|
||||||
return ans/n
|
return ans/n
|
||||||
end
|
end
|
||||||
|
|
||||||
converged(x) = NLsolve.converged(x)
|
struct Result
|
||||||
|
converged::Bool
|
||||||
function converged(_::String)
|
zero::Matrix{Float64}
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function nlp_solve(start::Vector{Float64},
|
function nlp_solve(start::Vector{Float64},
|
||||||
@@ -28,10 +25,21 @@ function nlp_solve(start::Vector{Float64},
|
|||||||
num_iters=1_000)
|
num_iters=1_000)
|
||||||
|
|
||||||
function f!(F,x)
|
function f!(F,x)
|
||||||
|
try
|
||||||
F .= 0.0
|
F .= 0.0
|
||||||
F[1:6, 1] .= prop_nlsolve(tanh.(x), start, craft, μ, tf-t0) .- final
|
F[1:6, 1] .= prop(tanh.(x), start, copy(craft), μ, tf-t0)[2][1:6] .- final[1:6]
|
||||||
|
catch e
|
||||||
|
F .= 10000000.0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return nlsolve(f!, atanh.(x0), ftol=tol, autodiff=:forward, iterations=num_iters)
|
result = Result(false, zeros(size(x0)))
|
||||||
|
try
|
||||||
|
nl_results = nlsolve(f!, atanh.(x0), ftol=tol, autodiff=:forward, iterations=num_iters)
|
||||||
|
result = Result(converged(nl_results), tanh.(nl_results.zero))
|
||||||
|
catch e
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -8,6 +8,7 @@ there's only the outer loop left to do. And that's pretty easy.
|
|||||||
"""
|
"""
|
||||||
function inner_loop(launch_date::DateTime,
|
function inner_loop(launch_date::DateTime,
|
||||||
craft::Sc,
|
craft::Sc,
|
||||||
|
start_mass::Float64,
|
||||||
phases::Vector{Phase};
|
phases::Vector{Phase};
|
||||||
min_flyby::Float64=1000.,
|
min_flyby::Float64=1000.,
|
||||||
mbh_specs=nothing,
|
mbh_specs=nothing,
|
||||||
@@ -38,36 +39,32 @@ function inner_loop(launch_date::DateTime,
|
|||||||
δ = acos((phases[i].v∞_outgoing ⋅ phases[i-1].v∞_incoming)/v∞^2)
|
δ = acos((phases[i].v∞_outgoing ⋅ phases[i-1].v∞_incoming)/v∞^2)
|
||||||
flyby = μs[phases[i].from_planet]/v∞^2 * (1/sin(δ/2) - 1)
|
flyby = μs[phases[i].from_planet]/v∞^2 * (1/sin(δ/2) - 1)
|
||||||
true_min = rs[phases[i].from_planet] + min_flyby
|
true_min = rs[phases[i].from_planet] + min_flyby
|
||||||
if flyby <= true_min
|
flyby <= true_min || error("Flyby too low from phase $(i-1) to $(i): $(flyby) / $(true_min)")
|
||||||
error("Flyby was too low between phase $(i-1) and $(i): $(flyby) / $(true_min)")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
time = utc2et(Dates.format(launch_date,"yyyy-mm-ddTHH:MM:SS"))
|
time = utc2et(Dates.format(launch_date,"yyyy-mm-ddTHH:MM:SS"))
|
||||||
thrust_profiles = []
|
thrust_profiles = []
|
||||||
try
|
|
||||||
for phase in phases
|
for phase in phases
|
||||||
planet1_state = spkssb(ids[phase.from_planet], time, "J2000")
|
planet1_state = [spkssb(ids[phase.from_planet], time, "J2000"); 0.0]
|
||||||
time += phase.time_of_flight
|
time += phase.time_of_flight
|
||||||
planet2_state = spkssb(ids[phase.to_planet], time, "J2000")
|
planet2_state = [spkssb(ids[phase.to_planet], time, "J2000"); 0.0]
|
||||||
|
start = planet1_state + [0., 0., 0., phase.v∞_outgoing..., start_mass]
|
||||||
|
final = planet2_state + [0., 0., 0., phase.v∞_incoming..., start_mass]
|
||||||
|
println(start)
|
||||||
|
println(final)
|
||||||
# TODO: Come up with improved method of calculating "n"
|
# TODO: Come up with improved method of calculating "n"
|
||||||
start = planet1_state + [0., 0., 0., phase.v∞_outgoing...]
|
|
||||||
final = planet2_state + [0., 0., 0., phase.v∞_incoming...]
|
|
||||||
if mbh_specs === nothing
|
if mbh_specs === nothing
|
||||||
best = mbh(start, final, craft, μs["Sun"], 0.0, phase.time_of_flight, 10,
|
best = mbh(start, final, craft, μs["Sun"], 0.0, phase.time_of_flight, 20,
|
||||||
verbose=verbose)[1]
|
verbose=verbose)[1]
|
||||||
else
|
else
|
||||||
num_iters, sil, dil = mbh_specs
|
sil, dil = mbh_specs
|
||||||
best = mbh(start, final, craft, μs["Sun"], 0.0, phase.time_of_flight, 10,
|
best = mbh(start, final, craft, μs["Sun"], 0.0, phase.time_of_flight, 20,
|
||||||
verbose=verbose, num_iters=num_iters, search_patience_lim=sil,
|
verbose=verbose, search_patience_lim=sil, drill_patience_lim=dil)[1]
|
||||||
drill_patience_lim=dil)
|
|
||||||
end
|
end
|
||||||
push!(thrust_profiles, best)
|
push!(thrust_profiles, best.zero)
|
||||||
craft.mass = prop(tanh.(best.zero), planet1_state, sc, μs["Sun"], prop_time)[2][end]
|
|
||||||
end
|
|
||||||
return craft.mass, thrust_profiles
|
|
||||||
catch
|
|
||||||
return "One path did not converge"
|
|
||||||
end
|
end
|
||||||
|
return thrust_profiles
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
function laguerre_conway(state::Vector{T}, μ::Float64, time::Float64) where T
|
function laguerre_conway(state::Vector{<:Real}, μ::Float64, time::Float64)
|
||||||
|
|
||||||
n = 5 # Choose LaGuerre-Conway "n"
|
n = 5 # Choose LaGuerre-Conway "n"
|
||||||
i = 0
|
i = 0
|
||||||
|
|||||||
@@ -26,42 +26,38 @@ function mbh(start::AbstractVector,
|
|||||||
t0::AbstractFloat,
|
t0::AbstractFloat,
|
||||||
tf::AbstractFloat,
|
tf::AbstractFloat,
|
||||||
n::Int;
|
n::Int;
|
||||||
num_iters=25,
|
search_patience_lim::Int=2000,
|
||||||
search_patience_lim::Int=200,
|
drill_patience_lim::Int=40,
|
||||||
drill_patience_lim::Int=200,
|
|
||||||
tol=1e-6,
|
tol=1e-6,
|
||||||
verbose=false)
|
verbose=false)
|
||||||
|
|
||||||
archive = []
|
archive = []
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
if verbose println("Current Iteration") end
|
x_current = Result(false, 1e8*ones(n,3))
|
||||||
while true
|
while i < search_patience_lim
|
||||||
i += 1
|
i += 1
|
||||||
if verbose print("\r",i) end
|
|
||||||
search_impatience = 0
|
|
||||||
drill_impatience = 0
|
drill_impatience = 0
|
||||||
x_star = nlp_solve(start, final, craft, μ, t0, tf, new_x(n), tol=tol, num_iters=100)
|
if verbose print("\r\t", "search: ", i, " drill: ", drill_impatience, " ") end
|
||||||
while converged(x_star) == false && search_impatience < search_patience_lim
|
x_star = nlp_solve(start, final, craft, μ, t0, tf, new_x(n), tol=tol)
|
||||||
search_impatience += 1
|
# If x_star is converged and better, set new x_current
|
||||||
x_star = nlp_solve(start, final, craft, μ, t0, tf, new_x(n), tol=tol, num_iters=100)
|
if x_star.converged && mass_est(x_star.zero) < mass_est(x_current.zero)
|
||||||
end
|
|
||||||
if drill_impatience > drill_patience_lim break end
|
|
||||||
drill_impatience = 0
|
|
||||||
if converged(x_star)
|
|
||||||
x_current = x_star
|
x_current = x_star
|
||||||
|
end
|
||||||
|
# If x_star is converged, drill down, otherwise, start over
|
||||||
|
if x_star.converged
|
||||||
while drill_impatience < drill_patience_lim
|
while drill_impatience < drill_patience_lim
|
||||||
x_star = nlp_solve(start, final, craft, μ, t0, tf, perturb(tanh.(x_current.zero),n), tol=tol)
|
x_star = nlp_solve(start, final, craft, μ, t0, tf, perturb(x_current.zero,n), tol=tol)
|
||||||
if converged(x_star) && mass_est(tanh.(x_star.zero)) < mass_est(tanh.(x_current.zero))
|
if x_star.converged && mass_est(x_star.zero) < mass_est(x_current.zero)
|
||||||
x_current = x_star
|
x_current = x_star
|
||||||
drill_impatience = 0
|
drill_impatience = 0
|
||||||
else
|
else
|
||||||
|
if verbose print("\r\t", "search: ", i, " drill: ", drill_impatience, " ") end
|
||||||
drill_impatience += 1
|
drill_impatience += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
push!(archive, x_current)
|
push!(archive, x_current)
|
||||||
end
|
end
|
||||||
if i >= num_iters break end
|
|
||||||
end
|
end
|
||||||
if verbose println() end
|
if verbose println() end
|
||||||
|
|
||||||
@@ -70,8 +66,8 @@ function mbh(start::AbstractVector,
|
|||||||
current_best_mass = 1e8
|
current_best_mass = 1e8
|
||||||
best = archive[1]
|
best = archive[1]
|
||||||
for candidate in archive
|
for candidate in archive
|
||||||
if mass_est(tanh.(candidate.zero)) < current_best_mass
|
if mass_est(candidate.zero) < current_best_mass
|
||||||
current_best_mass = mass_est(tanh.(candidate.zero))
|
current_best_mass = mass_est(candidate.zero)
|
||||||
best = candidate
|
best = candidate
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,234 +3,80 @@ export prop
|
|||||||
"""
|
"""
|
||||||
Maximum ΔV that a spacecraft can impulse for a given single time step
|
Maximum ΔV that a spacecraft can impulse for a given single time step
|
||||||
"""
|
"""
|
||||||
function max_ΔV(duty_cycle::T,
|
function max_ΔV(duty_cycle::Float64,
|
||||||
num_thrusters::Int,
|
|
||||||
max_thrust::T,
|
|
||||||
tf::T,
|
|
||||||
t0::T,
|
|
||||||
mass::S) where {T <: Real, S <: Real}
|
|
||||||
return duty_cycle*num_thrusters*max_thrust*(tf-t0)/mass
|
|
||||||
end
|
|
||||||
|
|
||||||
"""
|
|
||||||
This function propagates the spacecraft forward in time 1 Sim-Flanagan step (of variable length of time),
|
|
||||||
applying a thrust in the center.
|
|
||||||
"""
|
|
||||||
function prop_one(thrust_unit::Vector{<:Real},
|
|
||||||
state::Vector{<:Real},
|
|
||||||
duty_cycle::Float64,
|
|
||||||
num_thrusters::Int,
|
num_thrusters::Int,
|
||||||
max_thrust::Float64,
|
max_thrust::Float64,
|
||||||
mass::T,
|
tf::Float64,
|
||||||
mass_flow_rate::Float64,
|
t0::Float64,
|
||||||
μ::Float64,
|
mass::T) where T <: Real
|
||||||
time::Float64) where T<:Real
|
return duty_cycle*num_thrusters*max_thrust*(tf-t0)/mass
|
||||||
|
|
||||||
ΔV = max_ΔV(duty_cycle, num_thrusters, max_thrust, time, 0., mass) * thrust_unit
|
|
||||||
halfway = laguerre_conway(state, μ, time/2) + [0., 0., 0., ΔV...]
|
|
||||||
return laguerre_conway(halfway, μ, time/2), mass - mass_flow_rate*norm(thrust_unit)*time
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A convenience function for using spacecraft. Note that this function outputs a sc instead of a mass
|
A convenience function for using spacecraft. Note that this function outputs a sc instead of a mass
|
||||||
"""
|
"""
|
||||||
function prop_one(ΔV_unit::Vector{T},
|
function prop_one(ΔV_unit::Vector{<:Real},
|
||||||
state::Vector{S},
|
state::Vector{<:Real},
|
||||||
craft::Sc,
|
craft::Sc,
|
||||||
μ::Float64,
|
μ::Float64,
|
||||||
time::Float64) where {T <: Real,S <: Real}
|
time::Float64)
|
||||||
state, mass = prop_one(ΔV_unit, state, craft.duty_cycle, craft.num_thrusters, craft.max_thrust,
|
|
||||||
craft.mass, craft.mass_flow_rate, μ, time)
|
for direction in ΔV_unit
|
||||||
return state, Sc(mass, craft.mass_flow_rate, craft.max_thrust, craft.num_thrusters, craft.duty_cycle)
|
if abs(direction) > 1.0
|
||||||
|
println(direction)
|
||||||
|
error("ΔV is impossibly high")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ΔV = max_ΔV(craft.duty_cycle, craft.num_thrusters, craft.max_thrust, time, 0., state[7]) * ΔV_unit
|
||||||
|
halfway = laguerre_conway(state, μ, time/2) + [zeros(3); ΔV]
|
||||||
|
final = laguerre_conway(halfway, μ, time/2)
|
||||||
|
return [final; state[7] - craft.mass_flow_rate*norm(ΔV_unit)*time]
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This propagates over a given time period, with a certain number of intermediate steps
|
The propagator function
|
||||||
"""
|
"""
|
||||||
function prop(ΔVs::Matrix{T},
|
function prop(ΔVs::Matrix{T},
|
||||||
state::Vector{Float64},
|
state::Vector{Float64},
|
||||||
duty_cycle::Float64,
|
craft::Sc,
|
||||||
num_thrusters::Int,
|
|
||||||
max_thrust::Float64,
|
|
||||||
mass::Float64,
|
|
||||||
mass_flow_rate::Float64,
|
|
||||||
μ::Float64,
|
μ::Float64,
|
||||||
time::Float64) where T <: Real
|
time::Float64) where T <: Real
|
||||||
|
|
||||||
if size(ΔVs)[2] != 3 throw(ErrorException("ΔV input is wrong size")) end
|
|
||||||
n = size(ΔVs)[i]
|
|
||||||
|
|
||||||
for i in 1:n
|
|
||||||
state, mass = prop_one(ΔVs[i,:], state, duty_cycle, num_thrusters, max_thrust, mass,
|
|
||||||
mass_flow_rate, μ, time/n)
|
|
||||||
end
|
|
||||||
|
|
||||||
return state, mass
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
"""
|
|
||||||
The same function, using Scs
|
|
||||||
"""
|
|
||||||
function prop(ΔVs::Matrix{T},
|
|
||||||
state::Vector{S},
|
|
||||||
craft::Sc,
|
|
||||||
μ::Float64,
|
|
||||||
time::Float64) where {T <: Real, S <: Real}
|
|
||||||
|
|
||||||
if size(ΔVs)[2] != 3 throw(ErrorException("ΔV input is wrong size")) end
|
if size(ΔVs)[2] != 3 throw(ErrorException("ΔV input is wrong size")) end
|
||||||
n = size(ΔVs)[1]
|
n = size(ΔVs)[1]
|
||||||
|
|
||||||
x_states = [state[1]]
|
x_states = Vector{T}()
|
||||||
y_states = [state[2]]
|
y_states = Vector{T}()
|
||||||
z_states = [state[3]]
|
z_states = Vector{T}()
|
||||||
dx_states = [state[4]]
|
dx_states = Vector{T}()
|
||||||
dy_states = [state[5]]
|
dy_states = Vector{T}()
|
||||||
dz_states = [state[6]]
|
dz_states = Vector{T}()
|
||||||
masses = [craft.mass]
|
masses = Vector{T}()
|
||||||
|
|
||||||
for i in 1:n
|
|
||||||
state, craft = prop_one(ΔVs[i,:], state, craft, μ, time/n)
|
|
||||||
push!(x_states, state[1])
|
push!(x_states, state[1])
|
||||||
push!(y_states, state[2])
|
push!(y_states, state[2])
|
||||||
push!(z_states, state[3])
|
push!(z_states, state[3])
|
||||||
push!(dx_states, state[4])
|
push!(dx_states, state[4])
|
||||||
push!(dy_states, state[5])
|
push!(dy_states, state[5])
|
||||||
push!(dz_states, state[6])
|
push!(dz_states, state[6])
|
||||||
push!(masses, craft.mass)
|
push!(masses, state[7])
|
||||||
end
|
|
||||||
|
|
||||||
return [x_states, y_states, z_states, dx_states, dy_states, dz_states], masses, state
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function prop_nlsolve(ΔVs::Matrix{T},
|
|
||||||
state::Vector{S},
|
|
||||||
craft::Sc,
|
|
||||||
μ::Float64,
|
|
||||||
time::Float64) where {T <: Real, S <: Real}
|
|
||||||
|
|
||||||
n = size(ΔVs)[1]
|
|
||||||
try
|
|
||||||
for i in 1:n
|
|
||||||
state, craft = prop_one(ΔVs[i,:], state, craft, μ, time/n)
|
|
||||||
end
|
|
||||||
return state
|
|
||||||
catch
|
|
||||||
return [0., 0., 0., 0., 0., 0.]
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function prop_simple(ΔVs::AbstractMatrix,
|
|
||||||
state::AbstractVector,
|
|
||||||
craft::Sc,
|
|
||||||
μ::Float64,
|
|
||||||
time::Float64)
|
|
||||||
|
|
||||||
if size(ΔVs)[2] != 3 throw(ErrorException("ΔV input is wrong size")) end
|
|
||||||
n = size(ΔVs)[1]
|
|
||||||
|
|
||||||
for i in 1:n
|
for i in 1:n
|
||||||
state, craft = prop_one(ΔVs[i,:], state, craft, μ, time/n)
|
state = prop_one(ΔVs[i,:], state, craft, μ, time/n)
|
||||||
|
push!(x_states, state[1])
|
||||||
|
push!(y_states, state[2])
|
||||||
|
push!(z_states, state[3])
|
||||||
|
push!(dx_states, state[4])
|
||||||
|
push!(dy_states, state[5])
|
||||||
|
push!(dz_states, state[6])
|
||||||
|
push!(masses, state[7])
|
||||||
|
if state[7] < craft.dry_mass
|
||||||
|
println(state[7])
|
||||||
|
error("Mass is too low")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return state
|
return [x_states, y_states, z_states, dx_states, dy_states, dz_states, masses], state
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function prop_one_simple(Tx, Ty, Tz, x, y, z, dx, dy, dz, t, μ)
|
|
||||||
|
|
||||||
# perform laguerre_conway once
|
|
||||||
r0_mag = √(x^2 + y^2 + z^2)
|
|
||||||
v0_mag = √(dx^2 + dy^2 + dz^2)
|
|
||||||
σ0 = ([x, y, z] ⋅ [dx, dy, dz])/√(μ)
|
|
||||||
a = 1 / ( 2/r0_mag - v0_mag^2/μ )
|
|
||||||
coeff = 1 - r0_mag/a
|
|
||||||
|
|
||||||
if a > 0 # Elliptical
|
|
||||||
ΔM = ΔE_new = √(μ) / sqrt(a^3) * t/2
|
|
||||||
ΔE = 1000
|
|
||||||
while abs(ΔE - ΔE_new) > 1e-10
|
|
||||||
ΔE = ΔE_new
|
|
||||||
F = ΔE - ΔM + σ0 / √(a) * (1-cos(ΔE)) - coeff * sin(ΔE)
|
|
||||||
dF = 1 + σ0 / √(a) * sin(ΔE) - coeff * cos(ΔE)
|
|
||||||
d2F = σ0 / √(a) * cos(ΔE) + coeff * sin(ΔE)
|
|
||||||
sign = dF >= 0 ? 1 : -1
|
|
||||||
ΔE_new = ΔE - 5*F / ( dF + sign * √(abs((5-1)^2*dF^2 - 5*(5-1)*F*d2F )))
|
|
||||||
end
|
|
||||||
F = 1 - a/r0_mag * (1-cos(ΔE))
|
|
||||||
G = a * σ0/ √(μ) * (1-cos(ΔE)) + r0_mag * √(a) / √(μ) * sin(ΔE)
|
|
||||||
r = a + (r0_mag - a) * cos(ΔE) + σ0 * √(a) * sin(ΔE)
|
|
||||||
Ft = -√(a)*√(μ) / (r*r0_mag) * sin(ΔE)
|
|
||||||
Gt = 1 - a/r * (1-cos(ΔE))
|
|
||||||
else # Hyperbolic or Parabolic
|
|
||||||
ΔN = √(μ) / sqrt(-a^3) * t/2
|
|
||||||
ΔH = 0
|
|
||||||
ΔH_new = t/2 < 0 ? -1 : 1
|
|
||||||
while abs(ΔH - ΔH_new) > 1e-10
|
|
||||||
ΔH = ΔH_new
|
|
||||||
F = -ΔN - ΔH + σ0 / √(-a) * (cos(ΔH)-1) + coeff * sin(ΔH)
|
|
||||||
dF = -1 + σ0 / √(-a) * sin(ΔH) + coeff * cos(ΔH)
|
|
||||||
d2F = σ0 / √(-a) * cos(ΔH) + coeff * sin(ΔH)
|
|
||||||
sign = dF >= 0 ? 1 : -1
|
|
||||||
ΔH_new = ΔH - 5*F / ( dF + sign * √(abs((5-1)^2*dF^2 - 5*(5-1)*F*d2F )))
|
|
||||||
end
|
|
||||||
F = 1 - a/r0_mag * (1-cos(ΔH))
|
|
||||||
G = a * σ0/ √(μ) * (1-cos(ΔH)) + r0_mag * √(-a) / √(μ) * sin(ΔH)
|
|
||||||
r = a + (r0_mag - a) * cos(ΔH) + σ0 * √(-a) * sin(ΔH)
|
|
||||||
Ft = -√(-a)*√(μ) / (r*r0_mag) * sin(ΔH)
|
|
||||||
Gt = 1 - a/r * (1-cos(ΔH))
|
|
||||||
end
|
|
||||||
|
|
||||||
# add the thrust vector
|
|
||||||
x,y,z,dx,dy,dz = [F*[x,y,z] + G*[dx,dy,dz]; Ft*[x,y,z] + Gt*[dx,dy,dz] + [Tx, Ty, Tz]]
|
|
||||||
|
|
||||||
#perform again
|
|
||||||
r0_mag = √(x^2 + y^2 + z^2)
|
|
||||||
v0_mag = √(dx^2 + dy^2 + dz^2)
|
|
||||||
σ0 = ([x, y, z] ⋅ [dx, dy, dz])/√(μ)
|
|
||||||
a = 1 / ( 2/r0_mag - v0_mag^2/μ )
|
|
||||||
coeff = 1 - r0_mag/a
|
|
||||||
|
|
||||||
if a > 0 # Elliptical
|
|
||||||
ΔM = ΔE_new = √(μ) / sqrt(a^3) * t/2
|
|
||||||
ΔE = 1000
|
|
||||||
while abs(ΔE - ΔE_new) > 1e-10
|
|
||||||
ΔE = ΔE_new
|
|
||||||
F = ΔE - ΔM + σ0 / √(a) * (1-cos(ΔE)) - coeff * sin(ΔE)
|
|
||||||
dF = 1 + σ0 / √(a) * sin(ΔE) - coeff * cos(ΔE)
|
|
||||||
d2F = σ0 / √(a) * cos(ΔE) + coeff * sin(ΔE)
|
|
||||||
sign = dF >= 0 ? 1 : -1
|
|
||||||
ΔE_new = ΔE - 5*F / ( dF + sign * √(abs((5-1)^2*dF^2 - 5*(5-1)*F*d2F )))
|
|
||||||
end
|
|
||||||
F = 1 - a/r0_mag * (1-cos(ΔE))
|
|
||||||
G = a * σ0/ √(μ) * (1-cos(ΔE)) + r0_mag * √(a) / √(μ) * sin(ΔE)
|
|
||||||
r = a + (r0_mag - a) * cos(ΔE) + σ0 * √(a) * sin(ΔE)
|
|
||||||
Ft = -√(a)*√(μ) / (r*r0_mag) * sin(ΔE)
|
|
||||||
Gt = 1 - a/r * (1-cos(ΔE))
|
|
||||||
else # Hyperbolic or Parabolic
|
|
||||||
ΔN = √(μ) / sqrt(-a^3) * t/2
|
|
||||||
ΔH = 0
|
|
||||||
ΔH_new = t/2 < 0 ? -1 : 1
|
|
||||||
while abs(ΔH - ΔH_new) > 1e-10
|
|
||||||
ΔH = ΔH_new
|
|
||||||
F = -ΔN - ΔH + σ0 / √(-a) * (cos(ΔH)-1) + coeff * sin(ΔH)
|
|
||||||
dF = -1 + σ0 / √(-a) * sin(ΔH) + coeff * cos(ΔH)
|
|
||||||
d2F = σ0 / √(-a) * cos(ΔH) + coeff * sin(ΔH)
|
|
||||||
sign = dF >= 0 ? 1 : -1
|
|
||||||
ΔH_new = ΔH - 5*F / ( dF + sign * √(abs((5-1)^2*dF^2 - 5*(5-1)*F*d2F )))
|
|
||||||
end
|
|
||||||
F = 1 - a/r0_mag * (1-cos(ΔH))
|
|
||||||
G = a * σ0/ √(μ) * (1-cos(ΔH)) + r0_mag * √(-a) / √(μ) * sin(ΔH)
|
|
||||||
r = a + (r0_mag - a) * cos(ΔH) + σ0 * √(-a) * sin(ΔH)
|
|
||||||
Ft = -√(-a)*√(μ) / (r*r0_mag) * sin(ΔH)
|
|
||||||
Gt = 1 - a/r * (1-cos(ΔH))
|
|
||||||
end
|
|
||||||
|
|
||||||
return [F*[x,y,z] + G*[dx,dy,dz]; Ft*[x,y,z] + Gt*[dx,dy,dz]]
|
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -38,6 +38,12 @@ function plot_orbits(paths::Vector{Vector{Vector{Float64}}};
|
|||||||
color = colors != [] ? colors[i] : random_color()
|
color = colors != [] ? colors[i] : random_color()
|
||||||
push!(t1, scatter3d(;x=(path[1]),y=(path[2]),z=(path[3]),
|
push!(t1, scatter3d(;x=(path[1]),y=(path[2]),z=(path[3]),
|
||||||
mode="lines", name=label, line_color=color, line_width=3))
|
mode="lines", name=label, line_color=color, line_width=3))
|
||||||
|
push!(t1, scatter3d(;x=([path[1][1]]),y=([path[2][1]]),z=([path[3][1]]),
|
||||||
|
mode="markers", showlegend=false,
|
||||||
|
marker=attr(color=color, size=3, symbol="circle")))
|
||||||
|
push!(t1, scatter3d(;x=([path[1][end]]),y=([path[2][end]]),z=([path[3][end]]),
|
||||||
|
mode="markers", showlegend=false,
|
||||||
|
marker=attr(color=color, size=3, symbol="diamond")))
|
||||||
end
|
end
|
||||||
limit = max(maximum(abs.(flatten(flatten(paths)))),
|
limit = max(maximum(abs.(flatten(flatten(paths)))),
|
||||||
maximum(abs.(flatten(ps)))) * 1.1
|
maximum(abs.(flatten(ps)))) * 1.1
|
||||||
@@ -48,10 +54,11 @@ function plot_orbits(paths::Vector{Vector{Vector{Float64}}};
|
|||||||
showscale=false,
|
showscale=false,
|
||||||
colorscale = p_colors[primary])
|
colorscale = p_colors[primary])
|
||||||
|
|
||||||
layout = Layout(;title=title,
|
layout = Layout(title=title,
|
||||||
width=1000,
|
width=1000,
|
||||||
height=600,
|
height=600,
|
||||||
paper_bgcolor="#222529",
|
paper_bgcolor="rgba(5,10,40,1.0)",
|
||||||
|
plot_bgcolor="rgba(100,100,100,0.01)",
|
||||||
scene = attr(xaxis = attr(autorange = false,range=[-limit,limit]),
|
scene = attr(xaxis = attr(autorange = false,range=[-limit,limit]),
|
||||||
yaxis = attr(autorange = false,range=[-limit,limit]),
|
yaxis = attr(autorange = false,range=[-limit,limit]),
|
||||||
zaxis = attr(autorange = false,range=[-limit,limit]),
|
zaxis = attr(autorange = false,range=[-limit,limit]),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export Sc
|
export Sc
|
||||||
struct Sc{T <: Real}
|
mutable struct Sc
|
||||||
mass::T
|
dry_mass::Float64
|
||||||
mass_flow_rate::Float64
|
mass_flow_rate::Float64
|
||||||
max_thrust::Float64
|
max_thrust::Float64
|
||||||
num_thrusters::Int
|
num_thrusters::Int
|
||||||
@@ -8,11 +8,17 @@ struct Sc{T <: Real}
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Sc(name::String)
|
function Sc(name::String)
|
||||||
|
# This has extra thrusters to make plots more visible (and most don't use fuel)
|
||||||
if name == "test"
|
if name == "test"
|
||||||
return Sc(10000., 0.01, 0.05, 2, 1.)
|
return Sc(9000., 0.00025/(2000*0.00981), 0.00025, 50, 0.9)
|
||||||
|
# This is the normal one
|
||||||
|
elseif name == "bepi"
|
||||||
|
return Sc(9000., 2*0.00025/(2000*0.00981), 0.00025, 2, 0.9)
|
||||||
elseif name == "no_thrust"
|
elseif name == "no_thrust"
|
||||||
return Sc(10000., 0.01, 0., 0, 0.)
|
return Sc(9000., 0.01, 0., 0, 0.)
|
||||||
else
|
else
|
||||||
throw(ErrorException("Bad sc name"))
|
throw(ErrorException("Bad sc name"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Base.copy(s::Sc) = Sc(s.dry_mass, s.mass_flow_rate, s.max_thrust, s.num_thrusters, s.duty_cycle)
|
||||||
|
|||||||
@@ -6,45 +6,45 @@
|
|||||||
|
|
||||||
# Initial Setup
|
# Initial Setup
|
||||||
sc = Sc("test")
|
sc = Sc("test")
|
||||||
|
fresh_sc = copy(sc)
|
||||||
a = rand(25000:1.:40000)
|
a = rand(25000:1.:40000)
|
||||||
e = rand(0.01:0.01:0.05)
|
e = rand(0.01:0.01:0.05)
|
||||||
i = rand(0.01:0.01:π/6)
|
i = rand(0.01:0.01:π/6)
|
||||||
T = 2π*√(a^3/μs["Earth"])
|
T = 2π*√(a^3/μs["Earth"])
|
||||||
prop_time = T
|
prop_time = 5T
|
||||||
n = 10
|
n = 200
|
||||||
|
|
||||||
# A simple orbit raising
|
# A simple orbit raising
|
||||||
start = oe_to_xyz([ a, e, i, 0., 0., 0. ], μs["Earth"])
|
start_mass = 10_000.
|
||||||
Tx, Ty, Tz = conv_T(repeat([0.6], n), repeat([0.], n), repeat([0.], n),
|
start = [ oe_to_xyz([ a, e, i, 0., 0., 0. ], μs["Earth"]); start_mass ]
|
||||||
|
Tx, Ty, Tz = conv_T(repeat([0.9], n), repeat([0.], n), repeat([0.], n),
|
||||||
start,
|
start,
|
||||||
sc.mass,
|
|
||||||
sc,
|
sc,
|
||||||
prop_time,
|
prop_time,
|
||||||
μs["Earth"])
|
μs["Earth"])
|
||||||
final = prop(hcat(Tx, Ty, Tz), start, sc, μs["Earth"], prop_time)[3]
|
final = prop(hcat(Tx, Ty, Tz), start, copy(sc), μs["Earth"], prop_time)[2]
|
||||||
new_T = 2π*√(xyz_to_oe(final, μs["Earth"])[1]^3/μs["Earth"])
|
new_T = 2π*√(xyz_to_oe(final, μs["Earth"])[1]^3/μs["Earth"])
|
||||||
|
|
||||||
# This should be close enough to 0.6 for convergence
|
# This should be close enough to converge
|
||||||
Tx, Ty, Tz = conv_T(repeat([0.59], n), repeat([0.01], n), repeat([0.], n),
|
Tx, Ty, Tz = conv_T(repeat([0.89], n), repeat([0.], n), repeat([0.], n),
|
||||||
start,
|
start,
|
||||||
sc.mass,
|
|
||||||
sc,
|
sc,
|
||||||
prop_time,
|
prop_time,
|
||||||
μs["Earth"])
|
μs["Earth"])
|
||||||
result = nlp_solve(start, final, sc, μs["Earth"], 0.0, prop_time, hcat(Tx, Ty, Tz))
|
result = nlp_solve(start, final, sc, μs["Earth"], 0.0, prop_time, hcat(Tx, Ty, Tz))
|
||||||
|
|
||||||
# Test and plot
|
# Test and plot
|
||||||
@test converged(result)
|
@test result.converged
|
||||||
path1 = prop(zeros((100,3)), start, sc, μs["Earth"], T)[1]
|
path1 = prop(zeros((100,3)), start, sc, μs["Earth"], T)[1]
|
||||||
path2, mass, calc_final = prop(tanh.(result.zero), start, sc, μs["Earth"], prop_time)
|
path2, calc_final = prop(result.zero, start, sc, μs["Earth"], prop_time)
|
||||||
path3 = prop(zeros((100,3)), calc_final, sc, μs["Earth"], new_T)[1]
|
path3 = prop(zeros((100,3)), calc_final, sc, μs["Earth"], new_T)[1]
|
||||||
path4 = prop(zeros((100,3)), final, sc, μs["Earth"], new_T)[1]
|
path4 = prop(zeros((100,3)), final, fresh_sc, μs["Earth"], new_T)[1]
|
||||||
savefig(plot_orbits([path1, path2, path3, path4],
|
savefig(plot_orbits([path1, path2, path3, path4],
|
||||||
labels=["initial", "transit", "after transit", "final"],
|
labels=["initial", "transit", "after transit", "final"],
|
||||||
colors=["#FFFFFF","#FF4444","#44FF44","#4444FF"]),
|
colors=["#FFFFFF","#FF4444","#44FF44","#4444FF"]),
|
||||||
"../plots/find_closest_test.html")
|
"../plots/find_closest_test.html")
|
||||||
if converged(result)
|
if result.converged
|
||||||
@test norm(calc_final - final) < 1e-4
|
@test norm(calc_final[1:6] - final[1:6]) < 1e-4
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,28 +2,73 @@
|
|||||||
|
|
||||||
println("Testing Inner Loop")
|
println("Testing Inner Loop")
|
||||||
|
|
||||||
using Dates
|
using Dates, SPICE, PlotlyJS
|
||||||
|
|
||||||
sc = Sc("test")
|
sc = Sc("test")
|
||||||
|
|
||||||
phase1 = Phase("Earth",
|
launch_date = DateTime(2016,3,28)
|
||||||
"Mars",
|
launch_j2000 = utc2et(Dates.format(launch_date,"yyyy-mm-ddTHH:MM:SS"))
|
||||||
3600*24*365*1.85,
|
leg1_tof = 3600*24*30*10.75
|
||||||
[1., 0.3, 0.],
|
leg2_tof = 3600*24*365*5.5
|
||||||
[3., 3., 0.])
|
v∞s = [ [0.34251772594197877, -2.7344726708862477, -1.1854707164631975],
|
||||||
|
[-1.1, -3., -2.6],
|
||||||
|
[3.5, 3.5, √(5^2 - 2*3.5^2)],
|
||||||
|
[0.3, 1., 0.] ]
|
||||||
|
p1 = "Mars"
|
||||||
|
p2 = "Saturn"
|
||||||
|
start_mass = 10_000.
|
||||||
|
|
||||||
phase2 = Phase("Mars",
|
phase1 = Phase("Earth", p1, leg1_tof, v∞s[1], v∞s[2])
|
||||||
"Jupiter",
|
phase2 = Phase(p1, p2, leg2_tof, v∞s[3], v∞s[4])
|
||||||
3600*24*365*3.5,
|
|
||||||
[2., 3.7416573867739413, 0.],
|
|
||||||
[0.3, 1., 0.])
|
|
||||||
|
|
||||||
result = inner_loop(DateTime(2024,3,5),
|
# For finding the best trajectories
|
||||||
|
earth_state = [spkssb(Thesis.ids["Earth"], launch_j2000, "J2000"); start_mass]
|
||||||
|
p1_state = [spkssb(Thesis.ids[p1], launch_j2000+leg1_tof, "J2000"); start_mass]
|
||||||
|
p2_state = [spkssb(Thesis.ids[p2], launch_j2000+leg1_tof+leg2_tof, "J2000"); start_mass]
|
||||||
|
earth = prop(zeros(100,3), earth_state, sc, μs["Sun"], 3600*24*365.)[1]
|
||||||
|
p1_path = prop(zeros(100,3), p1_state, sc, μs["Sun"], 3600*24*365*2.)[1]
|
||||||
|
p2_path = prop(zeros(100,3), p2_state, sc, μs["Sun"], 3600*24*365*8.)[1]
|
||||||
|
leg1, leg1_final = prop(zeros(400,3),
|
||||||
|
earth_state+[zeros(3);v∞s[1];start_mass],
|
||||||
|
copy(sc),
|
||||||
|
μs["Sun"],
|
||||||
|
leg1_tof)
|
||||||
|
leg2, leg2_final = prop(zeros(400,3),
|
||||||
|
p1_state+[zeros(3);v∞s[3];start_mass],
|
||||||
|
copy(sc),
|
||||||
|
μs["Sun"],
|
||||||
|
leg2_tof)
|
||||||
|
savefig(plot_orbits( [earth, p1_path, p2_path, leg1, leg2],
|
||||||
|
primary="Sun",
|
||||||
|
labels=["Earth", p1, p2, "Leg 1", "Leg 2"],
|
||||||
|
title="Inner Loop without thrusting",
|
||||||
|
colors=["#0000FF", "#FF0000", "#FFFF00", "#FF00FF", "#00FFFF"] ),
|
||||||
|
"../plots/inner_loop_before.html")
|
||||||
|
|
||||||
|
# The first leg should be valid
|
||||||
|
fresh_sc = copy(sc)
|
||||||
|
mass, thrusts = inner_loop( launch_date,
|
||||||
sc,
|
sc,
|
||||||
|
start_mass,
|
||||||
|
[phase1],
|
||||||
|
verbose=true,
|
||||||
|
mbh_specs=(25,50) )
|
||||||
|
@test sc.mass > sc.dry_mass
|
||||||
|
path, final = prop(thrusts[1], earth_state+[zeros(3);v∞s[1]], fresh_sc, μs["Sun"], leg1_tof)
|
||||||
|
@test final ≈ p1_state + [zeros(3); v∞s[2]]
|
||||||
|
savefig(plot_orbits( [earth, p1_path, path],
|
||||||
|
primary="Sun",
|
||||||
|
labels=["Earth", p1, "Leg 1"],
|
||||||
|
title="Inner Loop with thrusting",
|
||||||
|
colors=["#0000FF", "#FF0000", "#FF00FF"] ),
|
||||||
|
"../plots/inner_loop_after.html")
|
||||||
|
|
||||||
|
# The second one was too hard to figure out on my own, so I'm letting it fail
|
||||||
|
@test_throws ErrorException inner_loop( launch_date,
|
||||||
|
sc,
|
||||||
|
start_mass,
|
||||||
[phase1, phase2],
|
[phase1, phase2],
|
||||||
verbose=true,
|
verbose=true,
|
||||||
mbh_specs=(5,50,100))
|
mbh_specs=(10,10) )
|
||||||
|
|
||||||
@test result == "One path did not converge"
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,28 +1,27 @@
|
|||||||
@testset "Monotonic Basin Hopping" begin
|
@testset "Monotonic Basin Hopping" begin
|
||||||
|
|
||||||
using PlotlyJS, NLsolve
|
using PlotlyJS, NLsolve, Dates
|
||||||
|
|
||||||
println("Testing Monotonic Basin Hopper")
|
println("Testing Monotonic Basin Hopper")
|
||||||
|
|
||||||
# Initial Setup
|
# Initial Setup
|
||||||
sc = Sc("test")
|
sc = Sc("test")
|
||||||
a = rand(15000:1.:40000)
|
a = rand(50_000:1.:100_000)
|
||||||
e = rand(0.01:0.01:0.5)
|
e = rand(0.01:0.01:0.5)
|
||||||
i = rand(0.01:0.01:π/6)
|
i = rand(0.01:0.01:π/6)
|
||||||
T = 2π*√(a^3/μs["Earth"])
|
T = 2π*√(a^3/μs["Earth"])
|
||||||
prop_time = 0.75T
|
prop_time = 0.5T
|
||||||
n = 10
|
n = 20
|
||||||
|
start_mass = 10_000.
|
||||||
|
|
||||||
# A simple orbit raising
|
# A simple orbit raising
|
||||||
start = oe_to_xyz([ a, e, i, 0., 0., 0. ], μs["Earth"])
|
start = [oe_to_xyz([ a, e, i, 0., 0., 0. ], μs["Earth"]); start_mass]
|
||||||
# T_craft = hcat(repeat([0.6], n), repeat([0.], n), repeat([0.], n))
|
|
||||||
Tx, Ty, Tz = conv_T(repeat([0.8], n), repeat([0.], n), repeat([0.], n),
|
Tx, Ty, Tz = conv_T(repeat([0.8], n), repeat([0.], n), repeat([0.], n),
|
||||||
start,
|
start,
|
||||||
sc.mass,
|
|
||||||
sc,
|
sc,
|
||||||
prop_time,
|
prop_time,
|
||||||
μs["Earth"])
|
μs["Earth"])
|
||||||
nominal_path, normal_mass, final = prop(hcat(Tx, Ty, Tz), start, sc, μs["Earth"], prop_time)
|
nominal_path, final = prop(hcat(Tx, Ty, Tz), start, sc, μs["Earth"], prop_time)
|
||||||
new_T = 2π*√(xyz_to_oe(final, μs["Earth"])[1]^3/μs["Earth"])
|
new_T = 2π*√(xyz_to_oe(final, μs["Earth"])[1]^3/μs["Earth"])
|
||||||
|
|
||||||
# Find the best solution
|
# Find the best solution
|
||||||
@@ -33,14 +32,13 @@
|
|||||||
0.0,
|
0.0,
|
||||||
prop_time,
|
prop_time,
|
||||||
n,
|
n,
|
||||||
num_iters=5,
|
search_patience_lim=25,
|
||||||
search_patience_lim=50,
|
drill_patience_lim=50,
|
||||||
drill_patience_lim=100,
|
|
||||||
verbose=true)
|
verbose=true)
|
||||||
|
|
||||||
# Test and plot
|
# Test and plot
|
||||||
@test converged(best)
|
@test best.converged
|
||||||
transit, best_masses, calc_final = prop(tanh.(best.zero), start, sc, μs["Earth"], prop_time)
|
transit, calc_final = prop(best.zero, start, sc, μs["Earth"], prop_time)
|
||||||
initial_path = prop(zeros((100,3)), start, sc, μs["Earth"], T)[1]
|
initial_path = prop(zeros((100,3)), start, sc, μs["Earth"], T)[1]
|
||||||
after_transit = prop(zeros((100,3)), calc_final, sc, μs["Earth"], new_T)[1]
|
after_transit = prop(zeros((100,3)), calc_final, sc, μs["Earth"], new_T)[1]
|
||||||
final_path = prop(zeros((100,3)), final, sc, μs["Earth"], new_T)[1]
|
final_path = prop(zeros((100,3)), final, sc, μs["Earth"], new_T)[1]
|
||||||
@@ -53,21 +51,62 @@
|
|||||||
colors=["#FFFFFF", "#FF4444","#44FF44","#4444FF"]),
|
colors=["#FFFFFF", "#FF4444","#44FF44","#4444FF"]),
|
||||||
"../plots/mbh_best.html")
|
"../plots/mbh_best.html")
|
||||||
i = 0
|
i = 0
|
||||||
best_mass = best_masses[end]
|
best_mass = calc_final[end]
|
||||||
nominal_mass = normal_mass[end]
|
nominal_mass = final[end]
|
||||||
masses = []
|
masses = []
|
||||||
for candidate in archive
|
for candidate in archive
|
||||||
@test converged(candidate)
|
@test candidate.converged
|
||||||
path2, cand_ms, calc_final = prop(tanh.(candidate.zero), start, sc, μs["Earth"], prop_time)
|
path2, calc_final = prop(candidate.zero, start, sc, μs["Earth"], prop_time)
|
||||||
push!(masses, cand_ms[end])
|
push!(masses, calc_final[end])
|
||||||
@test norm(calc_final - final) < 1e-4
|
@test norm(calc_final[1:6] - final[1:6]) < 1e-4
|
||||||
end
|
end
|
||||||
@test best_mass == maximum(masses)
|
@test best_mass == maximum(masses)
|
||||||
|
|
||||||
# This won't always work since the test is reduced in fidelity,
|
# This won't always work since the test is reduced in fidelity,
|
||||||
# but hopefully will usually work:
|
# but hopefully will usually work:
|
||||||
@test (sc.mass - best_mass) < 1.1 * (sc.mass - nominal_mass)
|
@test (start_mass - best_mass) < 1.1 * (start_mass - nominal_mass)
|
||||||
@show best_mass
|
|
||||||
@show nominal_mass
|
# Now let's test a sun case. This should be pretty close to begin with
|
||||||
|
launch_date = DateTime(2016,3,28)
|
||||||
|
launch_j2000 = utc2et(Dates.format(launch_date,"yyyy-mm-ddTHH:MM:SS"))
|
||||||
|
earth_start = [spkssb(ids["Earth"], launch_j2000, "J2000"); 1e5]
|
||||||
|
earth_speed = earth_start[4:6]
|
||||||
|
v∞ = 3.0*earth_speed/norm(earth_speed)
|
||||||
|
start = earth_start + [zeros(3); v∞; 0.0]
|
||||||
|
final = [1.62914115303947e8, 1.33709639408102e8, 5.690490452749867e7, -16.298522963602757, 15.193294491415365, 6.154820267250081, 1.0001e8]
|
||||||
|
tof = 3600*24*30*10.75
|
||||||
|
a = xyz_to_oe(final, μs["Sun"])[1]
|
||||||
|
T = 2π*√(a^3/μs["Sun"])
|
||||||
|
n = 20
|
||||||
|
|
||||||
|
# But we'll plot to see
|
||||||
|
beginning_path = prop(zeros(100,3), start, Sc("test"), μs["Sun"], tof)[1]
|
||||||
|
ending_path = prop(zeros(100,3), final, Sc("test"), μs["Sun"], T)[1]
|
||||||
|
savefig(plot_orbits([beginning_path, ending_path],
|
||||||
|
labels=["initial", "ending"],
|
||||||
|
colors=["#F2F", "#2F2"]),
|
||||||
|
"../plots/mbh_sun_initial.html")
|
||||||
|
|
||||||
|
# Now we solve and plot the new case
|
||||||
|
best, archive = mbh(start,
|
||||||
|
final,
|
||||||
|
Sc("test"),
|
||||||
|
μs["Sun"],
|
||||||
|
0.0,
|
||||||
|
tof,
|
||||||
|
n,
|
||||||
|
search_patience_lim=25,
|
||||||
|
drill_patience_lim=50,
|
||||||
|
verbose=true)
|
||||||
|
solved_path, solved_state = prop(best.zero, start, Sc("test"), μs["Sun"], tof)
|
||||||
|
ending_path = prop(zeros(100,3), final, Sc("test"), μs["Sun"], T)[1]
|
||||||
|
savefig(plot_orbits([solved_path, ending_path],
|
||||||
|
labels=["best", "ending"],
|
||||||
|
colors=["#C2F", "#2F2"]),
|
||||||
|
"../plots/mbh_sun_solved.html")
|
||||||
|
|
||||||
|
# We'll just make sure that this at least converged correctly
|
||||||
|
@test norm(solved_state[1:6] - final[1:6]) < 1e-4
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,37 +5,27 @@
|
|||||||
using Thesis: prop_one
|
using Thesis: prop_one
|
||||||
|
|
||||||
# Set up
|
# Set up
|
||||||
start = oe_to_xyz([ (μs["Earth"]*(rand(3600*1.5:0.01:3600*4)/(2π))^2)^(1/3),
|
start_mass = 10_000.
|
||||||
|
start = [oe_to_xyz([ (μs["Earth"]*(rand(3600*1.5:0.01:3600*4)/(2π))^2)^(1/3),
|
||||||
rand(0.01:0.01:0.5),
|
rand(0.01:0.01:0.5),
|
||||||
rand(0.01:0.01:0.45π),
|
rand(0.01:0.01:0.45π),
|
||||||
0.,
|
0.,
|
||||||
0.,
|
0.,
|
||||||
1. ], μs["Earth"])
|
1. ], μs["Earth"]); start_mass]
|
||||||
stepsize = rand(100.0:0.01:500.0)
|
stepsize = rand(100.0:0.01:500.0)
|
||||||
|
|
||||||
# Test that Laguerre-Conway is the default propagator
|
|
||||||
propped = prop_one([0., 0., 0.], start, 0., 0, 0., 1000., 0.1, μs["Earth"], stepsize)
|
|
||||||
@test laguerre_conway(start, μs["Earth"], stepsize) ≈ propped[1]
|
|
||||||
|
|
||||||
# Test that Laguerre-Conway is the default propagator for spacecrafts
|
# Test that Laguerre-Conway is the default propagator for spacecrafts
|
||||||
craft = Sc("no_thrust")
|
craft = Sc("no_thrust")
|
||||||
start_mass = craft.mass
|
state = prop_one([0., 0., 0.], start, craft, μs["Earth"], stepsize)
|
||||||
state, craft = prop_one([0., 0., 0.], start, craft, μs["Earth"], stepsize)
|
@test laguerre_conway(start, μs["Earth"], stepsize) ≈ state[1:6]
|
||||||
@test laguerre_conway(start, μs["Earth"], stepsize) ≈ state
|
@test state[7] == start_mass
|
||||||
@test craft.mass == start_mass
|
|
||||||
|
|
||||||
# Test that mass is reduced properly
|
# Test that mass is reduced properly
|
||||||
craft = Sc("test")
|
craft = Sc("test")
|
||||||
start_mass = craft.mass
|
state = prop_one([1., 0., 0.], start, craft, μs["Earth"], stepsize)
|
||||||
state, craft = prop_one([1., 0., 0.], start, craft, μs["Earth"], stepsize)
|
@test state[7] == start_mass - craft.mass_flow_rate*stepsize
|
||||||
@test craft.mass == start_mass - craft.mass_flow_rate*stepsize
|
|
||||||
|
|
||||||
# Test that a bad ΔV throws an error
|
# Test that a bad ΔV throws an error
|
||||||
# craft = Sc("test")
|
@test_throws ErrorException prop_one([1.5, 0., 0.], start, craft, μs["Earth"], stepsize)
|
||||||
# start_mass = craft.mass
|
|
||||||
# @test_throws ErrorException prop_one([1.5, 0., 0.], start, craft, μs["Earth"], stepsize)
|
|
||||||
|
|
||||||
# Test that a full propagation doesn't take too long
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,15 +7,16 @@
|
|||||||
# First some setup
|
# First some setup
|
||||||
sc = Sc("test")
|
sc = Sc("test")
|
||||||
T = rand(3600*2:0.01:3600*4)
|
T = rand(3600*2:0.01:3600*4)
|
||||||
start = oe_to_xyz([ (μs["Earth"]*(T/(2π))^2)^(1/3),
|
start = [oe_to_xyz([ (μs["Earth"]*(T/(2π))^2)^(1/3),
|
||||||
0.1,
|
0.1,
|
||||||
π/4,
|
π/4,
|
||||||
0.,
|
0.,
|
||||||
0.,
|
0.,
|
||||||
1. ], μs["Earth"])
|
1. ], μs["Earth"]); 10_000.]
|
||||||
n = 100
|
revs = 30
|
||||||
ΔVs = repeat([0.5, 0., 0.]', outer=(n,1))
|
n = revs*100
|
||||||
path = prop(ΔVs, start, sc, μs["Earth"], 3T)[1]
|
ΔVs = repeat([0.9, 0., 0.]', outer=(n,1))
|
||||||
|
path = prop(ΔVs, start, copy(sc), μs["Earth"], revs*T)[1]
|
||||||
p = plot_orbits([path])
|
p = plot_orbits([path])
|
||||||
savefig(p,"../plots/plot_test.html")
|
savefig(p,"../plots/plot_test.html")
|
||||||
@test typeof(p) == PlotlyJS.SyncPlot
|
@test typeof(p) == PlotlyJS.SyncPlot
|
||||||
|
|||||||
@@ -4,17 +4,25 @@
|
|||||||
|
|
||||||
# Test that the standard spacecraft can be created
|
# Test that the standard spacecraft can be created
|
||||||
craft = Sc("test")
|
craft = Sc("test")
|
||||||
@test craft.mass == 10000.
|
@test craft.dry_mass == 9000.
|
||||||
@test craft.mass_flow_rate == 0.01
|
@test craft.mass_flow_rate == craft.max_thrust/(0.00981*2000)
|
||||||
@test craft.max_thrust == 0.05
|
@test craft.max_thrust == 0.00025
|
||||||
@test craft.num_thrusters == 2
|
@test craft.num_thrusters == 50
|
||||||
@test craft.duty_cycle == 1.
|
@test craft.duty_cycle == 0.9
|
||||||
|
|
||||||
craft = Sc("no_thrust")
|
craft = Sc("no_thrust")
|
||||||
@test craft.mass == 10000.
|
@test craft.dry_mass == 9000.
|
||||||
@test craft.mass_flow_rate == 0.01
|
@test craft.mass_flow_rate == 0.01
|
||||||
@test craft.max_thrust == 0.
|
@test craft.max_thrust == 0.
|
||||||
@test craft.num_thrusters == 0
|
@test craft.num_thrusters == 0
|
||||||
@test craft.duty_cycle == 0.
|
@test craft.duty_cycle == 0.
|
||||||
|
|
||||||
|
# Test that the standard spacecraft can be copied
|
||||||
|
new_craft = copy(craft)
|
||||||
|
@test new_craft.dry_mass == craft.dry_mass
|
||||||
|
@test new_craft.mass_flow_rate == craft.mass_flow_rate
|
||||||
|
@test new_craft.max_thrust == craft.max_thrust
|
||||||
|
@test new_craft.num_thrusters == craft.num_thrusters
|
||||||
|
@test new_craft.duty_cycle == craft.duty_cycle
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user