def alt2temp(H, alt_units=default_alt_units, temp_units=default_temp_units): """Return the standard temperature for the specified altitude. Altitude units may be feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'). Temperature units may be degrees C, F, K or R ('C', 'F', 'K' or 'R') If the units are not specified, the units in default_units.py are used. Examples: Calculate the standard temperature (in default temperature units) at 5,000 (default altitude units): >>> alt2temp(5000) 5.093999999999994 Calculate the standard temperature in deg F at sea level: >>> alt2temp(0, temp_units = 'F') 59.0 Calculate the standard temperature in deg K at 11,000 m: >>> alt2temp(11000, alt_units = 'm', temp_units = 'K') 216.64999999999998 Calculate the standard temperature at 11 statute miles in deg R: >>> alt2temp(11, alt_units = 'sm', temp_units = 'R') 389.96999999999997 The input value may be an expression: >>> alt2temp(11 * 5280, temp_units = 'R') 389.96999999999997 """ # Validated to 84000 m # uses meters and degrees K for the internal calculations # function tested in tests/test_std_atm.py H = U.length_conv(H, from_units=alt_units, to_units='km') if H <= 11: temp = T0 + H * L0 elif H <= 20: temp = T11 elif H <= 32: temp = T20 + (H - 20) * L20 elif H <= 47: temp = T32 + (H - 32) * L32 elif H <= 51: temp = T47 elif H <= 71: temp = T51 + (H - 51) * L51 elif H <= 84.852: temp = T71 + (H - 71) * L71 else: raise ValueError( 'This function is only implemented for altitudes of 84.852 km and below.' ) return U.temp_conv(temp, to_units=temp_units, from_units='K')
def cp2bhp(Cp, rpm, density, dia, power_units='hp', density_units='lb/ft**3', dia_units='in'): """ Returns the bhp, given propeller power coefficient (Cp), revolutions per minute (rpm), and propeller diameter. The power units may be specified as "hp", "ft-lb/mn", "ft-lb/s", "W" (watts) or "kW" (kilowatts), but default to "hp" if not specified. The density units may be specified as "lb/ft**3", "slug/ft**3" or "kg/m**3", but default to "lb/ft**3" if not specified. The diameter units may be specified as "in", "ft", or "m", but default to inches if not specified. """ # bhp = U.power_conv(bhp, from_units = power_units, to_units = 'W') density = U.density_conv(density, from_units=density_units, to_units='kg/m**3') dia = U.length_conv(dia, from_units=dia_units, to_units='m') bhp = Cp * (density * ((rpm / 60.)**3) * dia**5) bhp = U.power_conv(bhp, from_units='W', to_units=power_units) return bhp
def tip_mach(tas, rpm, temperature, dia, speed_units='kt', temp_units='C', dia_units='in'): """ Returns the mach number of the propeller blade tip, given the true airspeed (tas), revolutions per minute (rpm), temperature and propeller diameter. The speed units may be specified as "kt", "mph", "km/h" or "ft/s", but default to "kt" if not specified. The temperature units may be specified as "C", "F", "K" or "R", but default to deg C if not specified. The diameter units may be specified as "in", "ft", or "m", but default to inches if not specified. """ dia = U.length_conv(dia, from_units=dia_units, to_units='m') tas = U.speed_conv(tas, from_units=speed_units, to_units='m/s') speed_of_sound = SA.temp2speed_of_sound(temperature, temp_units=temp_units, speed_units='m/s') rotation_speed = dia * rpm * M.pi / 60 tip_speed = M.sqrt(tas**2 + rotation_speed**2) tip_mach = tip_speed / speed_of_sound return tip_mach
def press2alt(P, press_units=default_press_units, alt_units=default_alt_units): """ Return the altitude corresponding to the specified pressure, with pressure in inches of HG, mm of HG, psi, psf (lb per sq. ft), pa, hpa or mb. The altitude is in units of feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm') If the units are not specified, the units in default_units.py are used. Examples: Calculate the pressure altitude in feet for a pressure of 31.0185 inches of HG: >>> press2alt(31.0185) -999.9602016597179 Calculate the pressure altitude in feet for a pressure of 1455.33 lb sq. ft: >>> press2alt(1455.33, press_units = 'psf') 10000.029960829057 Calculate the pressure altitude in metres for a pressure of 90.3415 mm HG: >>> press2alt(90.3415, press_units = 'mm HG', alt_units = 'm') 15000.032231346277 Calculate the pressure altitude in metres for a pressure of 1171.86 pascal: >>> press2alt(1171.86, press_units = 'pa', alt_units = 'm') 30000.03658869385 """ # function tested in tests/test_std_atm.py P = U.press_conv(P, from_units=press_units, to_units='pa') if P > P11: H = _press2alt_gradient(P, P0, 0, T0, L0) elif P > P20: H = _press2alt_isothermal(P, P11, 11, T11) elif P > P32: H = _press2alt_gradient(P, P20, 20, T20, L20) elif P > P47: H = _press2alt_gradient(P, P32, 32, T32, L32) elif P > P51: H = _press2alt_isothermal(P, P47, 47, T47) elif P > P71: H = _press2alt_gradient(P, P51, 51, T51, L51) else: H = _press2alt_gradient(P, P71, 71, T71, L71) if H > 84.852: raise ValueError( 'This function is only implemented for altitudes of 84.852 km and below.' ) return U.length_conv(H, from_units='km', to_units=alt_units)
def alt2temp(H, alt_units=default_alt_units, temp_units=default_temp_units): """Return the standard temperature for the specified altitude. Altitude units may be feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'). Temperature units may be degrees C, F, K or R ('C', 'F', 'K' or 'R') If the units are not specified, the units in default_units.py are used. Examples: Calculate the standard temperature (in default temperature units) at 5,000 (default altitude units): >>> alt2temp(5000) 5.0939999999999941 Calculate the standard temperature in deg F at sea level: >>> alt2temp(0, temp_units = 'F') 59.0 Calculate the standard temperature in deg K at 11,000 m: >>> alt2temp(11000, alt_units = 'm', temp_units = 'K') 216.64999999999998 Calculate the standard temperature at 11 statute miles in deg R: >>> alt2temp(11, alt_units = 'sm', temp_units = 'R') 389.96999999999997 The input value may be an expression: >>> alt2temp(11 * 5280, temp_units = 'R') 389.96999999999997 """ # Validated to 84000 m # uses meters and degrees K for the internal calculations # function tested in tests/test_std_atm.py H = U.length_conv(H, from_units=alt_units, to_units='km') if H <= 11: temp = T0 + H * L0 elif H <= 20: temp = T11 elif H <= 32: temp = T20 + (H - 20) * L20 elif H <= 47: temp = T32 + (H - 32) * L32 elif H <= 51: temp = T47 elif H <= 71: temp = T51 + (H - 51) * L51 elif H <= 84.852: temp = T71 + (H - 71) * L71 else: raise ValueError('This function is only implemented for altitudes of 84.852 km and below.') return U.temp_conv(temp, to_units=temp_units, from_units='K')
def QNH( HP, H, alt_units=default_alt_units, alt_setting_units='in HG', ): """ Return the altimeter setting, given the pressure altitude (HP) and the barometric altitude (H). """ HP = U.length_conv(HP, from_units=alt_units, to_units='ft') H = U.length_conv(H, from_units=alt_units, to_units='ft') QNH = P0 * (1 - (HP - H) / 145442.2)**5.255594 QNH = U.press_conv(QNH, from_units='in HG', to_units=alt_setting_units) return QNH
def press2alt(P, press_units=default_press_units, alt_units=default_alt_units): """ Return the altitude corresponding to the specified pressure, with pressure in inches of HG, mm of HG, psi, psf (lb per sq. ft), pa, hpa or mb. The altitude is in units of feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm') If the units are not specified, the units in default_units.py are used. Examples: Calculate the pressure altitude in feet for a pressure of 31.0185 inches of HG: >>> press2alt(31.0185) -999.96020165971788 Calculate the pressure altitude in feet for a pressure of 1455.33 lb sq. ft: >>> press2alt(1455.33, press_units = 'psf') 10000.029960829057 Calculate the pressure altitude in metres for a pressure of 90.3415 mm HG: >>> press2alt(90.3415, press_units = 'mm HG', alt_units = 'm') 15000.032231346277 Calculate the pressure altitude in metres for a pressure of 1171.86 pascal: >>> press2alt(1171.86, press_units = 'pa', alt_units = 'm') 30000.036588693849 """ # function tested in tests/test_std_atm.py P = U.press_conv(P, from_units=press_units, to_units='pa') if P > P11: H = _press2alt_gradient(P, P0, 0, T0, L0) elif P > P20: H = _press2alt_isothermal(P, P11, 11, T11) elif P > P32: H = _press2alt_gradient(P, P20, 20, T20, L20) elif P > P47: H = _press2alt_gradient(P, P32, 32, T32, L32) elif P > P51: H = _press2alt_isothermal(P, P47, 47, T47) elif P > P71: H = _press2alt_gradient(P, P51, 51, T51, L51) else: H = _press2alt_gradient(P, P71, 71, T71, L71) if H > 84.852: raise ValueError('This function is only implemented for altitudes of 84.852 km and below.') return U.length_conv(H, from_units='km', to_units=alt_units)
def QNH( HP, H, alt_units=default_alt_units, alt_setting_units='in HG', ): """ Return the altimeter setting, given the pressure altitude (HP) and the barometric altitude (H). """ HP = U.length_conv(HP, from_units=alt_units, to_units='ft') H = U.length_conv(H, from_units=alt_units, to_units='ft') QNH = P0 * (1 - (HP - H) / 145442.2) ** 5.255594 QNH = U.press_conv(QNH, from_units='in HG', to_units=alt_setting_units) return QNH
def pressure_alt(H, alt_setting, alt_units=default_alt_units): """ Return the pressure altitude, given the barometric altitude and the altimeter setting. Altimeter setting may have units of inches of HG, or hpa or mb. If the altimeter setting value is less than 35, the units are assumed to be in HG, otherwise they are assumed to be hpa. The altimeter setting must be in the range of 25 to 35 inches of mercury. The altitude may have units of feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'). If the units are not specified, the units in default_units.py are used. Examples: Calculate the pressure altitude for 1,000 (default altitude units) barometric altitude with altimeter setting of 30.92 in HG: >>> pressure_alt(1000, 30.92) 88.6424431787118 Calculate the pressure altitude for 1,000 (default altitude units) barometric altitude with altimeter setting of 1008 mb: >>> pressure_alt(1000, 1008) 1143.679844292918 Calculate the pressure altitude in metres for 304.8 m barometric altitude with altimeter setting of 1008 mb: >>> pressure_alt(304.8, 1008, alt_units = 'm') 348.59361654048143 """ H = U.length_conv(H, from_units=alt_units, to_units='ft') if alt_setting > 35: alt_setting = U.press_conv(alt_setting, from_units='hpa', to_units='in HG') if alt_setting < 25 or alt_setting > 35: raise ValueError('Altimeter setting out of range.') base_press = U.press_conv(P0, from_units='pa', to_units='in HG') HP = H + 145442.2 * (1 - (alt_setting / base_press)**0.190261) HP = U.length_conv(HP, from_units='ft', to_units=alt_units) return HP
def pressure_alt(H, alt_setting, alt_units=default_alt_units): """ Return the pressure altitude, given the barometric altitude and the altimeter setting. Altimeter setting may have units of inches of HG, or hpa or mb. If the altimeter setting value is less than 35, the units are assumed to be in HG, otherwise they are assumed to be hpa. The altimeter setting must be in the range of 25 to 35 inches of mercury. The altitude may have units of feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'). If the units are not specified, the units in default_units.py are used. Examples: Calculate the pressure altitude for 1,000 (default altitude units) barometric altitude with altimeter setting of 30.92 in HG: >>> pressure_alt(1000, 30.92) 88.642443178711801 Calculate the pressure altitude for 1,000 (default altitude units) barometric altitude with altimeter setting of 1008 mb: >>> pressure_alt(1000, 1008) 1143.679844292918 Calculate the pressure altitude in metres for 304.8 m barometric altitude with altimeter setting of 1008 mb: >>> pressure_alt(304.8, 1008, alt_units = 'm') 348.59361654048143 """ H = U.length_conv(H, from_units=alt_units, to_units='ft') if alt_setting > 35: alt_setting = U.press_conv(alt_setting, from_units='hpa', to_units='in HG') if alt_setting < 25 or alt_setting > 35: raise ValueError('Altimeter setting out of range.') base_press = U.press_conv(P0, from_units='pa', to_units='in HG') HP = H + 145442.2 * (1 - (alt_setting / base_press) ** 0.190261) HP = U.length_conv(HP, from_units='ft', to_units=alt_units) return HP
def ct2thrust(Ct, Rho, rpm, dia, thrust_units="lb", density_units="lb/ft**3", dia_units="in"): """ Returns the thrust, given thrust coefficient, Ct, density, rpm and prop diameter. """ Rho = U.density_conv(Rho, from_units=density_units, to_units="kg/m**3") dia = U.length_conv(dia, from_units=dia_units, to_units="m") # convert rpm to revolutions / s n = rpm / 60.0 thrust = Ct * Rho * n ** 2.0 * dia ** 4.0 return U.force_conv(thrust, from_units="N", to_units=thrust_units)
def pwr(rpm, MP, altitude, temp = 'std', alt_units = 'ft', temp_units = 'C'): """ Returns horsepower for Lycoming IO-360-A series engines, given: rpm - engine speed in revolutions per minute MP - manifold pressure (" HG) altitude - pressure altitude temp - ambient temperature (optional - std temperature is used if no temperature is input). alt_units - (optional) - units for altitude, ft, m, or km (default is ft) temp_units - (optional) - units for temperature, C, F, K or R (default is deg C) The function replicates Lycoming curve 12700-A, and is valid at mixture for maximum power. Examples: Determine power at 2620 rpm, 28 inches HG manifold pressure, 0 ft, and -10 deg C: >>> pwr(2620, 28, 0, -10) 197.71751932574702 Determine power at 2500 rpm, 25" MP, 5000 ft and 0 deg F: >>> pwr(2500, 25, 5000, 0, temp_units = 'F') 171.87810350172663 Determine power at 2200 rpm, 20" MP, 2000 metres and -5 deg C >>> pwr(2200, 20, 2000, -5, alt_units = 'm') 108.60284092217333 Determine power at 2200 rpm, 20" MP, 2000 metres and standard temperature: >>> pwr(2200, 20, 2000, alt_units = 'm') 107.2124765533882 """ # convert units altitude = U.length_conv(altitude, from_units = alt_units, to_units = 'ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units = temp_units) temp = U.temp_conv(temp, from_units = temp_units, to_units = 'K') # get standard temperature temp_std = SA.alt2temp(altitude, temp_units = 'K') # get power at standard temperature pwr_std = _pwr_std_temp(rpm, MP, altitude) # correct power for non-standard temperature pwr = pwr_std * M.sqrt(temp_std / temp) return pwr
def pwr(rpm, MP, altitude, temp = 'std', alt_units = 'ft', temp_units = 'C'): """ Returns horsepower for Lycoming O-360-A series engines, given: rpm - engine speed in revolutions per minute MP - manifold pressure (" HG) altitude - pressure altitude temp - ambient temperature (optional - std temperature is used if no temperature is input). alt_units - (optional) - units for altitude, ft, m, or km (default is ft) temp_units - (optional) - units for temperature, C, F, K or R (default is deg C) The function replicates Lycoming curve ??????? and is valid at mixture for maximum power. Examples: Determine power at 2620 rpm, 28 inches HG manifold pressure, 0 ft, and -10 deg C: >>> pwr(2620, 28, 0, -10) 183.91485642478889 Determine power at 2500 rpm, 25" MP, 5000 ft and 0 deg F: >>> pwr(2500, 25, 5000, 0, temp_units = 'F') 164.10572738791328 Determine power at 2200 rpm, 20" MP, 2000 metres and -5 deg C >>> pwr(2200, 20, 2000, -5, alt_units = 'm') 111.72954664842844 Determine power at 2200 rpm, 20" MP, 2000 metres and standard temperature: >>> pwr(2200, 20, 2000, alt_units = 'm') 110.29915330621547 """ # convert units altitude = U.length_conv(altitude, from_units = alt_units, to_units = 'ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units = temp_units) temp = U.temp_conv(temp, from_units = temp_units, to_units = 'K') # get standard temperature temp_std = SA.alt2temp(altitude, temp_units = 'K') # get power at standard temperature pwr_std = _pwr_std_temp(rpm, MP, altitude) # correct power for non-standard temperature pwr = pwr_std * M.sqrt(temp_std / temp) return pwr
def pwr(rpm, MP, altitude, temp='std', alt_units='ft', temp_units='C'): """ Returns horsepower for Lycoming IO-360-A series engines, given: rpm - engine speed in revolutions per minute MP - manifold pressure (" HG) altitude - pressure altitude temp - ambient temperature (optional - std temperature is used if no temperature is input). alt_units - (optional) - units for altitude, ft, m, or km (default is ft) temp_units - (optional) - units for temperature, C, F, K or R (default is deg C) The function replicates Lycoming curve 12700-A, and is valid at mixture for maximum power. Examples: Determine power at 2620 rpm, 28 inches HG manifold pressure, 0 ft, and -10 deg C: >>> pwr(2620, 28, 0, -10) 197.71751932574702 Determine power at 2500 rpm, 25" MP, 5000 ft and 0 deg F: >>> pwr(2500, 25, 5000, 0, temp_units = 'F') 171.87810350172663 Determine power at 2200 rpm, 20" MP, 2000 metres and -5 deg C >>> pwr(2200, 20, 2000, -5, alt_units = 'm') 108.60284092217333 Determine power at 2200 rpm, 20" MP, 2000 metres and standard temperature: >>> pwr(2200, 20, 2000, alt_units = 'm') 107.2124765533882 """ # convert units altitude = U.length_conv(altitude, from_units=alt_units, to_units='ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units=temp_units) temp = U.temp_conv(temp, from_units=temp_units, to_units='K') # get standard temperature temp_std = SA.alt2temp(altitude, temp_units='K') # get power at standard temperature pwr_std = _pwr_std_temp(rpm, MP, altitude) # correct power for non-standard temperature pwr = pwr_std * M.sqrt(temp_std / temp) return pwr
def pwr(rpm, MP, altitude, temp='std', alt_units='ft', temp_units='C'): """ Returns horsepower for Lycoming O-360-A series engines, given: rpm - engine speed in revolutions per minute MP - manifold pressure (" HG) altitude - pressure altitude temp - ambient temperature (optional - std temperature is used if no temperature is input). alt_units - (optional) - units for altitude, ft, m, or km (default is ft) temp_units - (optional) - units for temperature, C, F, K or R (default is deg C) The function replicates Lycoming curve ??????? and is valid at mixture for maximum power. Examples: Determine power at 2620 rpm, 28 inches HG manifold pressure, 0 ft, and -10 deg C: >>> pwr(2620, 28, 0, -10) 183.91485642478889 Determine power at 2500 rpm, 25" MP, 5000 ft and 0 deg F: >>> pwr(2500, 25, 5000, 0, temp_units = 'F') 164.10572738791328 Determine power at 2200 rpm, 20" MP, 2000 metres and -5 deg C >>> pwr(2200, 20, 2000, -5, alt_units = 'm') 111.72954664842844 Determine power at 2200 rpm, 20" MP, 2000 metres and standard temperature: >>> pwr(2200, 20, 2000, alt_units = 'm') 110.29915330621547 """ # convert units altitude = U.length_conv(altitude, from_units=alt_units, to_units='ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units=temp_units) temp = U.temp_conv(temp, from_units=temp_units, to_units='K') # get standard temperature temp_std = SA.alt2temp(altitude, temp_units='K') # get power at standard temperature pwr_std = _pwr_std_temp(rpm, MP, altitude) # correct power for non-standard temperature pwr = pwr_std * np.sqrt(temp_std / temp) return pwr
def alt2press_ratio(H, alt_units=default_alt_units): """ Return the pressure ratio (atmospheric pressure / standard pressure for sea level). The altitude is specified in feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'). If the units are not specified, the units in default_units.py are used. Examples: Calculate the pressure ratio at 5000 (default altitude units): >>> alt2press_ratio(5000) 0.8320481158727735 Calculate the pressure ratio at 1000 m: >>> alt2press_ratio(1000, alt_units = 'm') 0.8869930463888704 The functions are only implemented at altitudes of 84.852 km and lower. >>> alt2press_ratio(90, alt_units = 'km') Traceback (most recent call last): File \"<stdin>\", line 1, in <module> File \"std_atm.py\", line 461, in alt2press_ratio 'This function is only implemented for altitudes of 84.852 km and below.' ValueError: This function is only implemented for altitudes of 84.852 km and below. """ # uses meters and degrees K for the internal calculations # function tested in tests/test_std_atm.py H = U.length_conv(H, from_units=alt_units, to_units='km') if H <= 11: return _alt2press_ratio_gradient(H, 0, P0, T0, L0) if H <= 20: return _alt2press_ratio_isothermal(H, 11, P11, T11) if H <= 32: return _alt2press_ratio_gradient(H, 20, P20, T20, L20) if H <= 47: return _alt2press_ratio_gradient(H, 32, P32, T32, L32) if H <= 51: return _alt2press_ratio_isothermal(H, 47, P47, T47) if H <= 71: return _alt2press_ratio_gradient(H, 51, P51, T51, L51) if H <= 84.852: return _alt2press_ratio_gradient(H, 71, P71, T71, L71) else: raise ValueError( 'This function is only implemented for altitudes of 84.852 km and below.' )
def density2alt(Rho, density_units=default_density_units, alt_units=default_alt_units): """ Return the altitude corresponding to the specified density, with density in 'lb/ft**3', 'slug/ft**3' or 'kg/m**3'. The altitude is specified in feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'). If the units are not specified, the units in default_units.py are used. Examples: Calculate the altitude in default altitude units where the density is 0.056475 in default density units: >>> density2alt(.056475) 9999.804093493727 Calculate the altitude in metres where the density is 0.018012 kg / m cubed: >>> density2alt(.018012, alt_units = 'm', density_units = 'kg/m**3') 29999.978688508152 """ # function tested in tests/test_std_atm.py Rho = U.density_conv(Rho, from_units=density_units, to_units='kg/m**3') if Rho > Rho11: H = _density2alt_gradient(Rho, Rho0, 0, T0, L0) elif Rho > Rho20: H = _density2alt_isothermal(Rho, Rho11, 11, T11) elif Rho > Rho32: H = _density2alt_gradient(Rho, Rho20, 20, T20, L20) elif Rho > Rho47: H = _density2alt_gradient(Rho, Rho32, 32, T32, L32) elif Rho > Rho51: H = _density2alt_isothermal(Rho, Rho47, 47, T47) elif Rho > Rho71: H = _density2alt_gradient(Rho, Rho51, 51, T51, L51) else: H = _density2alt_gradient(Rho, Rho71, 71, T71, L71) if H > 84.852: raise ValueError( 'This function is only implemented for altitudes of 84.852 km and below.' ) return U.length_conv(H, from_units='km', to_units=alt_units)
def alt2press_ratio(H, alt_units=default_alt_units): """ Return the pressure ratio (atmospheric pressure / standard pressure for sea level). The altitude is specified in feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'). If the units are not specified, the units in default_units.py are used. Examples: Calculate the pressure ratio at 5000 (default altitude units): >>> alt2press_ratio(5000) 0.8320481158727735 Calculate the pressure ratio at 1000 m: >>> alt2press_ratio(1000, alt_units = 'm') 0.88699304638887044 The functions are only implemented at altitudes of 84.852 km and lower. >>> alt2press_ratio(90, alt_units = 'km') Traceback (most recent call last): File \"<stdin>\", line 1, in <module> File \"std_atm.py\", line 461, in alt2press_ratio 'This function is only implemented for altitudes of 84.852 km and below.' ValueError: This function is only implemented for altitudes of 84.852 km and below. """ # uses meters and degrees K for the internal calculations # function tested in tests/test_std_atm.py H = U.length_conv(H, from_units=alt_units, to_units='km') if H <= 11: return _alt2press_ratio_gradient(H, 0, P0, T0, L0) if H <= 20: return _alt2press_ratio_isothermal(H, 11, P11, T11) if H <= 32: return _alt2press_ratio_gradient(H, 20, P20, T20, L20) if H <= 47: return _alt2press_ratio_gradient(H, 32, P32, T32, L32) if H <= 51: return _alt2press_ratio_isothermal(H, 47, P47, T47) if H <= 71: return _alt2press_ratio_gradient(H, 51, P51, T51, L51) if H <= 84.852: return _alt2press_ratio_gradient(H, 71, P71, T71, L71) else: raise ValueError('This function is only implemented for altitudes of 84.852 km and below.')
def density2alt(Rho, density_units=default_density_units, alt_units=default_alt_units): """ Return the altitude corresponding to the specified density, with density in 'lb/ft**3', 'slug/ft**3' or 'kg/m**3'. The altitude is specified in feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'). If the units are not specified, the units in default_units.py are used. Examples: Calculate the altitude in default altitude units where the density is 0.056475 in default density units: >>> density2alt(.056475) 9999.8040934937271 Calculate the altitude in metres where the density is 0.018012 kg / m cubed: >>> density2alt(.018012, alt_units = 'm', density_units = 'kg/m**3') 29999.978688508152 """ # function tested in tests/test_std_atm.py Rho = U.density_conv(Rho, from_units=density_units, to_units='kg/m**3') if Rho > Rho11: H = _density2alt_gradient(Rho, Rho0, 0, T0, L0) elif Rho > Rho20: H = _density2alt_isothermal(Rho, Rho11, 11, T11) elif Rho > Rho32: H = _density2alt_gradient(Rho, Rho20, 20, T20, L20) elif Rho > Rho47: H = _density2alt_gradient(Rho, Rho32, 32, T32, L32) elif Rho > Rho51: H = _density2alt_isothermal(Rho, Rho47, 47, T47) elif Rho > Rho71: H = _density2alt_gradient(Rho, Rho51, 51, T51, L51) else: H = _density2alt_gradient(Rho, Rho71, 71, T71, L71) if H > 84.852: raise ValueError('This function is only implemented for altitudes of 84.852 km and below.') return U.length_conv(H, from_units='km', to_units=alt_units)
def pp(rpm, MP, altitude, temp = 'std', alt_units = 'ft', temp_units = 'C'): """ Returns percent power for Lycoming IO-360-A series engines, given: rpm - engine speed in revolutions per minute MP - manifold pressure (" HG) altitude - pressure altitude temp - ambient temperature (optional - std temperature is used if no temperature is input). alt_units - (optional) - units for altitude, ft, m, or km (default is ft) temp_units - (optional) - units for temperature, C, F, K or R (default is deg C) The function replicates Lycoming curve 12700-A, and is valid at mixture for maximum power. Note: the output is rounded off to two decimal places. Examples: Determine power at 2620 rpm, 28 inches HG manifold pressure, 0 ft, and -10 deg C: >>> pp(2620, 28, 0, -10) '98.86%' Determine power at 2500 rpm, 25" MP, 5000 ft and 0 deg F: >>> pp(2500, 25, 5000, 0, temp_units = 'F') '85.94%' Determine power at 2200 rpm, 20" MP, 2000 metres and -5 deg C >>> pp(2200, 20, 2000, -5, alt_units = 'm') '54.30%' Determine power at 2200 rpm, 20" MP, 2000 metres and standard temperature: >>> pp(2200, 20, 2000, alt_units = 'm') '53.61%' """ altitude = U.length_conv(altitude, from_units = alt_units, to_units = 'ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units = temp_units) temp = U.temp_conv(temp, from_units = temp_units, to_units = 'C') pp = pwr(rpm, MP, altitude, temp) / 2 # return pp return '%.2f' % (pp) + '%'
def pp(rpm, MP, altitude, temp='std', alt_units='ft', temp_units='C'): """ Returns percent power for Lycoming IO-360-A series engines, given: rpm - engine speed in revolutions per minute MP - manifold pressure (" HG) altitude - pressure altitude temp - ambient temperature (optional - std temperature is used if no temperature is input). alt_units - (optional) - units for altitude, ft, m, or km (default is ft) temp_units - (optional) - units for temperature, C, F, K or R (default is deg C) The function replicates Lycoming curve 12700-A, and is valid at mixture for maximum power. Note: the output is rounded off to two decimal places. Examples: Determine power at 2620 rpm, 28 inches HG manifold pressure, 0 ft, and -10 deg C: >>> pp(2620, 28, 0, -10) '98.86%' Determine power at 2500 rpm, 25" MP, 5000 ft and 0 deg F: >>> pp(2500, 25, 5000, 0, temp_units = 'F') '85.94%' Determine power at 2200 rpm, 20" MP, 2000 metres and -5 deg C >>> pp(2200, 20, 2000, -5, alt_units = 'm') '54.30%' Determine power at 2200 rpm, 20" MP, 2000 metres and standard temperature: >>> pp(2200, 20, 2000, alt_units = 'm') '53.61%' """ altitude = U.length_conv(altitude, from_units=alt_units, to_units='ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units=temp_units) temp = U.temp_conv(temp, from_units=temp_units, to_units='C') pp = pwr(rpm, MP, altitude, temp) / 2 # return pp return '%.2f' % (pp) + '%'
def Re(V, L, KV, speed_units=default_speed_units, length_units=default_length_units, #kinematic_viscosity_units=default_kinematic_viscosity_units ): """ Return Reynold's number, given velocity, characteristic length and kinematic viscosity' V = velocity L = characteristic length KV = kinematic viscosity """ V = U.speed_conv(V, speed_units, 'm/s') L = U.length_conv(L, length_units, 'm') # KV = U.kinematic_viscosity_conv(KV, kinematic_viscosity_units, '??') Re = V * L / KV return Re
def pp2mp(percent_power, rpm, altitude, temp='std', alt_units='ft', temp_units='C'): """ Returns manifold pressure in inches of mercury for a given percent power, rpm, altitude and temperature (temperature input is optional - standard temperature is used if no temperature is input). Note: the output is rounded off to two decimal places. Examples: Determine manifold pressure required for 62.5% power at 2550 rpm at 8000 ft and 10 deg C: >>> pp2mp(62.5, 2550, 8000, 10) '19.45' Determine manifold pressure required for 75% power at 2500 rpm at 7500 ft at 10 deg F: >>> pp2mp(75, 2500, 7500, 10, temp_units = 'F') '22.25' Determine manifold pressure required for 55% power at 2400 rpm at 9,500 ft at standard temperature: >>> pp2mp(55, 2400, 9500) '18.18' """ if percent_power <= 0: raise ValueError('Power input must be positive.') # convert units altitude = U.length_conv(altitude, from_units=alt_units, to_units='ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units=temp_units) temp = U.temp_conv(temp, from_units=temp_units, to_units='C') pwr_seek = percent_power * 2 mp = pwr2mp(pwr_seek, rpm, altitude, temp) return mp
def advance_ratio(tas, rpm, dia, speed_units='kt', dia_units='in'): """ Returns the propeller advance ratio, J, given the revolutions per minute (rpm), true airspeed (tas), temperature and propeller diameter. The advance ratio is the forward distance that the propeller advances during one revolution, divided by the diameter of the propeller. The diameter units may be specified as "in", "ft", or "m", but default to inches if not specified. """ tas = U.speed_conv(tas, from_units=speed_units, to_units='m/s') dia = U.length_conv(dia, from_units=dia_units, to_units='m') advance_ratio = tas * 60. / (rpm * dia) return advance_ratio
def ct2thrust(Ct, Rho, rpm, dia, thrust_units='lb', density_units='lb/ft**3', dia_units='in'): """ Returns the thrust, given thrust coefficient, Ct, density, rpm and prop diameter. """ Rho = U.density_conv(Rho, from_units=density_units, to_units='kg/m**3') dia = U.length_conv(dia, from_units=dia_units, to_units='m') # convert rpm to revolutions / s n = rpm / 60. thrust = Ct * Rho * n**2. * dia**4. return U.force_conv(thrust, from_units='N', to_units=thrust_units)
def advance_ratio(tas, rpm, dia, speed_units="kt", dia_units="in"): """ Returns the propeller advance ratio, J, given the revolutions per minute (rpm), true airspeed (tas), temperature and propeller diameter. The advance ratio is the forward distance that the propeller advances during one revolution, divided by the diameter of the propeller. The diameter units may be specified as "in", "ft", or "m", but default to inches if not specified. """ tas = U.speed_conv(tas, from_units=speed_units, to_units="m/s") dia = U.length_conv(dia, from_units=dia_units, to_units="m") advance_ratio = tas * 60.0 / (rpm * dia) return advance_ratio
def pp2rpm(percent_power, mp, altitude, temp='std', alt_units='ft', temp_units='C'): """ Returns manifold pressure in inches of mercury for a given percent power, rpm, altitude and temperature (temperature input is optional - standard temperature is used if no temperature is input). Examples: Determine rpm required for 125 hp at 20 inches HG manifold pressure at 8000 ft and 10 deg C: >>> pp2rpm(62.5, 20, 8000, 10) 2246 Determine rpm required for 75% power at 22 inches HG manifold pressure at 6500 ft and 10 deg F: >>> pp2rpm(75, 22, 6500, 10, temp_units = 'F') 2345 Determine rpm required for 55% power at at 18 inches HG manifold pressure at 9,500 ft at standard temperature: >>> pp2rpm(55, 18, 9500) 2423 """ if percent_power <= 0: raise ValueError('Power input must be positive.') # convert units altitude = U.length_conv(altitude, from_units=alt_units, to_units='ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units=temp_units) temp = U.temp_conv(temp, from_units=temp_units, to_units='C') pwr_seek = percent_power * 1.8 # print('Temp:', temp) print('Power seeked:', pwr_seek) rpm = pwr2rpm(pwr_seek, mp, altitude, temp) return rpm
def bhp2Cp(bhp, rpm, density, dia, power_units="hp", density_units="lb/ft**3", dia_units="in"): """ Returns the propeller power coefficient, Cp, given power, revolutions per minute (rpm), and propeller diameter. The power units may be specified as "hp", "ft-lb/mn", "ft-lb/s", "W" (watts) or "kW" (kilowatts), but default to "hp" if not specified. The density units may be specified as "lb/ft**3", "slug/ft**3" or "kg/m**3", but default to "lb/ft**3" if not specified. The diameter units may be specified as "in", "ft", or "m", but default to inches if not specified. """ bhp = U.power_conv(bhp, from_units=power_units, to_units="W") density = U.density_conv(density, from_units=density_units, to_units="kg/m**3") dia = U.length_conv(dia, from_units=dia_units, to_units="m") Cp = bhp / (density * ((rpm / 60.0) ** 3) * dia ** 5) return Cp
def pp2mp(percent_power, rpm, altitude, temp = 'std', alt_units = 'ft', temp_units = 'C'): """ Returns manifold pressure in inches of mercury for a given percent power, rpm, altitude and temperature (temperature input is optional - standard temperature is used if no temperature is input). Note: the output is rounded off to two decimal places. Examples: Determine manifold pressure required for 62.5% power at 2550 rpm at 8000 ft and 10 deg C: >>> pp2mp(62.5, 2550, 8000, 10) '19.45' Determine manifold pressure required for 75% power at 2500 rpm at 7500 ft at 10 deg F: >>> pp2mp(75, 2500, 7500, 10, temp_units = 'F') '22.25' Determine manifold pressure required for 55% power at 2400 rpm at 9,500 ft at standard temperature: >>> pp2mp(55, 2400, 9500) '18.18' """ if percent_power <= 0: raise ValueError, 'Power input must be positive.' # convert units altitude = U.length_conv(altitude, from_units = alt_units, to_units = 'ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units = temp_units) temp = U.temp_conv(temp, from_units = temp_units, to_units = 'C') pwr_seek = percent_power * 2 mp = pwr2mp(pwr_seek, rpm, altitude, temp) return mp
def Re( V, L, KV, speed_units=default_speed_units, length_units=default_length_units, #kinematic_viscosity_units=default_kinematic_viscosity_units ): """ Return Reynold's number, given velocity, characteristic length and kinematic viscosity' V = velocity L = characteristic length KV = kinematic viscosity """ V = U.speed_conv(V, speed_units, 'm/s') L = U.length_conv(L, length_units, 'm') # KV = U.kinematic_viscosity_conv(KV, kinematic_viscosity_units, '??') Re = V * L / KV return Re
def pp2rpm(percent_power, mp, altitude, temp = 'std', alt_units = 'ft', temp_units = 'C'): """ Returns manifold pressure in inches of mercury for a given percent power, rpm, altitude and temperature (temperature input is optional - standard temperature is used if no temperature is input). Examples: Determine rpm required for 125 hp at 20 inches HG manifold pressure at 8000 ft and 10 deg C: >>> pp2rpm(62.5, 20, 8000, 10) 2246 Determine rpm required for 75% power at 22 inches HG manifold pressure at 6500 ft and 10 deg F: >>> pp2rpm(75, 22, 6500, 10, temp_units = 'F') 2345 Determine rpm required for 55% power at at 18 inches HG manifold pressure at 9,500 ft at standard temperature: >>> pp2rpm(55, 18, 9500) 2423 """ if percent_power <= 0: raise ValueError, 'Power input must be positive.' # convert units altitude = U.length_conv(altitude, from_units = alt_units, to_units = 'ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units = temp_units) temp = U.temp_conv(temp, from_units = temp_units, to_units = 'C') pwr_seek = percent_power * 1.8 # print 'Temp:', temp print 'Power seeked:', pwr_seek rpm = pwr2rpm(pwr_seek, mp, altitude, temp) return rpm
def alt2press(H, alt_units=default_alt_units, press_units=default_press_units): """ Return the atmospheric pressure for a given altitude, with the altitude in feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'), and the pressure in inches of HG ('in HG'), mm of HG ('mm HG'), psi, lb per sq. ft ('psf'), pa, hpa or mb. If the units are not specified, the units in default_units.py are used. Examples: Calculate the pressure in inches of mercury at 5,000 (default altitude units): >>> alt2press(5000) 24.895987851572702 Calculate the pressure in pounds per square foot at 10,000 (default altitude units): >>> alt2press(10000, press_units = 'psf') 1455.331692025379 Calculate the pressure in pascal at 20 km: >>> alt2press(20, press_units = 'pa', alt_units = 'km') 5474.8885557436233 """ # uses meters, pa and degrees K for the internal calculations # function tested in tests/test_std_atm.py H = U.length_conv(H, from_units=alt_units, to_units='m') press = P0 * alt2press_ratio(H, alt_units='m') press = U.press_conv(press, from_units='pa', to_units=press_units) return press
def tip_mach(tas, rpm, temperature, dia, speed_units="kt", temp_units="C", dia_units="in"): """ Returns the mach number of the propeller blade tip, given the true airspeed (tas), revolutions per minute (rpm), temperature and propeller diameter. The speed units may be specified as "kt", "mph", "km/h" or "ft/s", but default to "kt" if not specified. The temperature units may be specified as "C", "F", "K" or "R", but default to deg C if not specified. The diameter units may be specified as "in", "ft", or "m", but default to inches if not specified. """ dia = U.length_conv(dia, from_units=dia_units, to_units="m") tas = U.speed_conv(tas, from_units=speed_units, to_units="m/s") speed_of_sound = SA.temp2speed_of_sound(temperature, temp_units=temp_units, speed_units="m/s") rotation_speed = dia * rpm * M.pi / 60 tip_speed = M.sqrt(tas ** 2 + rotation_speed ** 2) tip_mach = tip_speed / speed_of_sound return tip_mach
def alt2press(H, alt_units=default_alt_units, press_units=default_press_units): """ Return the atmospheric pressure for a given altitude, with the altitude in feet ('ft'), metres ('m'), statute miles, ('sm') or nautical miles ('nm'), and the pressure in inches of HG ('in HG'), mm of HG ('mm HG'), psi, lb per sq. ft ('psf'), pa, hpa or mb. If the units are not specified, the units in default_units.py are used. Examples: Calculate the pressure in inches of mercury at 5,000 (default altitude units): >>> alt2press(5000) 24.895987851572702 Calculate the pressure in pounds per square foot at 10,000 (default altitude units): >>> alt2press(10000, press_units = 'psf') 1455.331692025379 Calculate the pressure in pascal at 20 km: >>> alt2press(20, press_units = 'pa', alt_units = 'km') 5474.888555743623 """ # uses meters, pa and degrees K for the internal calculations # function tested in tests/test_std_atm.py H = U.length_conv(H, from_units=alt_units, to_units='m') press = P0 * alt2press_ratio(H, alt_units='m') press = U.press_conv(press, from_units='pa', to_units=press_units) return press
def test_01(self): Value = U.length_conv(120, from_units='in', to_units='ft') Truth = 10 self.assertTrue(RE(Value, Truth) <= 1e-5)
def pwr2rpm(pwr_seek, mp, altitude, temp = 'std', alt_units = 'ft', temp_units = 'C'): """ Returns rpm for a given power, manifold pressure in inches of mercury, altitude and temperature (temperature input is optional - standard temperature is used if no temperature is input). Note: the output is rounded off to the nearest rpm. Examples: Determine rpm required for 125 hp at 20 inches HG manifold pressure at 8000 ft and 10 deg C: >>> pwr2rpm(125, 20, 8000, 10) 2477 Determine rpm required for 75% power at 22 inches HG manifold pressure at 6500 ft and 10 deg F: >>> pwr2rpm(.75 * 200, 22, 6500, 10, temp_units = 'F') 2547 Determine rpm required for 55% power at at 18 inches HG manifold pressure at 9,500 ft at standard temperature: >>> pwr2rpm(.55 * 200, 18, 9500) 2423 """ if pwr_seek <= 0: raise ValueError, 'Power input must be positive.' low = 1000 # initial lower guess high = 3500 # initial upper guess # convert units altitude = U.length_conv(altitude, from_units = alt_units, to_units = 'ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units = temp_units) temp = U.temp_conv(temp, from_units = temp_units, to_units = 'C') # confirm initial low and high are OK: pwr_low = pwr(low, mp, altitude, temp) # print "pwr_low=", pwr_low if pwr_low > pwr_seek: raise ValueError, 'Initial low guess too high.' pwr_high = pwr(high, mp, altitude, temp) # print "pwr_high=", pwr_high if pwr_high < pwr_seek: # print "pwr_high=", pwr_high print "Function called was IO.pwr(%f, %f, %f, %f)" % (high, mp, altitude, temp) raise ValueError, 'Initial high guess too low.' guess = (low + high) / 2. pwr_guess = pwr(guess, mp, altitude, temp) # keep iterating until power is within 0.1% of desired value while M.fabs(pwr_guess - pwr_seek) / pwr_seek > 1e-4: if pwr_guess > pwr_seek: high = guess else: low = guess guess = (low + high) / 2. pwr_guess = pwr(guess, mp, altitude, temp) return int(round(guess,0))
def __init__(self, base_name, base_path=''): """Returns a propeller object prop = Prop('7666-2RV') prop = Prop('MTV*183-59B') prop = Prop('MTV*402') """ self.prop = base_name # create temp lists, to hold the data before it is read into arrays temp_data_storage1 = [] temp_data_storage2 = [] temp_data_storage3 = [] if '7666' in base_name: self.manufacturer = 'Hartzell' self.model = base_name if base_path == '': node_name = node() if node_name[:9] == 'PowerBook': base_path = '/Users/kwh/RV/Engine_prop/Hartzell_prop_maps/' elif node_name == 'Kevins-MacBook-Air.local': base_path = '/Users/kwh/Documents/RV/Engine_prop/Hartzell_prop_maps/' elif node_name == 'Kevins-MBPr.local': base_path = '/Users/kwh/Documents/RV/Engine_prop/Hartzell_prop_maps/' elif node_name == 'MacMini.local': base_path = '/Users/kwh/Documents/Flying/RV/Engine_prop/Hartzell_prop_maps/' elif node_name == 'ncrnbhortonk2': base_path = 'C:\\Documents and Settings\\hortonk\\My Documents\\rv\\Prop\\Hartzell_prop_maps\\' elif node_name == 'eeepc': base_path = '/home/kwh/RV/Hartzell_prop_maps/' elif node_name == 'sage-BHYVE': base_path = '/home/kwh/Prop_Maps/Hartzell_prop_maps/' elif node_name == 'sage-ubuntu-1404': base_path = '/home/kwh/python/prop_maps/Hartzell_prop_maps/' else: raise ValueError('Unknown computer') # confirm the path to the data files exists if os.path.exists(base_path): pass else: raise ValueError( 'The path specified for the prop map files does not exist') file_glob = base_path + base_name + '*.csv' file_names = glob.glob(file_glob) # confirm that at least one data file was found if len(file_names) < 1: raise ValueError('No prop data files were found.') # need names in sorted order, so the array ends up in order of mach # sorting seems to not be needed on OS X, as glob.glob() returns a sorted list # but, on Linux, the list is not sorted file_names.sort() for file_name in file_names: FILE = open(file_name) raw_data = csv.reader(FILE) # parse mach number for line in raw_data: mach_search = re.search('Mach\s0\.\d+', line[0]) if mach_search: mach_group = re.search('0\.\d+', line[0]) mach = mach_group.group() break # find start of CT data for line in raw_data: try: header_search = re.search('THRUST COEFFICIENT', line[0]) if header_search: break except IndexError: pass # load block of CT values into temp storage temp_lines1 = [] while 1: value_line = next(raw_data) try: value_line_search = re.match('[0\.\d+,CP]', value_line[0]) except IndexError: # at the end of the data block - move on break if value_line_search: # strip spurious zeros from right end of data while value_line[-1] == '0': value_line.pop() temp_lines1.append(value_line) # convert values to float for i, item in enumerate(value_line): try: value_line[i] = float(item) except ValueError: value_line[i] = 0 else: # at the end of the data block - move on break # strip of "CP / J" from first line, and replace by mach, temp_lines1[0][0] = float(mach) # find start of blade angle data for line in raw_data: try: header_search = re.search('BLADE ANGLE', line[0]) if header_search: break except IndexError: pass # load block of blade angle values into temp storage temp_lines3 = [] while 1: try: value_line = next(raw_data) except StopIteration: break try: value_line_search = re.match('[0\.\d+,CP]', value_line[0]) except IndexError: # at the end of the data block - move on break if value_line_search: # strip spurious zeros from right end of data while value_line[-1] == '0': value_line.pop() temp_lines3.append(value_line) # convert values to float for i, item in enumerate(value_line): try: value_line[i] = float(item) except ValueError: value_line[i] = 0 else: # at the end of the data block - move on break # strip of "CP / J" from first line, and replace by mach, temp_lines3[0][0] = float(mach) # find start of efficiency data for line in raw_data: try: header_search = re.search('EFFICIENCY', line[0]) if header_search: break except IndexError: pass # load block of efficiency values into temp storage temp_lines2 = [] while 1: try: value_line = next(raw_data) except StopIteration: break try: value_line_search = re.match('[0\.\d+,CP]', value_line[0]) except IndexError: # at the end of the data block - move on break if value_line_search: # strip spurious zeros from right end of data while value_line[-1] == '0': value_line.pop() temp_lines2.append(value_line) # convert values to float for i, item in enumerate(value_line): try: value_line[i] = float(item) except ValueError: value_line[i] = 0 else: # at the end of the data block - move on break # strip of "CP / J" from first line, and replace by mach, temp_lines2[0][0] = float(mach) # determine required size for array # this is done once for each data file, but only the last result is used self.x_size = len(temp_lines1[0]) self.y_size = len(temp_lines1) self.z_size = len(file_names) # push data blocks into temp storage temp_data_storage1.append(temp_lines1) temp_data_storage2.append(temp_lines2) temp_data_storage3.append(temp_lines3) # create array for CT data, and populate it self.prop_CT_map = N.zeros((self.z_size, self.y_size, self.x_size)) # trim length of temp data to be sure it will fit in array for i, layer in enumerate(temp_data_storage1): for i, line in enumerate(layer): while len(line) > self.x_size: if line[-1] == 0: line.pop(-1) else: print('Problem line =', line) raise ValueError( 'Problem - Trying to remove real data from end of line' ) for i, item in enumerate(temp_data_storage1): self.prop_CT_map[i] = temp_data_storage1[i] # determine range of mach, advance ratio and power coefficient in the CT data self.Ct_mach_min = min(self.prop_CT_map[:, 0, 0]) self.Ct_mach_max = max(self.prop_CT_map[:, 0, 0]) self.Ct_Cp_min = min(self.prop_CT_map[0, 1:, 0]) self.Ct_Cp_max = max(self.prop_CT_map[0, 1:, 0]) self.Ct_J_min = min(self.prop_CT_map[0, 0, :]) self.Ct_J_max = max(self.prop_CT_map[0, 0, :]) # create array for blade angle data, and populate it self.blade_angle_map = N.zeros( (self.z_size, self.y_size, self.x_size)) # trim length of temp data to be sure it will fit in array for i, layer in enumerate(temp_data_storage3): for i, line in enumerate(layer): while len(line) > self.x_size: if line[-1] == 0: line.pop(-1) else: raise ValueError( 'Problem - Trying to remove real data from end of line' ) for i, item in enumerate(temp_data_storage1): self.blade_angle_map[i] = temp_data_storage3[i] # determine range of mach, advance ratio and power coefficient in the blade angle data self.blade_angle_mach_min = min(self.blade_angle_map[:, 0, 0]) self.blade_angle_mach_max = max(self.blade_angle_map[:, 0, 0]) self.blade_angle_Cp_min = min(self.blade_angle_map[0, 1:, 0]) self.blade_angle_Cp_max = max(self.blade_angle_map[0, 1:, 0]) self.blade_angle_J_min = min(self.blade_angle_map[0, 0, :]) self.blade_angle_J_max = max(self.blade_angle_map[0, 0, :]) # create array for efficiency data, and populate it self.prop_eff_map = N.zeros( (self.z_size, self.y_size, self.x_size)) # trim length of temp data to be sure it will fit in array for i, layer in enumerate(temp_data_storage2): for i, line in enumerate(layer): while len(line) > self.x_size: if line[-1] == 0: line.pop(-1) else: raise ValueError( 'Problem - Trying to remove real data from end of line' ) for i, item in enumerate(temp_data_storage1): self.prop_eff_map[i] = temp_data_storage2[i] # determine range of mach, advance ratio and power coefficient in the efficiency data self.eff_mach_min = min(self.prop_eff_map[:, 0, 0]) self.eff_mach_max = max(self.prop_eff_map[:, 0, 0]) self.eff_Cp_min = min(self.prop_eff_map[0, 1:, 0]) self.eff_Cp_max = max(self.prop_eff_map[0, 1:, 0]) self.eff_J_min = min(self.prop_eff_map[0, 0, :]) self.eff_J_max = max(self.prop_eff_map[0, 0, :]) # wipe temp storage, to be sure to start with a clean slate for the next type of data temp_data_storage1 = [] temp_data_storage2 = [] temp_data_storage3 = [] if base_name == '7666-4RV': self.dia = 72 elif base_name == '7666-2RV': self.dia = 74 else: raise ValueError('Invalid prop') elif 'MTV' in base_name: if base_path == '': node_name = node() if node_name[:9] == 'PowerBook': base_path = '/Users/kwh/Documents/RV/MT_Prop/' elif node_name == 'Kevins-MacBook-Air.local': base_path = '/Users/kwh/Documents/RV/Engine_prop/MT_Prop/' elif node_name == 'Kevins-MBPr.local': base_path = '/Users/kwh/Documents/RV/Engine_prop/MT_Prop/' elif node_name == 'MacMini.local': base_path = '/Users/kwh/Documents/Flying/RV/Engine_prop/MT_Prop/' elif node_name == 'ncrnbhortonk2': base_path = 'C:\\Documents and Settings\\hortonk\\My Documents\\rv\\Prop\\MT_Prop\\' elif node_name == 'eeepc': base_path = '/home/kwh/RV/MT_Prop/' elif node_name == 'sage-BHYVE': base_path = '/home/kwh/Prop_Maps/MT_Prop/' elif node_name == 'sage-ubuntu-1204': base_path = '/home/kwh/python//prop_maps/' else: raise ValueError('Unknown computer') # confirm the path to the data files exists if os.path.exists(base_path): pass else: raise ValueError( 'The path specified for the prop map files does not exist') file_glob = base_path + base_name + '*.csv' # file_glob = base_path + '*' + base_name + '*.csv' file_names = glob.glob(file_glob) # confirm that at least one data file was found if len(file_names) < 1: raise ValueError('No prop data files were found.') for file_name in file_names: temp_lines = [] FILE = open(file_name) raw_data = csv.reader(FILE) header_lines = 2 line1 = next(raw_data) model_match = re.search('(\S+)\s+(\S+)\s.*', line1[0]) self.manufacturer = model_match.group(1) self.model = model_match.group(2) self.dia = float( re.search('[^-]+-[^-]+-[^-]+-(\d+).*', line1[0]).group(1)) self.dia = U.length_conv(self.dia, from_units='cm', to_units='in') for n in range(header_lines - 1): next(raw_data) #replace "J" with mach 0 temp_lines.append(next(raw_data)) temp_lines[0][0] = 0 # load block of efficiency values into temp storage while 1: try: temp_lines.append(next(raw_data)) except StopIteration: break for l, line in enumerate(temp_lines): for i, item in enumerate(line): try: temp_lines[l][i] = float(item) except ValueError: temp_lines[l][i] = 0. # determine required size for array self.x_size = len(temp_lines[0]) self.y_size = len(temp_lines) self.z_size = 2 temp_array1 = [] for line in temp_lines: temp_array1.append(line) # MT eff map does not have different data for different tip mach numbers. # To allow using the same routines as for Hartzell props, set the original # data for Mach 0, and make a copy for Mach 1. temp_array = [temp_array1, temp_array1] self.prop_eff_map = N.array(temp_array) self.prop_eff_map[1, 0, 0] = 1 # MT eff data has Cp running left to right, and Js running # vertically, which is the reverse of the Hartzell data. # Must swapaxes to get the same orientation for both props. self.prop_eff_map = self.prop_eff_map.swapaxes(1, 2) # determine range of mach, advance ratio and power coefficient in the efficiency data self.eff_mach_min = min(self.prop_eff_map[:, 0, 0]) self.eff_mach_max = max(self.prop_eff_map[:, 0, 0]) self.eff_Cp_min = min(self.prop_eff_map[0, :, 0]) self.eff_Cp_max = max(self.prop_eff_map[0, :, 0]) self.eff_J_min = min(self.prop_eff_map[0, 0, 1:]) self.eff_J_max = max(self.prop_eff_map[0, 0, 1:]) else: print('prop type not known')
def __init__(self, base_name, base_path=""): """Returns a propeller object prop = Prop('7666-2RV') prop = Prop('MTV*183-59B') prop = Prop('MTV*402') """ self.prop = base_name # create temp lists, to hold the data before it is read into arrays temp_data_storage1 = [] temp_data_storage2 = [] temp_data_storage3 = [] if "7666" in base_name: self.manufacturer = "Hartzell" self.model = base_name if base_path == "": node_name = node() if node_name[:9] == "PowerBook": base_path = "/Users/kwh/RV/Engine_prop/Hartzell_prop_maps/" elif node_name == "Kevins-MacBook-Air.local": base_path = "/Users/kwh/Documents/RV/Engine_prop/Hartzell_prop_maps/" elif node_name == "Kevins-MBPr.local": base_path = "/Users/kwh/Documents/RV/Engine_prop/Hartzell_prop_maps/" elif node_name == "MacMini.local": base_path = "/Users/kwh/Documents/Flying/RV/Engine_prop/Hartzell_prop_maps/" elif node_name == "ncrnbhortonk2": base_path = "C:\\Documents and Settings\\hortonk\\My Documents\\rv\\Prop\\Hartzell_prop_maps\\" elif node_name == "eeepc": base_path = "/home/kwh/RV/Hartzell_prop_maps/" elif node_name[:4] == "sage": base_path = "/home/kwh/python/prop_maps/Hartzell_prop_maps/" elif node_name == "sage-ubuntu-1404": base_path = "/home/kwh/python/prop_maps/Hartzell_prop_maps/" else: raise ValueError, "Unknown computer" # confirm the path to the data files exists if os.path.exists(base_path): pass else: raise ValueError, "The path specified for the prop map files does not exist" file_glob = base_path + base_name + "*.csv" file_names = glob.glob(file_glob) # confirm that at least one data file was found if len(file_names) < 1: raise ValueError, "No prop data files were found." # need names in sorted order, so the array ends up in order of mach # sorting seems to not be needed on OS X, as glob.glob() returns a sorted list # but, on Linux, the list is not sorted file_names.sort() for file_name in file_names: FILE = open(file_name) raw_data = csv.reader(FILE) # parse mach number for line in raw_data: mach_search = re.search("Mach\s0\.\d+", line[0]) if mach_search: mach_group = re.search("0\.\d+", line[0]) mach = mach_group.group() break # find start of CT data for line in raw_data: try: header_search = re.search("THRUST COEFFICIENT", line[0]) if header_search: break except IndexError: pass # load block of CT values into temp storage temp_lines1 = [] while 1: value_line = raw_data.next() try: value_line_search = re.match("[0\.\d+,CP]", value_line[0]) except IndexError: # at the end of the data block - move on break if value_line_search: # strip spurious zeros from right end of data while value_line[-1] == "0": value_line.pop() temp_lines1.append(value_line) # convert values to float for i, item in enumerate(value_line): try: value_line[i] = float(item) except ValueError: value_line[i] = 0 else: # at the end of the data block - move on break # strip of "CP / J" from first line, and replace by mach, temp_lines1[0][0] = float(mach) # find start of blade angle data for line in raw_data: try: header_search = re.search("BLADE ANGLE", line[0]) if header_search: break except IndexError: pass # load block of blade angle values into temp storage temp_lines3 = [] while 1: try: value_line = raw_data.next() except StopIteration: break try: value_line_search = re.match("[0\.\d+,CP]", value_line[0]) except IndexError: # at the end of the data block - move on break if value_line_search: # strip spurious zeros from right end of data while value_line[-1] == "0": value_line.pop() temp_lines3.append(value_line) # convert values to float for i, item in enumerate(value_line): try: value_line[i] = float(item) except ValueError: value_line[i] = 0 else: # at the end of the data block - move on break # strip of "CP / J" from first line, and replace by mach, temp_lines3[0][0] = float(mach) # find start of efficiency data for line in raw_data: try: header_search = re.search("EFFICIENCY", line[0]) if header_search: break except IndexError: pass # load block of efficiency values into temp storage temp_lines2 = [] while 1: try: value_line = raw_data.next() except StopIteration: break try: value_line_search = re.match("[0\.\d+,CP]", value_line[0]) except IndexError: # at the end of the data block - move on break if value_line_search: # strip spurious zeros from right end of data while value_line[-1] == "0": value_line.pop() temp_lines2.append(value_line) # convert values to float for i, item in enumerate(value_line): try: value_line[i] = float(item) except ValueError: value_line[i] = 0 else: # at the end of the data block - move on break # strip of "CP / J" from first line, and replace by mach, temp_lines2[0][0] = float(mach) # determine required size for array # this is done once for each data file, but only the last result is used self.x_size = len(temp_lines1[0]) self.y_size = len(temp_lines1) self.z_size = len(file_names) # push data blocks into temp storage temp_data_storage1.append(temp_lines1) temp_data_storage2.append(temp_lines2) temp_data_storage3.append(temp_lines3) # create array for CT data, and populate it self.prop_CT_map = N.zeros((self.z_size, self.y_size, self.x_size)) # trim length of temp data to be sure it will fit in array for i, layer in enumerate(temp_data_storage1): for i, line in enumerate(layer): while len(line) > self.x_size: if line[-1] == 0: line.pop(-1) else: print "Problem line =", line raise ValueError, "Problem - Trying to remove real data from end of line" for i, item in enumerate(temp_data_storage1): self.prop_CT_map[i] = temp_data_storage1[i] # determine range of mach, advance ratio and power coefficient in the CT data self.Ct_mach_min = min(self.prop_CT_map[:, 0, 0]) self.Ct_mach_max = max(self.prop_CT_map[:, 0, 0]) self.Ct_Cp_min = min(self.prop_CT_map[0, 1:, 0]) self.Ct_Cp_max = max(self.prop_CT_map[0, 1:, 0]) self.Ct_J_min = min(self.prop_CT_map[0, 0, :]) self.Ct_J_max = max(self.prop_CT_map[0, 0, :]) # create array for blade angle data, and populate it self.blade_angle_map = N.zeros((self.z_size, self.y_size, self.x_size)) # trim length of temp data to be sure it will fit in array for i, layer in enumerate(temp_data_storage3): for i, line in enumerate(layer): while len(line) > self.x_size: if line[-1] == 0: line.pop(-1) else: raise ValueError, "Problem - Trying to remove real data from end of line" for i, item in enumerate(temp_data_storage1): self.blade_angle_map[i] = temp_data_storage3[i] # determine range of mach, advance ratio and power coefficient in the blade angle data self.blade_angle_mach_min = min(self.blade_angle_map[:, 0, 0]) self.blade_angle_mach_max = max(self.blade_angle_map[:, 0, 0]) self.blade_angle_Cp_min = min(self.blade_angle_map[0, 1:, 0]) self.blade_angle_Cp_max = max(self.blade_angle_map[0, 1:, 0]) self.blade_angle_J_min = min(self.blade_angle_map[0, 0, :]) self.blade_angle_J_max = max(self.blade_angle_map[0, 0, :]) # create array for efficiency data, and populate it self.prop_eff_map = N.zeros((self.z_size, self.y_size, self.x_size)) # trim length of temp data to be sure it will fit in array for i, layer in enumerate(temp_data_storage2): for i, line in enumerate(layer): while len(line) > self.x_size: if line[-1] == 0: line.pop(-1) else: raise ValueError, "Problem - Trying to remove real data from end of line" for i, item in enumerate(temp_data_storage1): self.prop_eff_map[i] = temp_data_storage2[i] # determine range of mach, advance ratio and power coefficient in the efficiency data self.eff_mach_min = min(self.prop_eff_map[:, 0, 0]) self.eff_mach_max = max(self.prop_eff_map[:, 0, 0]) self.eff_Cp_min = min(self.prop_eff_map[0, 1:, 0]) self.eff_Cp_max = max(self.prop_eff_map[0, 1:, 0]) self.eff_J_min = min(self.prop_eff_map[0, 0, :]) self.eff_J_max = max(self.prop_eff_map[0, 0, :]) # wipe temp storage, to be sure to start with a clean slate for the next type of data temp_data_storage1 = [] temp_data_storage2 = [] temp_data_storage3 = [] if base_name == "7666-4RV": self.dia = 72 elif base_name == "7666-2RV": self.dia = 74 else: raise ValueError, "Invalid prop" elif "MTV" in base_name: if base_path == "": node_name = node() if node_name[:9] == "PowerBook": base_path = "/Users/kwh/Documents/RV/MT_Prop/" elif node_name == "Kevins-MacBook-Air.local": base_path = "/Users/kwh/Documents/RV/Engine_prop/MT_Prop/" elif node_name == "Kevins-MBPr.local": base_path = "/Users/kwh/Documents/RV/Engine_prop/MT_Prop/" elif node_name == "MacMini.local": base_path = "/Users/kwh/Documents/Flying/RV/Engine_prop/MT_Prop/" elif node_name == "ncrnbhortonk2": base_path = "C:\\Documents and Settings\\hortonk\\My Documents\\rv\\Prop\\MT_Prop\\" elif node_name == "eeepc": base_path = "/home/kwh/RV/MT_Prop/" elif node_name[:4] == "sage": base_path = "/home/kwh/python/prop_maps/" elif node_name == "sage-ubuntu-1204": base_path = "/home/kwh/python//prop_maps/" else: raise ValueError, "Unknown computer" # confirm the path to the data files exists if os.path.exists(base_path): pass else: raise ValueError, "The path specified for the prop map files does not exist" file_glob = base_path + base_name + "*.csv" # file_glob = base_path + '*' + base_name + '*.csv' file_names = glob.glob(file_glob) # confirm that at least one data file was found if len(file_names) < 1: raise ValueError, "No prop data files were found." for file_name in file_names: temp_lines = [] FILE = open(file_name) raw_data = csv.reader(FILE) header_lines = 2 line1 = raw_data.next() model_match = re.search("(\S+)\s+(\S+)\s.*", line1[0]) self.manufacturer = model_match.group(1) self.model = model_match.group(2) self.dia = float(re.search("[^-]+-[^-]+-[^-]+-(\d+).*", line1[0]).group(1)) self.dia = U.length_conv(self.dia, from_units="cm", to_units="in") for n in range(header_lines - 1): raw_data.next() # replace "J" with mach 0 temp_lines.append(raw_data.next()) temp_lines[0][0] = 0 # load block of efficiency values into temp storage while 1: try: temp_lines.append(raw_data.next()) except StopIteration: break for l, line in enumerate(temp_lines): for i, item in enumerate(line): try: temp_lines[l][i] = float(item) except ValueError: temp_lines[l][i] = 0.0 # determine required size for array self.x_size = len(temp_lines[0]) self.y_size = len(temp_lines) self.z_size = 2 temp_array1 = [] for line in temp_lines: temp_array1.append(line) # MT eff map does not have different data for different tip mach numbers. # To allow using the same routines as for Hartzell props, set the original # data for Mach 0, and make a copy for Mach 1. temp_array = [temp_array1, temp_array1] self.prop_eff_map = N.array(temp_array) self.prop_eff_map[1, 0, 0] = 1 # MT eff data has Cp running left to right, and Js running # vertically, which is the reverse of the Hartzell data. # Must swapaxes to get the same orientation for both props. self.prop_eff_map = self.prop_eff_map.swapaxes(1, 2) # determine range of mach, advance ratio and power coefficient in the efficiency data self.eff_mach_min = min(self.prop_eff_map[:, 0, 0]) self.eff_mach_max = max(self.prop_eff_map[:, 0, 0]) self.eff_Cp_min = min(self.prop_eff_map[0, :, 0]) self.eff_Cp_max = max(self.prop_eff_map[0, :, 0]) self.eff_J_min = min(self.prop_eff_map[0, 0, 1:]) self.eff_J_max = max(self.prop_eff_map[0, 0, 1:]) else: print "prop type not known"
def test_06(self): Value = U.length_conv(0.86897624, from_units='nm', to_units='sm') Truth = 1 self.assertTrue(RE(Value, Truth) <= 1e-5)
def pwr2mp(pwr_seek, rpm, altitude, temp='std', alt_units='ft', temp_units='C'): """ Returns manifold pressure in inches of mercury for a given power, rpm, altitude and temperature (temperature input is optional - standard temperature is used if no temperature is input). Note: the output is rounded off to two decimal places. Examples: Determine manifold pressure required for 125 hp at 2550 rpm at 8000 ft and 10 deg C: >>> pwr2mp(125, 2550, 8000, 10) '19.45' Determine manifold pressure required for 75% power at 2500 rpm at 7500 ft at 10 deg F: >>> pwr2mp(.75 * 200, 2500, 7500, 10, temp_units = 'F') '22.25' Determine manifold pressure required for 55% power at 2400 rpm at 9,500 ft at standard temperature: >>> pwr2mp(.55 * 200, 2400, 9500) '18.18' """ if pwr_seek <= 0: raise ValueError('Power input must be positive.') low = 0 # initial lower guess high = 35 # initial upper guess # convert units altitude = U.length_conv(altitude, from_units=alt_units, to_units='ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units=temp_units) temp = U.temp_conv(temp, from_units=temp_units, to_units='C') # confirm initial low and high are OK: pwr_low = pwr(rpm, low, altitude, temp) if pwr_low > pwr_seek: raise ValueError('Initial low guess too high.') pwr_high = pwr(rpm, high, altitude, temp) if pwr_high < pwr_seek: raise ValueError('Initial high guess too low.') guess = (low + high) / 2. pwr_guess = pwr(rpm, guess, altitude, temp) # keep iterating until power is within 0.1% of desired value while M.fabs(pwr_guess - pwr_seek) / pwr_seek > 1e-3: if pwr_guess > pwr_seek: high = guess else: low = guess guess = (low + high) / 2. pwr_guess = pwr(rpm, guess, altitude, temp) # result = int(guess) + round(guess % 1, 2)) # return guess # return result return '%.2f' % (guess)
def test_06(self): Value = U.length_conv(0.86897624, from_units='nm', to_units='sm') Truth = 1 self.failUnless(RE(Value, Truth) <= 1e-5)
def pwr2mp(pwr_seek, rpm, altitude, temp = 'std', alt_units = 'ft', temp_units = 'C'): """ Returns manifold pressure in inches of mercury for a given power, rpm, altitude and temperature (temperature input is optional - standard temperature is used if no temperature is input). Note: the output is rounded off to two decimal places. Examples: Determine manifold pressure required for 125 hp at 2550 rpm at 8000 ft and 10 deg C: >>> pwr2mp(125, 2550, 8000, 10) '19.45' Determine manifold pressure required for 75% power at 2500 rpm at 7500 ft at 10 deg F: >>> pwr2mp(.75 * 200, 2500, 7500, 10, temp_units = 'F') '22.25' Determine manifold pressure required for 55% power at 2400 rpm at 9,500 ft at standard temperature: >>> pwr2mp(.55 * 200, 2400, 9500) '18.18' """ if pwr_seek <= 0: raise ValueError, 'Power input must be positive.' low = 0 # initial lower guess high = 35 # initial upper guess # convert units altitude = U.length_conv(altitude, from_units = alt_units, to_units = 'ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units = temp_units) temp = U.temp_conv(temp, from_units = temp_units, to_units = 'C') # confirm initial low and high are OK: pwr_low = pwr(rpm, low, altitude, temp) if pwr_low > pwr_seek: raise ValueError, 'Initial low guess too high.' pwr_high = pwr(rpm, high, altitude, temp) if pwr_high < pwr_seek: raise ValueError, 'Initial high guess too low.' guess = (low + high) / 2. pwr_guess = pwr(rpm, guess, altitude, temp) # keep iterating until power is within 0.1% of desired value while M.fabs(pwr_guess - pwr_seek) / pwr_seek > 1e-3: if pwr_guess > pwr_seek: high = guess else: low = guess guess = (low + high) / 2. pwr_guess = pwr(rpm, guess, altitude, temp) # result = int(guess) + round(guess % 1, 2)) # return guess # return result return '%.2f' % (guess)
def pwr2rpm(pwr_seek, mp, altitude, temp='std', alt_units='ft', temp_units='C'): """ Returns rpm for a given power, manifold pressure in inches of mercury, altitude and temperature (temperature input is optional - standard temperature is used if no temperature is input). Note: the output is rounded off to the nearest rpm. Examples: Determine rpm required for 125 hp at 20 inches HG manifold pressure at 8000 ft and 10 deg C: >>> pwr2rpm(125, 20, 8000, 10) 2477 Determine rpm required for 75% power at 22 inches HG manifold pressure at 6500 ft and 10 deg F: >>> pwr2rpm(.75 * 200, 22, 6500, 10, temp_units = 'F') 2547 Determine rpm required for 55% power at at 18 inches HG manifold pressure at 9,500 ft at standard temperature: >>> pwr2rpm(.55 * 200, 18, 9500) 2423 """ if pwr_seek <= 0: raise ValueError('Power input must be positive.') low = 1000 # initial lower guess high = 3500 # initial upper guess # convert units altitude = U.length_conv(altitude, from_units=alt_units, to_units='ft') if temp == 'std': temp = SA.alt2temp(altitude, temp_units=temp_units) temp = U.temp_conv(temp, from_units=temp_units, to_units='C') # confirm initial low and high are OK: pwr_low = pwr(low, mp, altitude, temp) # print "pwr_low=", pwr_low if pwr_low > pwr_seek: raise ValueError('Initial low guess too high.') pwr_high = pwr(high, mp, altitude, temp) # print "pwr_high=", pwr_high if pwr_high < pwr_seek: # print "pwr_high=", pwr_high print("Function called was IO.pwr(%f, %f, %f, %f)" % (high, mp, altitude, temp)) raise ValueError('Initial high guess too low.') guess = (low + high) / 2. pwr_guess = pwr(guess, mp, altitude, temp) # keep iterating until power is within 0.1% of desired value while M.fabs(pwr_guess - pwr_seek) / pwr_seek > 1e-4: if pwr_guess > pwr_seek: high = guess else: low = guess guess = (low + high) / 2. pwr_guess = pwr(guess, mp, altitude, temp) return int(round(guess, 0))
def tas2ssec2(tas, ind_alt, oat, ias, std_alt = 0, speed_units=default_speed_units, alt_units=default_alt_units, temp_units=default_temp_units, press_units = default_press_units): """ Return static source position error as speed error, pressure error and altitude error at sea level using speed course method. Returns delta_Vpc, delta_Ps and delta_Hpc tas = true airspeed determined by speed course method, or GPS ind_alt = pressure altitude, corrected for instrument error oat = outside air temperature, corrected for instrument error and ram temperature rise ias = indicated airspeed, corrected for instrument error std_alt = altitude to provide delta_Hpc for delta_Vpc = error in airspeed = calibrated airspeed - indicated airspeed corrected for instrument error delta_Ps = error in the pressure sensed by the static system = pressure sensed in the static system - ambient pressure delta_Hpc = altitude error at std_alt = actual altitude - altitude sensed by the static system Uses analysis method from USAF Test Pilot School. Unlike some other methods (e.g.. that in FAA AC 23-8B, or NTPS GPS_PEC.xls), this method provides an exact conversion from TAS to CAS (some other methods assume CAS = EAS), and it accounts for the effect of position error of altitude on the conversion from TAS to CAS (some other methods assume pressure altitude = indicated pressure altitude). """ tas = U.speed_conv(tas, speed_units, 'kt') ind_alt = U.length_conv(ind_alt, alt_units, 'ft') oat = U.temp_conv(oat, temp_units, 'C') M = A.tas2mach(tas, oat, temp_units='C', speed_units='kt') if M > 1: raise ValueError, 'This method only works for Mach < 1' delta_ic = SA.alt2press_ratio(ind_alt, alt_units='ft') qcic_over_Psl = A.cas2dp(ias, speed_units='kt', press_units=press_units) / U.press_conv(constants.P0, 'pa', to_units=press_units) qcic_over_Ps = qcic_over_Psl / delta_ic Mic = A.dp_over_p2mach(qcic_over_Ps) delta_mach_pc = M - Mic if Mic > 1: raise ValueError, 'This method only works for Mach < 1' deltaPp_over_Ps = (1.4 * delta_mach_pc * (Mic + delta_mach_pc / 2)) / (1 + 0.2 * (Mic + delta_mach_pc / 2 )**2) deltaPp_over_qcic = deltaPp_over_Ps / qcic_over_Ps delta_Hpc = SA.alt2temp_ratio(std_alt, alt_units='ft') * deltaPp_over_Ps / 3.61382e-5 # experimental - alternate way to calculate delta_Hpc that gives same answer Ps = SA.alt2press(ind_alt, alt_units='ft', press_units=press_units) delta_Ps = deltaPp_over_Ps * Ps P_std = SA.alt2press(std_alt, alt_units='ft', press_units=press_units) deltaPs_std = deltaPp_over_Ps * P_std delta_Hpc2 = SA.press2alt(P_std - deltaPs_std, press_units = press_units) - std_alt delta_std_alt = SA.alt2press_ratio(std_alt, alt_units='ft') asl = U.speed_conv(constants.A0, 'm/s', 'kt') delta_Vpc_std_alt = deltaPp_over_Ps * delta_std_alt * asl**2 / (1.4 * ias * (1 + 0.2 * (ias / asl)**2)**2.5) actual_alt = SA.press2alt(Ps + delta_Ps, press_units = press_units, alt_units = 'ft') cas = A.tas2cas(tas, actual_alt, oat, speed_units='kt', alt_units='ft', temp_units='C') return delta_Vpc, delta_Ps, delta_Hpc, cas
def test_04(self): Value = U.length_conv(10, from_units='km', to_units='m') Truth = 10000 self.failUnless(RE(Value, Truth) <= 1e-5)
def test_04(self): Value = U.length_conv(10, from_units='km', to_units='m') Truth = 10000 self.assertTrue(RE(Value, Truth) <= 1e-5)
def test_01(self): Value = U.length_conv(120, from_units='in', to_units='ft') Truth = 10 self.failUnless(RE(Value, Truth) <= 1e-5)
def tas2ssec2(tas, ind_alt, oat, ias, std_alt=0, speed_units=default_speed_units, alt_units=default_alt_units, temp_units=default_temp_units, press_units=default_press_units): """ Return static source position error as speed error, pressure error and altitude error at sea level using speed course method. Returns delta_Vpc, delta_Ps and delta_Hpc tas = true airspeed determined by speed course method, or GPS ind_alt = pressure altitude, corrected for instrument error oat = outside air temperature, corrected for instrument error and ram temperature rise ias = indicated airspeed, corrected for instrument error std_alt = altitude to provide delta_Hpc for delta_Vpc = error in airspeed = calibrated airspeed - indicated airspeed corrected for instrument error delta_Ps = error in the pressure sensed by the static system = pressure sensed in the static system - ambient pressure delta_Hpc = altitude error at std_alt = actual altitude - altitude sensed by the static system Uses analysis method from USAF Test Pilot School. Unlike some other methods (e.g.. that in FAA AC 23-8B, or NTPS GPS_PEC.xls), this method provides an exact conversion from TAS to CAS (some other methods assume CAS = EAS), and it accounts for the effect of position error of altitude on the conversion from TAS to CAS (some other methods assume pressure altitude = indicated pressure altitude). """ tas = U.speed_conv(tas, speed_units, 'kt') ind_alt = U.length_conv(ind_alt, alt_units, 'ft') oat = U.temp_conv(oat, temp_units, 'C') M = A.tas2mach(tas, oat, temp_units='C', speed_units='kt') if M > 1: raise ValueError('This method only works for Mach < 1') delta_ic = SA.alt2press_ratio(ind_alt, alt_units='ft') qcic_over_Psl = A.cas2dp(ias, speed_units='kt', press_units=press_units) / U.press_conv( constants.P0, 'pa', to_units=press_units) qcic_over_Ps = qcic_over_Psl / delta_ic Mic = A.dp_over_p2mach(qcic_over_Ps) delta_mach_pc = M - Mic if Mic > 1: raise ValueError('This method only works for Mach < 1') deltaPp_over_Ps = (1.4 * delta_mach_pc * (Mic + delta_mach_pc / 2)) / ( 1 + 0.2 * (Mic + delta_mach_pc / 2)**2) deltaPp_over_qcic = deltaPp_over_Ps / qcic_over_Ps delta_Hpc = SA.alt2temp_ratio( std_alt, alt_units='ft') * deltaPp_over_Ps / 3.61382e-5 # experimental - alternate way to calculate delta_Hpc that gives same answer Ps = SA.alt2press(ind_alt, alt_units='ft', press_units=press_units) delta_Ps = deltaPp_over_Ps * Ps P_std = SA.alt2press(std_alt, alt_units='ft', press_units=press_units) deltaPs_std = deltaPp_over_Ps * P_std delta_Hpc2 = SA.press2alt(P_std - deltaPs_std, press_units=press_units) - std_alt delta_std_alt = SA.alt2press_ratio(std_alt, alt_units='ft') asl = U.speed_conv(constants.A0, 'm/s', 'kt') delta_Vpc_std_alt = deltaPp_over_Ps * delta_std_alt * asl**2 / ( 1.4 * ias * (1 + 0.2 * (ias / asl)**2)**2.5) actual_alt = SA.press2alt(Ps + delta_Ps, press_units=press_units, alt_units='ft') cas = A.tas2cas(tas, actual_alt, oat, speed_units='kt', alt_units='ft', temp_units='C') return delta_Vpc, delta_Ps, delta_Hpc, cas