You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Orbits/julia_code/attempt2/SimulationSteps.jl

291 lines
7.0 KiB
Julia

using LinearAlgebra
using Distributions
using StatsFuns
using Plots
abstract type DestructionProbability end
struct LinearProbability <: DestructionProbability
spontaneous
intra_constellation
inter_constellation
debris
end
function (lp::LinearProbability)(Sᵢ, S, D,)
min(1,max(0,
lp.spontaneous + lp.intra_constellation * Sᵢ + lp.inter_constellation * (S-Sᵢ) + lp.debris * D)
)
end
function individual_loss(Sᵢ, S, D,n=1,return_prob=false)
#=
This function simulates how many satellites will be lost
from a given constellation.
TODO: Requires calibration of some sort
=#
β₀ = 3e-4 #probability of spontaneous destruction
β₁ = 1e-6 #proability of collision with satellite in same constellation
β₂ = 1e-5 #probability of collision with satellite in different constellation
β₃ = 1e-4 #probability of collision with debris
#linear probability (with constraints)
p = min(1,max(0,β₀ + β₁ * Sᵢ + β₂ * (S-Sᵢ) + β₃ * D))
#p = logistic(β₀ + β₁ * Sᵢ + β₂ * (S-Sᵢ) + β₃ * D)
dist = Binomial(Sᵢ, p)
draw = rand(dist)
if return_prob
return draw, p
else
return draw
end
end
function debris_transition(D,S⃗, Y⃗, X⃗, δ=0.005, Γ=0.5)
#δ: 1/δ year decay rate
#Γ: proportion of the mass of the satellite that is released into orbit during launch
#new debris released equals the debris lost to deorbit + debris generated by collisions + debris due to launches
new_debris = (1-δ) * D .+ sum(Y⃗) .+ Γ*sum(X⃗)
return new_debris
end
function stocks_transition(S⃗, Y⃗, X⃗)
return S⃗ .+ X⃗ .- Y⃗
end
function overall_losses(S⃗, D)
#=
Simulate the losses for each constellation
=#
individual_outcomes = [ individual_loss(s, sum(S⃗),D,1,true) for s in S⃗ ]
losses = []
prob_distruction = []
for (loss,prob) in individual_outcomes
append!(losses,loss)
append!(prob_distruction,prob)
end
return losses,prob_distruction
end
# The demand function for the market
function inverse_demand_cournot(S⃗,A=100)
A - sum(S⃗)
end
function profit_function(s,x,C_operation,C_launch,T_launch, T_operation,Price)
#=
The profit function each participant recieves
Includes place for taxes and costs.
=#
(Price-T_operation-C_operation)*s - (C_launch + T_launch)*x
end
#Get histogram of loss numbers per 10_000
histogram(
[sum(individual_loss(33,67,500,10_000)) for i in 1:10000]
,bins=range(0,200,length=201)
,label="Satellites lost per 10,000"
)
#=
Basic simulations
1. What happens when both participants always launch a single satellite?
2. What happens when a single participant always launches a single satellite?
3. What happens when both participants maintain the cournot equilibrium?
=#
#Specify policies
abstract type Policy end
#=
Represent any policy as a struct holding parameters that can be called with
state variables to get the chosen policy.
=#
struct ConstantLaunchRatePolicy <: Policy
#=
Operator launches fixed number of satellites per turn
=#
rate_numerator
end
(p::ConstantLaunchRatePolicy)(s,S,D) = p.rate_numerator
struct SustainmentPolicy <: Policy
#=
Operator launches enough satellites to maintain a certain size
=#
level
end
(p::SustainmentPolicy)(s,S,D) = max(0,p.level - s)
struct simulation_result
state_path
profit_path
destruction_events
launch_choices
destruction_probabilities
end
function simulate_system(policies,starting_state,n)
#=
Given a set of policies and a starting state, calculate n steps ahead.
=#
state = fill(starting_state,n)
profit_path = []
decay_events=[]
launch_choices = []
destruction_probabilities = []
for i in 2:n
current_state = state[i-1]
S⃗ = current_state[2:end]
D = current_state[1]
#Calculate actions from policies
X = [policy(s,sum(S⃗),D) for (s,policy) in zip(S⃗,policies)]
push!(launch_choices, X)
#Information generation
price = inverse_demand_cournot(S⃗,10000)
push!(profit_path,[profit_function(s,x,4,100,0, 0,price) for (s,x) in zip(S⃗,X) ])
#calculate transition to next state
#loss of satellites
(Y⃗,prob_distruction) = overall_losses(S⃗, D)
push!(decay_events,Y⃗)
push!(destruction_probabilities, prob_distruction)
#debris
new_debris = debris_transition(D, S⃗, Y⃗, X,0.05, )
#stocks
new_stocks = stocks_transition(S⃗,Y⃗,X)
#update vector of states
next_state = [new_debris,new_stocks...]
#update vector
state[i] = next_state
println(current_state,next_state)
end
k = length(starting_state)
return simulation_result(
[ [v[i] for v in state] for i in 1:k], #states
[ [v[i] for v in profit_path] for i in 1:3 ], #profit paths
[ [v[i] for v in decay_events ] for i in 1:3], #counts of satellite distructions
[ [v[i] for v in launch_choices ] for i in 1:3], #counts of satellite launches
[ [v[i] for v in destruction_probabilities] for i in 1:3]
)
end
#setup state
n=2000
starting_state = [10.0,0,0,0]
policies = [SustainmentPolicy(x) for x in 25:5:35]
simulation = simulate_system(policies,starting_state,n)
plot(
simulation.state_path[2:4]
,labels=["stocks 1" "stocks 2" "Stocks 3"]
)
plot(
simulation.state_path[1]
,labels="debris"
)
plot(
simulation.state_path[1][3:end] .- simulation.state_path[1][2:end-1]
,labels="debris growth"
)
plot( simulation.state_path
,labels=["debris" "stocks 1" "stocks 2" "Stocks 3"]
)
plot(simulation.profit_path)
bar(
simulation.destruction_events
,layout = grid(3,1)
,legend=:none
)
plot(
simulation.launch_choices
,layout = grid(3,1)
,legend=:none
)
plot(simulation.destruction_probabilities)
#= Notes
With the (maintain equilibrium) approach, the probability
of distruction rises to 100% within a certain amount of time.
=#
bar(
[simulation.launch_choices, -1 .* simulation.destruction_events]
,layout = grid(3,1)
,ylims = (-25,25)
#,label = ["Launches 1" "Launches 2" "Launches 3" "Destruction 1" "Destruction 2" "Destruction 3"]
, legend = :none
, title = ["Operator 1" "Operator 2" "Operator 3"]
#,yaxis = (-20:5:20)
)
#Many simulations
sims = [simulate_system(policies,starting_state,n) for x in 1:1000]
state_plots = []
for sim in sims
push!(state_plots,plot(sim.state_path[2:end]))
end
state_plots[2]
for p in state_plots
display(p)
end
plot(sim1.state_path[2:end], color=:skyblue, alpha=0.5)
arr = [sim.state_path[2:end] for sim in sims]
plot(arr, color=:blue, alpha=0.01, legend=:none)
debarr = [ sim.state_path[1] for sim in sims]
plot(debarr, color=:blue, alpha=0.05, legend=:none)
profitarr = [sim.profit_path for sim in sims]
plot(profitarr, color=:blue, alpha=0.01, legend=:none)
# Plot out probability of distruction