Skip to content

Commit

Permalink
Editing ham stand docs
Browse files Browse the repository at this point in the history
  • Loading branch information
johnjasa committed Mar 21, 2024
1 parent 039451d commit a247294
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 30 deletions.
60 changes: 43 additions & 17 deletions aviary/docs/user_guide/hamilton_standard.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Hamilton Standard Propulsion Model

In the 1970s, NASA contracted Hamilton Standard to forecast into the future mid-80s to the 90s what they thought advanced propellers would look like. They took existing data and projected into the future. The result is what we call “Hamilton Standard model” today. The Hamilton Standard Documentation is publicly available on NTRS: [19720010354.pdf(https://ntrs.nasa.gov/api/citations/19720010354/downloads/19720010354.pdf) (nasa.gov). You can find the definitions, methodology, and Fortran code in the doc. In Aviary, we implement only one of the options, namely, for a given horsepower, it computes the corresponding thrust.
In the 1970s, NASA contracted Hamilton Standard to forecast into the future mid-80s to the 90s what they thought advanced propellers would look like.
The result is what we call “Hamilton Standard model” used in Aviary today.
The [Hamilton Standard Documentation is publicly available](https://ntrs.nasa.gov/api/citations/19720010354/downloads/19720010354.pdf).
You can find the definitions, methodology, and Fortran code in the document.
In Aviary, we implement only one of the computation options: the code computes the corresponding thrust for a given horsepower.

Below is an XDSM diagram of Hamilton Standard model:

Expand All @@ -9,32 +13,40 @@ Below is an XDSM diagram of Hamilton Standard model:
The inputs are grouped in three aspects:

Geometric inputs:

- Propeller diameter
- Activity factor per blade (range: 80 to 200, baseline: 150)
- Number of blades (range: 2 to 8)

Power inputs:

- Shaft power to propeller (hp)
- Installation loss factor (0 to 1)

Performance inputs:

- Operating altitude (ft)
- True airspeed (knots)
- Propeller tip speed (Usually < 800 ft/s)
- Propeller tip speed (Usually < 800 ft/s)
- Integrated lift coefficient (range: 0.3 to 0.8, baseline: 0.5)

Note that some of the inputs are good for limited ranges. The Hamilton Standard model can have odd number of blades although the data provided are based on even number of blades. For odd number of blades, interpolations using 2, 4, 6 and 8 blade data are used. The corresponding outputs are:
Some of the inputs are valid for limited ranges.
When using an odd number of blades, the Hamilton Standard model interpolates using the 2, 4, 6 and 8 blade data.
The corresponding outputs are:

Geometric outputs:

- Design blade pitch angle (at 0.75 Radius)

Power outputs:

- Installation loss factor
- Tip compressibility loss factor
- Power coefficient
- Thrust coefficient (rho=const, no losses)

Performance outputs:

- Flight Mach number
- Propeller tip Mach number
- Advance ratio
Expand All @@ -43,33 +55,47 @@ Performance outputs:
- Propeller efficiency with compressibility losses
- Propeller efficiency with compressibility and installation losses

As shown in the above XDSM diagram, the model is an OpenMDAO group that is composed of four components and one subgroup:
As shown in the above XDSM diagram, the model is an OpenMDAO group that is composed of four components and one subgroup:

- `USatmos`
- `PreHamiltonStandard`
- `HamiltonStandard`
- `InstallLoss`
- `PostHamiltonStandard`.
- `PostHamiltonStandard`

`USatmos` component provides the flight condition. The flight condition is passed to `PreHamiltonStandard` component from which flight Mach number, propeller tip Mach number, advance ratio and power coefficient are computed. They are fed into `HamiltonStandard` component.
`USatmos` component provides the flight conditions.
The flight conditions are passed to the `PreHamiltonStandard` component which computes the propeller tip Mach number, advance ratio, and power coefficient.
These values are then fed into the `HamiltonStandard` component.

![CP and CT matching](images/CPE_CTE_matching.png)
`HamiltonStandard` is the core of the model.
Given the power coefficient (CP) and advance ratio (J), it finds the blade angle (BL) by a CP-BL chart by tracing the advance ratio.
Then with the blade angle, it finds the thrust coefficient (CT) using its CT-BL chart by tracing advance ratio again.
This algorithm is shown in the below pair of charts.
The CP → BL → CT chart matching algorithm is based on baseline data.
If the user-inputted values are not in the valid region, it will first convert them to those baseline parameters by a sequence of interpolations to do the necessary corrections.
The newly converted parameters are called “effective parameters” (e.g., CPE and CTE).
The outputs are blade angle, thrust coefficient and tip compressibility loss factor.

HamiltonStandard is the core of the model. Given the power coefficient (CP) and advance ratio (J), it finds the blade angle (BL) by a CP-BL chart by tracing advance ratio and then with the blade angle, it finds the thrust coefficient (CT) using its CT-BL chart by tracing advance ratio again. This algorithm is shown in the above pair of charts. The CP → BL → CT chart matching algorithm is based on baseline data. If user inputs are not on baseline, it will first convert them to those baseline parameters by a sequence of interpolations to do corrections. The newly converted parameters are called “effective parameters” (e.g., CPE and CTE). The outputs are blade angle, thrust coefficient and tip compressibility loss factor.
![CP and CT matching](images/CPE_CTE_matching.png)

Finally, the thrust is computed in the `PostHamiltonStandard` component based on thrust coefficient and tip compressibility loss factor.

The Hamilton Standard model uses wind tunnel test data from un-installed propellers. When a nacelle is mounted behind the propeller, an installation loss factor is introduced. The installation loss factor can be given by the user or computed. If it is computed, we need another group of components as shown below:
The Hamilton Standard model uses wind tunnel test data from uninstalled propellers.
When a nacelle is mounted behind the propeller, an installation loss factor is introduced.
The installation loss factor can be given by the user or computed.
If it is computed, we need another group of components as shown below:

![Installation Loss Factor](images/installation_loss_factor.png)

This diagram is represented by `InstallLoss` group in the first diagram. Note that nacelle diameter is needed when installation loss factor is computed. We use the average nacelle diameter.
This diagram is represented by `InstallLoss` group in the first diagram.
Nacelle diameter is needed when installation loss factor is computed.
We use the average nacelle diameter.

The newly added aviary options and variables are:

```
```none
Aircraft.Engine.PROPELLER_DIAMETER
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT
Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR
Aircraft.Engine.NUM_BLADES
Aircraft.Design.COMPUTE_INSTALLATION_LOSS
Expand All @@ -78,24 +104,24 @@ Dynamic.Mission.SHAFT_POWER
Dynamic.Mission.INSTALLATION_LOSS_FACTOR
```

To build a turboprop engine that uses the Hamilton Standard propeller model, we use a `TurboPropDeck` object with `prop_model` set to `True`:
To build a turboprop engine that uses the Hamilton Standard propeller model we use a `TurboPropDeck` object with `prop_model` set to `True`:

```
```python
engine = TurboPropDeck(options=options, prop_model=True)
```

Some inputs are options:

```
```python
options.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10, units='ft')
options.set_val(Aircraft.Engine.NUM_BLADES, val=4, units='unitless')
options.set_val(Aircraft.Design.COMPUTE_INSTALLATION_LOSS, val=True, units='unitless')
```

We set the inputs like the following:

```
```python
prob.set_val(f'traj.cruise.rhs_all.{Dynamic.Mission.PROPELLER_TIP_SPEED}', 750., units='ft/s')
prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR}', 150., units='unitless')
prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT}', 0.5, units='unitless')
prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT}', 0.5, units='unitless')
```
8 changes: 4 additions & 4 deletions aviary/subsystems/propulsion/hamilton_standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ def setup(self):
self.add_input('tip_mach', val=np.zeros(nn), units='unitless')
self.add_input(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, val=0.0,
units='unitless') # Actitivty Factor per Blade
self.add_input(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT,
self.add_input(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT,
val=0.0, units='unitless') # blade integrated lift coeff

self.add_output('thrust_coefficient', val=np.zeros(nn), units='unitless')
Expand Down Expand Up @@ -630,7 +630,7 @@ def compute(self, inputs, outputs):
# flag that given lift coeff (cli) does not fall on a node point of CL_arr
CL_tab_idx_flg = 0 # NCL_flg
ifnd = 0
cli = inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT][0]
cli = inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT][0]
power_coefficient = inputs['power_coefficient'][i_node]
for ii in range(6):
cl_idx = ii
Expand Down Expand Up @@ -715,7 +715,7 @@ def compute(self, inputs, outputs):
CL_tab_idx = CL_tab_idx+1
if (CL_tab_idx_flg != 1):
PCLI, run_flag = _unint(
CL_arr[CL_tab_idx_begin:CL_tab_idx_begin+4], PXCLI[CL_tab_idx_begin:CL_tab_idx_begin+4], inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT][0])
CL_arr[CL_tab_idx_begin:CL_tab_idx_begin+4], PXCLI[CL_tab_idx_begin:CL_tab_idx_begin+4], inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT][0])
else:
PCLI = PXCLI[CL_tab_idx_begin]
# PCLI = CLI adjustment to power_coefficient
Expand Down Expand Up @@ -777,7 +777,7 @@ def compute(self, inputs, outputs):
XFFT[kl], run_flag = _biquad(comp_mach_CT_arr, 1, DMN, CTE2)
CL_tab_idx = CL_tab_idx + 1
if (CL_tab_idx_flg != 1):
cli = inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT][0]
cli = inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT][0]
TCLII, run_flag = _unint(
CL_arr[CL_tab_idx_begin:CL_tab_idx_begin+4], TXCLI[CL_tab_idx_begin:CL_tab_idx_begin+4], cli)
xft, run_flag = _unint(
Expand Down
2 changes: 1 addition & 1 deletion aviary/subsystems/propulsion/prop_performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def setup(self):
"adv_ratio",
"tip_mach",
Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR,
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT,
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT,
],
promotes_outputs=[
"thrust_coefficient",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ def test_turboprop(self):
prob.set_val(
f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR}', 150., units='unitless')
prob.set_val(
f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT}', 0.5, units='unitless')
f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT}', 0.5, units='unitless')

prob.set_solver_print(level=0)

Expand Down
6 changes: 3 additions & 3 deletions aviary/subsystems/propulsion/test/test_prop_performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def setUp(self):

prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10.5, units="ft")
prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 114.0, units="unitless")
prob.set_val(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT,
prob.set_val(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT,
0.5, units="unitless")
prob.set_val(Aircraft.Nacelle.AVG_DIAMETER, 2.8875, units='ft')

Expand Down Expand Up @@ -122,7 +122,7 @@ def test_case_3_4_5(self):
[0.0, 0.05, 0.05], units="unitless")
prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 12.0, units="ft")
prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 150.0, units="unitless")
prob.set_val(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT,
prob.set_val(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT,
0.5, units="unitless")
prob.set_val(Dynamic.Mission.ALTITUDE, [10000.0, 10000.0, 0.0], units="ft")
prob.set_val(Dynamic.Mission.VELOCITY, [200.0, 200.0, 50.0], units="knot")
Expand Down Expand Up @@ -153,7 +153,7 @@ def test_case_6_7_8(self):
[0.0, 0.05, 0.05], units="unitless")
prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 12.0, units="ft")
prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 150.0, units="unitless")
prob.set_val(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT,
prob.set_val(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT,
0.5, units="unitless")
prob.set_val(Dynamic.Mission.ALTITUDE, [10000.0, 10000.0, 0.0], units="ft")
prob.set_val(Dynamic.Mission.VELOCITY, [200.0, 200.0, 50.0], units="knot")
Expand Down
4 changes: 2 additions & 2 deletions aviary/subsystems/propulsion/test/test_turboprops.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def test_case_3(self):
self.prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR,
114.0, units="unitless")
self.prob.set_val(
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT, 0.5, units="unitless")
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless")

