pub struct Aircraft { /* private fields */ }Expand description
The aircraft we’re planning to fly with.
This aircraft provides all information necessary to execute the fuel and
mass & balance planning. The aircraft is created in it’s empty
configuration. All additional mass are loaded at a Station that places
the mass at a fixed distance from a reference datum (the arm). The
aircraft is created only with the station arms and mass is mapped to the
stations when doing the mass & balance calculation. Stations that account
for the mass of fuel are derived from the tanks and fuel consumption.
The aircraft’s mass & balance is calculated by mb for mass and fuel at
ramp and after landing. There are further methods to calculate the mass &
balance based on simplifications like constant mass during flight or equal
fuel distribution across all tanks.
§Examples
This is how a C172 of our flying club with a Diesel engine would look like:
let ac = Aircraft::builder()
.registration("N12345".to_string())
.icao_type("C172".to_string())
.stations(vec![
Station::new(Length::m(0.94), Some("front seats".to_string())),
Station::new(Length::m(1.85), Some("back seats".to_string())),
Station::new(Length::m(2.41), Some("first cargo compartment".to_string())),
Station::new(Length::m(3.12), Some("second cargo compartment".to_string())),
])
.empty_mass(Mass::kg(807.0))
.empty_balance(Length::m(1.0))
.fuel_type(FuelType::Diesel)
.tanks(vec![
FuelTank::new(Volume::l(168.8), Length::m(1.22)),
])
.cg_envelope(vec![
CGLimit::new(Mass::kg(0.0), Length::m(0.89)),
CGLimit::new(Mass::kg(885.0), Length::m(0.89)),
CGLimit::new(Mass::kg(1111.0), Length::m(1.02)),
CGLimit::new(Mass::kg(1111.0), Length::m(1.20)),
CGLimit::new(Mass::kg(0.0), Length::m(1.20)),
])
.build()
.unwrap();
// now we can calculate the mass & balance for a flight with one pilot on
// board and 20 Liter fuel consumption that is distributed equally across
// all tanks
let mb = ac.mb_from_const_mass_and_equally_distributed_fuel(
&vec![
// we're in the front
Mass::kg(80.0),
// and no mass on the other stations
Mass::kg(0.0),
Mass::kg(0.0),
Mass::kg(0.0)
],
// we start our flight with 80 Liter of Diesel
&diesel!(Volume::l(80.0)),
// and land with 60 Liter remaining in our tank
&diesel!(Volume::l(60.0)),
);
// finally we can check if the aircraft is balanced throughout the flight
assert!(ac.is_balanced(&mb.unwrap()));Implementations§
Source§impl Aircraft
impl Aircraft
Sourcepub fn builder() -> AircraftBuilder
pub fn builder() -> AircraftBuilder
Returns a builder to build an aircraft.
Examples found in repository?
38fn main() -> Result<()> {
39 // Performance setting with 65% load in cruise. This is the performance
40 // profile of a Cessna C172 with an TAE125-02-114 Diesel engine.
41 let perf = Performance::from_fn(
42 |vd| {
43 let tas = if *vd >= VerticalDistance::Altitude(10000) {
44 Speed::kt(114.0)
45 } else if *vd >= VerticalDistance::Altitude(8000) {
46 Speed::kt(112.0)
47 } else if *vd >= VerticalDistance::Altitude(6000) {
48 Speed::kt(110.0)
49 } else if *vd >= VerticalDistance::Altitude(4000) {
50 Speed::kt(109.0)
51 } else {
52 Speed::kt(107.0)
53 };
54
55 let ff = FuelFlow::PerHour(diesel!(Volume::l(21.0)));
56
57 (tas, ff)
58 },
59 // The data end at 10000 ft so we don't need to create the Performance
60 // with more values.
61 VerticalDistance::Altitude(10000),
62 );
63
64 let takeoff_perf = TakeoffLandingPerformance::builder(vec![
65 (
66 VerticalDistance::PressureAltitude(0),
67 Temperature::c(0.0),
68 Length::ft(845.0),
69 Length::ft(1510.0),
70 ),
71 (
72 VerticalDistance::PressureAltitude(0),
73 Temperature::c(10.0),
74 Length::ft(910.0),
75 Length::ft(1625.0),
76 ),
77 (
78 VerticalDistance::PressureAltitude(0),
79 Temperature::c(20.0),
80 Length::ft(980.0),
81 Length::ft(1745.0),
82 ),
83 (
84 VerticalDistance::PressureAltitude(0),
85 Temperature::c(30.0),
86 Length::ft(1055.0),
87 Length::ft(1875.0),
88 ),
89 (
90 VerticalDistance::PressureAltitude(0),
91 Temperature::c(40.0),
92 Length::ft(1135.0),
93 Length::ft(2015.0),
94 ),
95 ])
96 .factors(vec![
97 // Decrease distances 10% for each 9 knots headwind. For operation
98 // with tail winds up to 10 knots, increase distances by 10% for
99 // each 2 knots.
100 AlteringFactor::DecreaseHeadwind(FactorOfEffect::Rate {
101 numerator: 0.1,
102 denominator: Speed::kt(9.0),
103 }),
104 AlteringFactor::IncreaseTailwind(FactorOfEffect::Rate {
105 numerator: 0.1,
106 denominator: Speed::kt(2.0),
107 }),
108 // For operation on dry, grass runway, increase distances by 15% of
109 // the "ground roll" figure.
110 AlteringFactor::IncreaseRWYCC(HashMap::from([
111 ((None, Some(RunwaySurface::Grass)), 0.15), // we'll add 15% on any grass
112 ])),
113 ])
114 .build();
115
116 let aircraft = Aircraft::builder()
117 .registration("N12345".to_string())
118 .stations(vec![
119 Station::new(Length::m(0.94), Some(String::from("front seats"))),
120 Station::new(Length::m(1.85), Some(String::from("back seats"))),
121 Station::new(
122 Length::m(2.41),
123 Some(String::from("first cargo compartment")),
124 ),
125 Station::new(
126 Length::m(3.12),
127 Some(String::from("second cargo compartment")),
128 ),
129 ])
130 .empty_mass(Mass::kg(807.0))
131 .empty_balance(Length::m(1.0))
132 .fuel_type(FuelType::Diesel)
133 .tanks(vec![FuelTank::new(Volume::l(168.8), Length::m(1.22))])
134 .cg_envelope(vec![
135 CGLimit::new(Mass::kg(0.0), Length::m(0.89)),
136 CGLimit::new(Mass::kg(885.0), Length::m(0.89)),
137 CGLimit::new(Mass::kg(1111.0), Length::m(1.02)),
138 CGLimit::new(Mass::kg(1111.0), Length::m(1.20)),
139 CGLimit::new(Mass::kg(0.0), Length::m(1.20)),
140 ])
141 .build()
142 .expect("all required aircraft parameter should be configured");
143
144 let mut fms = FMS::new();
145
146 // read the ARINC database
147 let ed_nd = NavigationData::try_from_arinc424(ARINC_424_RECORDS)?;
148
149 fms.modify_nd(|nd| nd.append(ed_nd))?;
150
151 // decode a route from EDDH to EDHF with winds at 20 kt from 290° and
152 // cruising speed of 107 kt and an altitude of 2500 ft. Takeoff runway in
153 // EDDH is runway 33 and landing runway in EDHF is 20.
154 fms.decode("29020KT N0107 A0250 EDDH33 N2 N1 DCT EDHF20".to_string())?;
155
156 // Now we can enter some data into the flight planning to get a fuel planning
157 // and mass & balance calculation.
158 let mut builder = FlightPlanning::builder();
159
160 builder
161 .aircraft(aircraft)
162 .mass(vec![
163 // we're in the front
164 Mass::kg(80.0),
165 // and no mass on the other stations
166 Mass::kg(0.0),
167 Mass::kg(0.0),
168 Mass::kg(0.0),
169 ])
170 .policy(FuelPolicy::ManualFuel(diesel!(Volume::l(80.0))))
171 .taxi(diesel!(Volume::l(10.0)))
172 .reserve(Reserve::Manual(Duration::s(1800))) // 30 min
173 .perf(perf)
174 .takeoff_perf(takeoff_perf)
175 // we use the route's wind so no need to specify it here
176 .origin_rwycc(RunwayConditionCode::Six)
177 .origin_temperature(Temperature::c(20.0));
178
179 fms.set_flight_planning(builder)?;
180
181 println!("{}", fms.print(40));
182
183 Ok(())
184}Sourcepub fn registration(&self) -> &str
pub fn registration(&self) -> &str
The unique registration code of the aircraft aka tail number.
Sourcepub fn stations(&self) -> &[Station]
pub fn stations(&self) -> &[Station]
The distances from a reference datum at which mass can be loaded e.g. the position of a seat.
Sourcepub fn empty_mass(&self) -> &Mass
pub fn empty_mass(&self) -> &Mass
The mass of the empty aircraft taken from the last mass and balance report.
Sourcepub fn empty_balance(&self) -> &Length
pub fn empty_balance(&self) -> &Length
The center of gravity of the empty aircraft taken from the last mass and balance report.
Sourcepub fn cg_envelope(&self) -> &CGEnvelope
pub fn cg_envelope(&self) -> &CGEnvelope
The center of gravity envelope which must contains the CG at a mass for the aircraft to be balanced.
Sourcepub fn notes(&self) -> Option<&str>
pub fn notes(&self) -> Option<&str>
Notes regarding the aircraft e.g. when the empty mass and balance were determined.
Sourcepub fn usable_fuel(&self) -> Option<Fuel>
pub fn usable_fuel(&self) -> Option<Fuel>
Returns the usable fuel.
The usable fuel is the sum of all tank capacities with the aircraft’s
fuel type or None if no tank is defined.
Sourcepub fn is_balanced(&self, mb: &MassAndBalance) -> bool
pub fn is_balanced(&self, mb: &MassAndBalance) -> bool
Tests if the mass & balance is within the aircraft’s CGEnvelope.
Sourcepub fn mb(
&self,
mass_on_ramp: &[Mass],
mass_after_landing: &[Mass],
fuel_on_ramp: &[Fuel],
fuel_after_landing: &[Fuel],
) -> Result<MassAndBalance, Error>
pub fn mb( &self, mass_on_ramp: &[Mass], mass_after_landing: &[Mass], fuel_on_ramp: &[Fuel], fuel_after_landing: &[Fuel], ) -> Result<MassAndBalance, Error>
Returns the mass & balance on ramp and after landing.
The mass vectors are mapped to the station arms by position e.g. the mass at index 0 is placed at the station arm at index 0. Thus, the length of the mass vectors must match the length of the station arms. The same goes for the fuel, however the fuel vectors are mapped to the tanks.
§Errors
If the length of any mass vector doesn’t match the length of the station arms or the length of any fuel vector doesn’t match the tanks length, an error is returned.
pub fn mb_from_equally_distributed_fuel( &self, mass_on_ramp: &[Mass], mass_after_landing: &[Mass], on_ramp: &Fuel, after_landing: &Fuel, ) -> Result<MassAndBalance, Error>
pub fn mb_from_const_mass_and_equally_distributed_fuel( &self, mass: &[Mass], on_ramp: &Fuel, after_landing: &Fuel, ) -> Result<MassAndBalance, Error>
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Aircraft
impl<'de> Deserialize<'de> for Aircraft
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for Aircraft
impl StructuralPartialEq for Aircraft
Auto Trait Implementations§
impl Freeze for Aircraft
impl RefUnwindSafe for Aircraft
impl Send for Aircraft
impl Sync for Aircraft
impl Unpin for Aircraft
impl UnsafeUnpin for Aircraft
impl UnwindSafe for Aircraft
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more