Files
thesis/julia/src/mission.jl
2021-10-10 20:53:14 -06:00

184 lines
5.7 KiB
Julia

export Phase, Mission_Guess, Mission, Bad_Mission
export test_phase1, test_phase2
export test_mg
export Vector
struct Phase
planet::Body
v∞_in::Vector{Float64}
v∞_out::Vector{Float64}
tof::Float64
thrust_profile::Matrix{Float64}
end
const test_phase1 = Phase(Venus, [20., -80., 0.], [50., -50., 0.], 1.30464e7, zeros(20,3))
const test_phase2 = Phase(Jupiter, [0.3, 7.1, 0.2], [0.3, 7.1, 0.2], 3.9year, zeros(20,3))
const test_phases = [test_phase1, test_phase2]
"""
A convenience function for calculating mass usage given a certain thrust profile
"""
function mass_consumption(sc::Sc, phase::Phase)
weighted_thrusting_time = 0.0
n = size(phase.thrust_profile)[1]
for i in 1:size(phase.thrust_profile,1)
weighted_thrusting_time += norm(phase.thrust_profile[i,:]) * phase.tof/n
end
return weighted_thrusting_time*sc.mass_flow_rate
end
struct Mission_Guess
sc::Sc
start_mass::Float64
launch_date::DateTime
launch_v∞::Vector{Float64}
phases::Vector{Phase}
converged::Bool
end
"""
Constructor for a mission guess. Generally mission guesses are not converged
"""
function Mission_Guess(sc::Sc, mass::Float64, date::DateTime, v∞::Vector{Float64}, phases::Vector{Phase})
# First do some checks to make sure that it's valid
mass_used = 0
for phase in phases
mass_used += mass_consumption(sc, phase)
mass - mass_used > sc.dry_mass || throw(Mass_Error(mass - mass_used))
v∞_in, v∞_out = phase.v∞_in, phase.v∞_out
end
Mission_Guess(sc, mass, date, v∞, phases, false)
end
"""
This is the opposite of the function below. It takes a vector and any other necessary information and outputs a mission guess
"""
function Mission_Guess(x::Vector{Float64}, sc::Sc, mass::Float64, flybys::Vector{Body})
# Variable mission params
launch_date = Dates.unix2datetime(x[1])
launch_v∞ = x[2:4]
# Try to intelligently determine n
three_n = ((length(x)-4)/length(flybys)) - 7
three_n % 3 == 0 || throw(Mission_Creation_Error(three_n))
n::Int = three_n/3
# Build the phases
i = 0
phases = Vector{Phase}()
for flyby in flybys
phase_params = x[ 5 + (3n+7) * i : 5 + (3n+7) * (i+1) - 1 ]
v∞_in = phase_params[1:3]
v∞_out = phase_params[4:6]
tof = phase_params[7]
thrusts = reshape(phase_params[8:end], (n,3))
push!(phases, Phase(flyby, v∞_in, v∞_out, tof, thrusts))
i += 1
end
return Mission_Guess(sc, mass, launch_date, launch_v∞, phases, false)
end
"""
This is a function to convert a mission guess into an nlp-ready vector. It doesn't contain all
information from the guess though.
"""
function Base.Vector(g::Mission_Guess)
result = Vector{Float64}()
push!(result, Dates.datetime2unix(g.launch_date))
push!(result, g.launch_v∞...)
for phase in g.phases
push!(result,phase.v∞_in...)
push!(result,phase.v∞_out...)
push!(result,phase.tof)
push!(result,phase.thrust_profile...)
end
return result
end
function lowest_mission_vector(launch_window::Vector{DateTime}, num_phases::Int, n::Int)
result = Vector{Float64}()
push!(result, Dates.datetime2unix(launch_window[1]))
push!(result, -10*ones(3)...)
for i in 1:num_phases
push!(result, -10*ones(3)...)
push!(result, -10*ones(3)...)
push!(result, 86_400.0)
push!(result, -1 * ones(n,3)...)
end
return result
end
function highest_mission_vector(launch_window::Vector{DateTime}, mission_length::Float64, num_phases::Int, n::Int)
result = Vector{Float64}()
push!(result, Dates.datetime2unix(launch_window[2]))
push!(result, 10*ones(3)...)
for i in 1:num_phases
push!(result, 10*ones(3)...)
push!(result, 10*ones(3)...)
push!(result, mission_length)
push!(result, ones(n,3)...)
end
return result
end
const test_mg = Mission_Guess(bepi, 12_000., DateTime(1992,11,19), [-3.4,1.2,0.1], test_phases)
struct Mission
sc::Sc
start_mass::Float64
launch_date::DateTime
launch_v∞::Vector{Float64}
phases::Vector{Phase}
converged::Bool
end
"""
Constructor for a mission. Generally mission guesses are converged, so we check everything
"""
function Mission(sc::Sc, mass::Float64, date::DateTime, v∞::Vector{Float64}, phases::Vector{Phase};
force=false)
# First do some checks to make sure that it's valid
if !force
time = date
current_planet = Earth
start = state(current_planet, time, v∞, mass)
for phase in phases
final = prop(phase.thrust_profile, start, sc, phase.tof)[2]
mass = final[7]
mass > sc.dry_mass || throw(Mass_Error(mass - mass_used))
current_planet = phase.planet
time += Dates.Second(floor(phase.tof))
p_pos = state(current_planet, time)[1:3]
abs(norm(final[1:3] - p_pos)) < 30_000. || throw(Planet_Match_Error(final[1:3], p_pos))
v∞_in, v∞_out = phase.v∞_in, phase.v∞_out
if phase != phases[end]
abs(norm(v∞_in) - norm(v∞_out)) < 0.005 || throw(V∞_Error(v∞_in, v∞_out))
δ = acos( ( v∞_in v∞_out ) / ( norm(v∞_in) * norm(v∞_out) ) )
periapsis = (phase.planet.μ/(v∞_in v∞_in)) * ( 1/sin(δ/2) - 1 )
periapsis > 1.1phase.planet.r || throw(HitPlanet_Error())
end
end
end
Mission(sc, mass, date, v∞, phases, true)
end
"""
BE CAREFUL!! This just makes a guess converged, whether true or not
"""
function Mission(g::Mission_Guess)
return Mission(g.sc, g.start_mass, g.launch_date, g.launch_v∞, g.phases, force=true)
end
function Mission(x::Vector{Float64}, sc::Sc, mass::Float64, flybys::Vector{Body})
guess = Mission_Guess(x, sc, mass, flybys::Vector{Body})
return Mission(guess)
end
struct Bad_Mission
message::String
converged::Bool
end
Bad_Mission(s::String) = Bad_Mission(s,false)
Bad_Mission(s::Symbol) = Bad_Mission(String(s),false)