if options.get_val(Settings.VERBOSITY, units='unitless') is Verbosity.DEBUG:
om.n2(
Expand All @@ -198,7 +198,7 @@ def test_case_4(self):
self.prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR,
114.0, units="unitless")
self.prob.set_val(
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT, 0.5, units="unitless")
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless")

self.prob.run_model()
results = self.get_results(point_names)
Expand Down
2 changes: 1 addition & 1 deletion aviary/variable_info/variable_meta_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1918,7 +1918,7 @@
)

add_meta_data(
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICENT,
Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT,
meta_data=_MetaData,
historical_name={"GASP": 'INGASP.CLI',
"FLOPS": None,
Expand Down
2 changes: 1 addition & 1 deletion aviary/variable_info/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ class Engine:
POSITION_FACTOR = 'aircraft:engine:position_factor'
PROPELLER_ACTIVITY_FACTOR = 'aircraft:engine:propeller_activity_factor'
PROPELLER_DIAMETER = 'aircraft:engine:propeller_diameter'
PROPELLER_INTEGRATED_LIFT_COEFFICENT = 'aircraft:engine:propeller_integrated_lift_coefficient'
PROPELLER_INTEGRATED_LIFT_COEFFICIENT = 'aircraft:engine:propeller_integrated_lift_coefficient'
PYLON_FACTOR = 'aircraft:engine:pylon_factor'
REFERENCE_DIAMETER = 'aircraft:engine:reference_diameter'
REFERENCE_MASS = 'aircraft:engine:reference_mass'
Expand Down

0 comments on commit a247294

Please sign in to comment.