-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #27 - [x] Update the demos files to better elaborate on what's going on - [x] Add new demos files - [x] Link to demos from the source documentation - [x] Link to feature tests as additional sources of examples beyond the demos To preview updates, you can check out the branch `documentation-intro-material` and then open up the latest HTML in the directory `docs/generated/html/`. For example, `firefox docs/generated/html/getting-started.html`
- Loading branch information
1 parent
5ce60af
commit f7b5267
Showing
35 changed files
with
483 additions
and
240 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
""" | ||
# EKF | ||
This file demonstrates defining a symbolic model with some simple approximate | ||
physics. Then, compile it into a Python EKF implementation | ||
The same symbolic model could also be compiled into a C++ implementation. | ||
See featuretests/python_library_for_model_evaluation/simple_to_ekf_test.py and | ||
the featuretests/ directory for additional features and examples. | ||
""" | ||
|
||
from formak.ui import Model, symbols, Symbol | ||
from formak import python | ||
|
||
from collections import defaultdict | ||
|
||
dt = symbols("dt") # change in time | ||
|
||
|
||
def main(): | ||
""" | ||
The main function encapsulates a few common steps for all models: | ||
1. Defining symbols | ||
2. Identifying the symbol(s) used in the model state | ||
3. Identifying the symbol(s) used in the control inputs | ||
4. Defining the discrete state update | ||
5. Constructing the Model class | ||
The file also demonstrates: | ||
6. Compiling from the symbolic class to a Python model implementation | ||
7. Running a model update with the Python model | ||
""" | ||
|
||
# 1. Defining symbols | ||
vp = vehicle_properties = {k: Symbol(k) for k in ["m", "x", "v", "a"]} | ||
fuel_burn_rate = Symbol("fuel_burn_rate") | ||
|
||
# 2. Identifying the symbol(s) used in the model state | ||
state = set(vehicle_properties.values()) | ||
|
||
# 3. Identifying the symbol(s) used in the control inputs | ||
control = {fuel_burn_rate} # kg/sec | ||
|
||
# 4. Defining the discrete state update | ||
|
||
# momentum = mv | ||
# dmomentum / dt = F = d(mv)/dt | ||
# F = m dv/dt + dm/dt v | ||
# a = dv / dt = (F - dm/dt * v) / m | ||
|
||
F = 9.81 | ||
|
||
state_model = { | ||
vp["m"]: vp["m"] - fuel_burn_rate * dt, | ||
vp["x"]: vp["x"] + (vp["v"] * dt) + (1 / 2 * vp["a"] * dt * dt), | ||
vp["v"]: vp["v"] + (vp["a"] * dt), | ||
vp["a"]: (F - (fuel_burn_rate * vp["v"])) / vp["m"], | ||
} | ||
|
||
# 5. Constructing the Model class | ||
symbolic_model = Model(dt, state, control, state_model, debug_print=True) | ||
|
||
initial_state = { | ||
vp["m"]: 10.0, | ||
vp["x"]: 0.0, | ||
vp["v"]: 0.0, | ||
vp["a"]: 0.0, | ||
} | ||
|
||
# 6. Compiling from the symbolic class to a Python EKF implementation | ||
python_ekf = python.compile_ekf( | ||
symbolic_model=symbolic_model, | ||
process_noise={fuel_burn_rate: 1.0}, | ||
sensor_models={"simple": {vp["v"]: vp["v"]}}, | ||
sensor_noises={"simple": {vp["v"]: 1.0}}, | ||
) | ||
|
||
# 7. Running a process model update with the Python EKF | ||
state_vector = python_ekf.State.from_dict(initial_state) | ||
control_vector = python_ekf.Control.from_dict({fuel_burn_rate: 0.01}) | ||
state_variance = python_ekf.Covariance() | ||
|
||
print("Initial State") | ||
print(state_vector) | ||
|
||
state_vector_next, state_variance_next = python_ekf.process_model( | ||
0.1, state_vector, state_variance, control_vector | ||
) | ||
|
||
print("Next State") | ||
print(state_vector_next) | ||
|
||
return 0 | ||
|
||
|
||
if __name__ == "__main__": | ||
import sys | ||
|
||
sys.exit(main()) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
""" | ||
# Symbolic Model | ||
This file demonstrates defining a symbolic model with some simple approximate | ||
physics. To use this model, it is compiled into a Python implementation. | ||
The same symbolic model could also be compiled into a C++ implementation. | ||
See featuretests/python_library_for_model_evaluation/simple_test.py and the | ||
featuretests/ directory for additional features and examples. | ||
""" | ||
|
||
from formak.ui import Model, symbols, Symbol | ||
from formak import python | ||
|
||
from collections import defaultdict | ||
|
||
dt = symbols("dt") # change in time | ||
|
||
G = gravitational_constant = 6.674e-11 # m^3 / kg / s**2 | ||
Earth_Mass = 5.9722e24 # kg | ||
Earth_Equatorial_Radius = 6378.137 # m | ||
|
||
|
||
def SaturnVMass(): | ||
""" | ||
Summarize the mass distribution from the Apollo 7 launch vehicle. This mass | ||
will be used to initialize the state of the model. | ||
The details of the exact masses don't impact the definition of the model | ||
""" | ||
# Apollo 7 | ||
masses = { | ||
"SIB_dry": 84530, | ||
"SIB_oxidizer": 631300, | ||
"SIB_fuel": 276900, | ||
"SIB_other": 1182, | ||
"SIBSIVBinterstage_dry": 5543, | ||
"SIBSIVBinterstage_propellant": 1061, | ||
"SIVB_dry": 21852, | ||
"SIVB_oxidizer": 193330, | ||
"SIVB_fuel": 39909, | ||
"SIVB_other": 1432, | ||
"Instrument_dry": 4263, | ||
"Spacecraft_dry": 45312, | ||
} | ||
|
||
dry = 0 | ||
consumable = 0 | ||
|
||
for mass_description, mass_kg in masses.items(): | ||
if "dry" in mass_description: | ||
dry += mass_kg | ||
else: | ||
consumable += mass_kg | ||
|
||
assert (dry + consumable) == sum(masses.values()) | ||
|
||
mass_groups = defaultdict(float) | ||
for mass_description, mass_kg in masses.items(): | ||
group = mass_description.split("_")[0] | ||
mass_groups[group] += mass_kg | ||
|
||
print("Mass Groups") | ||
for k, v in sorted(list(mass_groups.items())): | ||
print(" {}: {}".format(k, v)) | ||
|
||
return {"dry": dry, "consumable": consumable} | ||
|
||
|
||
Vehicle_Mass_Properties = SaturnVMass() | ||
|
||
|
||
# states, calibrates, constants | ||
|
||
|
||
def gravitational_force(m_1, m_2, r): | ||
""" | ||
Calculate the gravitational force acting between two bodies. | ||
This function can be called with floating point values or symbolic values | ||
representing the possible masses and radii between the two masses. For this | ||
example, it's used to encapsulate the calculation of the gravitational | ||
force acting on the simplified model of a launch vehicle. | ||
""" | ||
return -G * (m_1 * m_2) / (r**2) | ||
|
||
|
||
def main(): | ||
""" | ||
The main function encapsulates a few common steps for all models: | ||
1. Defining symbols | ||
2. Identifying the symbol(s) used in the model state | ||
3. Identifying the symbol(s) used in the control inputs | ||
4. Defining the discrete state update | ||
5. Constructing the Model class | ||
The file also demonstrates: | ||
6. Compiling from the symbolic class to a Python model implementation | ||
7. Running a model update with the Python model | ||
""" | ||
|
||
# 1. Defining symbols | ||
vp = vehicle_properties = {k: Symbol(k) for k in ["m", "x", "v", "a"]} | ||
fuel_burn_rate = Symbol("fuel_burn_rate") | ||
|
||
# 2. Identifying the symbol(s) used in the model state | ||
state = set(vehicle_properties.values()) | ||
|
||
# 3. Identifying the symbol(s) used in the control inputs | ||
control = {fuel_burn_rate} # kg/sec | ||
|
||
# 4. Defining the discrete state update | ||
|
||
# momentum = mv | ||
# dmomentum / dt = F = d(mv)/dt | ||
# F = m dv/dt + dm/dt v | ||
# a = dv / dt = (F - dm/dt * v) / m | ||
|
||
F = gravitational_force(vp["m"], Earth_Mass, vp["x"] + Earth_Equatorial_Radius) | ||
|
||
state_model = { | ||
vp["m"]: vp["m"] - fuel_burn_rate * dt, | ||
vp["x"]: vp["x"] + (vp["v"] * dt) + (1 / 2 * vp["a"] * dt * dt), | ||
vp["v"]: vp["v"] + (vp["a"] * dt), | ||
vp["a"]: (F - (fuel_burn_rate * vp["v"])) / vp["m"], | ||
} | ||
|
||
# 5. Constructing the Model class | ||
symbolic_model = Model(dt, state, control, state_model, debug_print=True) | ||
|
||
initial_state = { | ||
vp["m"]: Vehicle_Mass_Properties["dry"] + Vehicle_Mass_Properties["consumable"], | ||
vp["x"]: 0.0, | ||
vp["v"]: 0.0, | ||
vp["a"]: 0.0, | ||
} | ||
|
||
# 6. Compiling from the symbolic class to a Python model implementation | ||
python_model = python.compile(symbolic_model=symbolic_model) | ||
|
||
# 7. Running a model update with the Python model | ||
state_vector = python_model.State.from_dict(initial_state) | ||
control_vector = python_model.Control.from_dict({fuel_burn_rate: 0.0}) | ||
|
||
print("Initial State") | ||
print(state_vector) | ||
|
||
state_vector_next = python_model.model( | ||
dt=0.1, state=state_vector, control=control_vector | ||
) | ||
|
||
print("Next State") | ||
print(state_vector_next) | ||
|
||
return 0 | ||
|
||
|
||
if __name__ == "__main__": | ||
import sys | ||
|
||
sys.exit(main()) |
Oops, something went wrong.