[1]:
import fmdtools.sim.propagate as propagate
import fmdtools.analyze as an
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pandas as pd
import numpy as np
Urban Drone Demo
Model Overview
The drone model is defined in drone_mdl_urban.py
, along with some visualization functions.
[2]:
from drone_mdl_urban import Drone
[3]:
mdl = Drone()
This is the model structure:
[4]:
mg = an.graph.FunctionArchitectureGraph(mdl)
fig, ax = mg.draw()
We can also view the grid environment using its show
methods:
[5]:
collections={"all_occupied": {"color": "red"}, "all_allowed": {"color": "blue"}, "start": {"color": "blue"}, "end": {"color": "blue"}}
fig, ax = mdl.flows['environment'].c.show("height", collections=collections)
Which shows the Start, End, and allowed/unsafe locations in the 1000x1000-m grid. In this display, line thickness corresponds to building height, and hatching corresponds to whether or not the space is occupied. We can also display this using show.coord3d
:
[6]:
fig, ax = mdl.flows['environment'].c.show_z("height", collections=collections)
Nominal Simulation
Below we show how this drone performs in the nominal scenario.
[7]:
results_nom, hist_nom =propagate.nominal(mdl)
fig, axs = hist_nom.plot_line("fxns.store_ee.s.soc",
'flows.ee_1.s.rate',
'flows.dofs.s.z',
'fxns.plan_path.m.mode',
'fxns.plan_path.s.pt',
'flows.des_traj.s.power')
As shown, the flight ends fairly quickly (in 10 minutes), with the drone successively proceeding through points in the flight plan.
We can also view this flightpath in 3-d space using History.plot_trajectories
:
[8]:
fig, ax = hist_nom.plot_trajectories('dofs.s.x', 'dofs.s.y', 'dofs.s.z')
Trajectory plots can be overlaid on top of environment plots. In this case, we defined the method plot_env_with_traj
and plot_env_with_traj_z
for this case.
[9]:
from drone_mdl_urban import plot_env_with_traj, plot_env_with_traj_z
[10]:
plot_env_with_traj_z(hist_nom, mdl)
[10]:
(<Figure size 400x400 with 1 Axes>, <Axes3D: title={'center': 'trajectory'}>)
[11]:
plot_env_with_traj(hist_nom, mdl)
[11]:
(<Figure size 640x480 with 2 Axes>,
<Axes: title={'center': 'trajectory'}, xlabel='x', ylabel='y'>)
As shown, this is a rather simple straight-line path. If we wanted a more complex scenario, we could make the path more complex by adding multiple destinations or planning the path based on allowed flight/landing locations.
As it is, we may also want to adjust the timestep/speed to get more resolution, since the drone only has a few discrete timesteps in the air.
The results for the simulation are:
[12]:
results_nom
[12]:
endclass:
--rate: 1.0
--cost: 0.0
--expected_cost: 0.0
--repcost: 0
--unsafe_flight_time: 0
--body_strikes: 0.0
--head_strikes: 0.0
--property_restrictions: 0
--safecost: 0.0
--landcost: 0
--p_safety: 0.0
--severities: {'hazardous': 0.0, 'minor': 1.0}
Resilience model
A number of different faults have been implemented in the system.
For example, here we inject a mechanical fault in the left-rear rotor during flight:
[13]:
mdl.fxns['affect_dof'].m.faultmodes
[13]:
{'lf_short': Fault(prob=1.0000000000000002e-06, cost=200, phases={}, units='sim'),
'lf_openc': Fault(prob=1.0000000000000002e-06, cost=200, phases={}, units='sim'),
'lf_ctlup': Fault(prob=2.0000000000000003e-06, cost=500, phases={}, units='sim'),
'lf_ctldn': Fault(prob=2.0000000000000003e-06, cost=500, phases={}, units='sim'),
'lf_ctlbreak': Fault(prob=2.0000000000000003e-06, cost=1000, phases={}, units='sim'),
'lf_mechbreak': Fault(prob=1.0000000000000002e-06, cost=500, phases={}, units='sim'),
'lf_mechfriction': Fault(prob=5.000000000000001e-07, cost=500, phases={}, units='sim'),
'lf_propwarp': Fault(prob=1.0000000000000001e-07, cost=200, phases={}, units='sim'),
'lf_propstuck': Fault(prob=2.0000000000000002e-07, cost=200, phases={}, units='sim'),
'lf_propbreak': Fault(prob=3.0000000000000004e-07, cost=200, phases={}, units='sim'),
'lr_short': Fault(prob=1.0000000000000002e-06, cost=200, phases={}, units='sim'),
'lr_openc': Fault(prob=1.0000000000000002e-06, cost=200, phases={}, units='sim'),
'lr_ctlup': Fault(prob=2.0000000000000003e-06, cost=500, phases={}, units='sim'),
'lr_ctldn': Fault(prob=2.0000000000000003e-06, cost=500, phases={}, units='sim'),
'lr_ctlbreak': Fault(prob=2.0000000000000003e-06, cost=1000, phases={}, units='sim'),
'lr_mechbreak': Fault(prob=1.0000000000000002e-06, cost=500, phases={}, units='sim'),
'lr_mechfriction': Fault(prob=5.000000000000001e-07, cost=500, phases={}, units='sim'),
'lr_propwarp': Fault(prob=1.0000000000000001e-07, cost=200, phases={}, units='sim'),
'lr_propstuck': Fault(prob=2.0000000000000002e-07, cost=200, phases={}, units='sim'),
'lr_propbreak': Fault(prob=3.0000000000000004e-07, cost=200, phases={}, units='sim'),
'rf_short': Fault(prob=1.0000000000000002e-06, cost=200, phases={}, units='sim'),
'rf_openc': Fault(prob=1.0000000000000002e-06, cost=200, phases={}, units='sim'),
'rf_ctlup': Fault(prob=2.0000000000000003e-06, cost=500, phases={}, units='sim'),
'rf_ctldn': Fault(prob=2.0000000000000003e-06, cost=500, phases={}, units='sim'),
'rf_ctlbreak': Fault(prob=2.0000000000000003e-06, cost=1000, phases={}, units='sim'),
'rf_mechbreak': Fault(prob=1.0000000000000002e-06, cost=500, phases={}, units='sim'),
'rf_mechfriction': Fault(prob=5.000000000000001e-07, cost=500, phases={}, units='sim'),
'rf_propwarp': Fault(prob=1.0000000000000001e-07, cost=200, phases={}, units='sim'),
'rf_propstuck': Fault(prob=2.0000000000000002e-07, cost=200, phases={}, units='sim'),
'rf_propbreak': Fault(prob=3.0000000000000004e-07, cost=200, phases={}, units='sim'),
'rr_short': Fault(prob=1.0000000000000002e-06, cost=200, phases={}, units='sim'),
'rr_openc': Fault(prob=1.0000000000000002e-06, cost=200, phases={}, units='sim'),
'rr_ctlup': Fault(prob=2.0000000000000003e-06, cost=500, phases={}, units='sim'),
'rr_ctldn': Fault(prob=2.0000000000000003e-06, cost=500, phases={}, units='sim'),
'rr_ctlbreak': Fault(prob=2.0000000000000003e-06, cost=1000, phases={}, units='sim'),
'rr_mechbreak': Fault(prob=1.0000000000000002e-06, cost=500, phases={}, units='sim'),
'rr_mechfriction': Fault(prob=5.000000000000001e-07, cost=500, phases={}, units='sim'),
'rr_propwarp': Fault(prob=1.0000000000000001e-07, cost=200, phases={}, units='sim'),
'rr_propstuck': Fault(prob=2.0000000000000002e-07, cost=200, phases={}, units='sim'),
'rr_propbreak': Fault(prob=3.0000000000000004e-07, cost=200, phases={}, units='sim')}
[14]:
results_fault, hist_fault =propagate.one_fault(mdl, "affect_dof", "lr_mechbreak", time=2.0)
[15]:
fig, axs = hist_fault.plot_line("fxns.store_ee.s.soc",
'flows.ee_1.s.rate',
'flows.dofs.s.z',
'fxns.plan_path.m.mode',
'fxns.plan_path.s.pt',
'flows.des_traj.s.power')
[16]:
plot_env_with_traj_z(hist_fault, mdl)
[16]:
(<Figure size 400x400 with 1 Axes>, <Axes3D: title={'center': 'trajectory'}>)
[17]:
plot_env_with_traj(hist_fault, mdl)
[17]:
(<Figure size 640x480 with 2 Axes>,
<Axes: title={'center': 'trajectory'}, xlabel='x', ylabel='y'>)
[18]:
results_fault
[18]:
endclass.rate: 1.0000000000000002e-06
endclass.cost: 28600.0
endclass.expected_cost: 2860.0000000000005
endclass.repcost: 500
endclass.unsafe_flight_time: 281
endclass.body_strikes: 0.0
endclass.head_strikes: 0.0
endclass.property_restrictions: 0
endclass.safecost: 28100.0
endclass.landcost: 0
endclass.p_safety: 0.0
endclass.severities: {'hazardous': 0.0, 'minor': 1.0000000000000002e-06}
Here we inject a large list of faults in the system and evaluate their relative consequences in terms of metrics calculated in find_classification:
[19]:
from fmdtools.analyze.phases import PhaseMap, from_hist
phasemaps = from_hist(hist_nom, fxn_modephases=[])
phasemaps
[19]:
{'ctl_dof': PhaseMap({'nominal': [0.0, 30.0]}, {}),
'plan_path': PhaseMap({'taxi': [0.0, 1.0], 'move': [1.1, 1.6], 'land': [1.7, 2.4], 'taxi1': [2.5, 30.0]}, {})}
[20]:
from drone_mdl_urban import make_move_quad
move_quad=make_move_quad(hist_nom, phasemaps['plan_path'].phases['move'])
move_quad
[20]:
{'samp': 'quadrature',
'quad': {'nodes': [-0.20000000000000018, 1.0], 'weights': [1.0, 0.92]}}
[21]:
from fmdtools.sim.sample import FaultDomain, FaultSample
fd = FaultDomain(mdl)
fd.add_all()
fs = FaultSample(fd, phasemap = phasemaps['plan_path'])
fs.add_fault_phases("move", method = "quad",
args=(move_quad['quad']['nodes'], move_quad['quad']['weights']))
fs
[21]:
FaultSample of scenarios:
- manage_health_lostfunction_t2
- manage_health_lostfunction_t2
- store_ee_nocharge_t2
- store_ee_nocharge_t2
- store_ee_lowcharge_t2
- store_ee_lowcharge_t2
- store_ee_s1p1_short_t2
- store_ee_s1p1_short_t2
- store_ee_s1p1_degr_t2
- store_ee_s1p1_degr_t2
- ... (118 total)
[22]:
endresults, hists = propagate.fault_sample(mdl, fs, staged=False)
SCENARIOS COMPLETE: 100%|██████████| 118/118 [01:29<00:00, 1.32it/s]
[23]:
plot_env_with_traj_z(hists , mdl)
[23]:
(<Figure size 400x400 with 1 Axes>, <Axes3D: title={'center': 'trajectory'}>)
[24]:
statsfmea = an.tabulate.FMEA(endresults, fs,
weight_metrics=['rate'],
avg_metrics=['unsafe_flight_time', 'cost', 'repcost',
'landcost', 'body_strikes',
'head_strikes', 'property_restrictions'])
fmeatab = statsfmea.as_table(sort_by="cost")
fmeatab
[24]:
rate | unsafe_flight_time | cost | repcost | landcost | body_strikes | head_strikes | property_restrictions | ||
---|---|---|---|---|---|---|---|---|---|
plan_path | vision_lack_of_detection | 5.989583e-03 | 281.0 | 3.377386e+06 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
dist_ee | degr | 2.395833e-06 | 281.0 | 1.303438e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 |
short | 1.437500e-06 | 281.0 | 1.269100e+04 | 1500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
break | 9.583333e-07 | 281.0 | 1.240733e+04 | 1500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
affect_dof | lf_ctlbreak | 9.583333e-07 | 281.0 | 1.219775e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 |
lr_ctlbreak | 9.583333e-07 | 281.0 | 1.219775e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_ctlbreak | 9.583333e-07 | 281.0 | 1.219775e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_ctlbreak | 9.583333e-07 | 281.0 | 1.219775e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lr_ctlup | 9.583333e-07 | 281.0 | 1.198817e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lr_ctldn | 9.583333e-07 | 281.0 | 1.198817e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_ctldn | 9.583333e-07 | 281.0 | 1.198817e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_ctlup | 9.583333e-07 | 281.0 | 1.198817e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_ctlup | 9.583333e-07 | 281.0 | 1.198817e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lf_ctldn | 9.583333e-07 | 281.0 | 1.198817e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_ctldn | 9.583333e-07 | 281.0 | 1.198817e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lf_ctlup | 9.583333e-07 | 281.0 | 1.198817e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
hold_payload | deform | 2.875000e-09 | 281.0 | 1.184170e+04 | 1500.0 | 0.0 | 0.0 | 0.0 | 0.0 |
break | 7.187500e-10 | 281.0 | 1.184043e+04 | 1500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
affect_dof | lr_mechbreak | 4.791667e-07 | 281.0 | 1.171408e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 |
lf_mechbreak | 4.791667e-07 | 281.0 | 1.171408e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_mechbreak | 4.791667e-07 | 281.0 | 1.171408e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_mechbreak | 4.791667e-07 | 281.0 | 1.171408e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
plan_path | degloc | 2.875000e-08 | 281.0 | 1.165673e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 |
ctl_dof | degctl | 2.875000e-08 | 281.0 | 1.165673e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 |
noctl | 7.187500e-09 | 281.0 | 1.164418e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
plan_path | noloc | 7.187500e-09 | 281.0 | 1.164418e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 |
manage_health | lostfunction | 1.796875e-10 | 281.0 | 1.164010e+04 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 |
affect_dof | lr_short | 4.791667e-07 | 281.0 | 1.159121e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 |
lf_openc | 4.791667e-07 | 281.0 | 1.159121e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_openc | 4.791667e-07 | 281.0 | 1.159121e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_short | 4.791667e-07 | 281.0 | 1.159121e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_openc | 4.791667e-07 | 281.0 | 1.159121e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lf_short | 4.791667e-07 | 281.0 | 1.159121e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lr_openc | 4.791667e-07 | 281.0 | 1.159121e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_short | 4.791667e-07 | 281.0 | 1.159121e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_mechfriction | 2.395833e-07 | 281.0 | 1.157704e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lf_mechfriction | 2.395833e-07 | 281.0 | 1.157704e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_mechfriction | 2.395833e-07 | 281.0 | 1.157704e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lr_mechfriction | 2.395833e-07 | 281.0 | 1.157704e+04 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lr_propbreak | 1.437500e-07 | 281.0 | 1.140136e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lf_propbreak | 1.437500e-07 | 281.0 | 1.140136e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_propbreak | 1.437500e-07 | 281.0 | 1.140136e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_propbreak | 1.437500e-07 | 281.0 | 1.140136e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
store_ee | lowcharge | 1.677083e-07 | 281.0 | 1.137459e+04 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 |
affect_dof | lf_propstuck | 9.583333e-08 | 281.0 | 1.137424e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 |
lr_propstuck | 9.583333e-08 | 281.0 | 1.137424e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rf_propstuck | 9.583333e-08 | 281.0 | 1.137424e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
rr_propstuck | 9.583333e-08 | 281.0 | 1.137424e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
store_ee | s1p1_nocharge | 1.437500e-07 | 281.0 | 1.136108e+04 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 |
affect_dof | rr_propwarp | 4.791667e-08 | 281.0 | 1.134712e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 |
rf_propwarp | 4.791667e-08 | 281.0 | 1.134712e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lr_propwarp | 4.791667e-08 | 281.0 | 1.134712e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
lf_propwarp | 4.791667e-08 | 281.0 | 1.134712e+04 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
store_ee | s1p1_lowcharge | 9.583333e-08 | 281.0 | 1.133405e+04 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 |
s1p1_short | 7.187500e-08 | 281.0 | 1.132054e+04 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
s1p1_break | 7.187500e-08 | 281.0 | 1.132054e+04 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
s1p1_degr | 7.187500e-08 | 281.0 | 1.132054e+04 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
nocharge | 4.791667e-08 | 281.0 | 1.130702e+04 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | |
plan_path | vision_undesired_detection | 5.989583e-03 | 0.0 | 0.000000e+00 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
[ ]: