Beispiel #1
0
def gps2stall(GS,
              TK,
              Hp,
              T,
              temp_units='C',
              alt_units=default_alt_units,
              speed_units=default_speed_units,
              GPS_units=default_speed_units):
    """
    Return the CAS at the stall, given four GPS ground speeds, GPS tracks, 
    altitude and temperature.
    
    speed_units = CAS units.  May be 'kt', 'mph', 'km/h', 'm/s' and 'ft/s'.
    GS_units = GPS ground speed units.  'kt', 'mph', 'km/h', 'm/s' and 'ft/s'.
    HP = pressure altitude.  May be feet ('ft'), metres ('m'), kilometres ('km'), 
    statute miles, ('sm') or nautical miles ('nm').

    The temperature may be in deg C, F, K or R. 

    If the units are not specified, the units in default_units.py are used.
    
    Conduct four stalls, in a four sided box pattern, with all stalls at the same
    pressure altitude.  The data reduction algorithm calculates the TAS using Doug
    Gray's GPS to TAS method, using four different combinations of three legs.  If
    the data quality is high, all four TAS values will be similar, with a low standard
    deviation.
    
    The TAS at the stall is converted to CAS, using pressure altitude and 
    temperature.
    
    Returns CAS and standard deviation of the CAS value.
    
    Examples:
    
    >>> gps2stall([44, 104, 157, 131], [258, 29, 91, 150], 7000, 14, temp_units='F', GPS_units='km/h')
    (50.322235245211225, 0.6583323098888626)

    """

    tas, std_dev = SSEC.gps2tas(GS, TK, verbose=1)
    tas = U.speed_conv(tas, from_units=GPS_units, to_units=speed_units)
    std_dev = U.speed_conv(std_dev, from_units=GPS_units, to_units=speed_units)
    cas = A.tas2cas(tas,
                    Hp,
                    T,
                    temp_units=temp_units,
                    alt_units=alt_units,
                    speed_units=speed_units)
    std_dev = std_dev * cas / tas  # factor standard deviation to reference CAS vs TAS

    return cas, std_dev
def temp2speed_of_sound(temp, temp_units=default_temp_units,
                        speed_units=default_speed_units):
    """
    Return the speed of sound, given the air temperature.  
    
    The temperature units may be deg C, F, K or R ('C', 'F', 'K' or 'R').
    
    The speed units may be 'kt', 'mph', 'km/h', 'm/s' and 'ft/s'.

    If the units are not specified, the units in default_units.py are used.
    
    Examples:
    
    Determine speed of sound in knots at 15 deg (default temperature units):
    >>> temp2speed_of_sound(15)
    661.47882487301808
    
    Determine speed of sound in mph at 120 deg F:
    >>> temp2speed_of_sound(120, speed_units = 'mph', temp_units = 'F')
    804.73500154991291
    """

    # function tested in tests/test_std_atm.py

    temp = U.temp_conv(temp, from_units=temp_units, to_units='K')

    speed_of_sound = M.sqrt((1.4 * Rd) * temp)
    speed_of_sound = U.speed_conv(speed_of_sound, from_units='m/s',
                                  to_units=speed_units)

    return speed_of_sound
Beispiel #3
0
def cd2drag(
    Cd,
    eas,
    wing_area,
    speed_units=default_speed_units,
    area_units=default_area_units,
    drag_units=default_weight_units,
):
    """
    Returns the drag, given coefficient of drag, equivalent airspeed, and wing
    area.
    
    Example:
    >>> cd2drag(.138, 100, 10, speed_units='km/h', area_units='m**2',\
    drag_units='N')
    652.1990740740742
    """

    eas = U.speed_conv(eas, from_units=speed_units, to_units='m/s')
    wing_area = U.area_conv(wing_area, from_units=area_units, to_units='m**2')

    drag = (((0.5 * Rho0) * eas**2) * wing_area) * Cd
    drag = U.force_conv(drag, from_units='N', to_units=drag_units)

    return drag
def _pwr_error(eas_guess,
               altitude,
               weight,
               power,
               rpm,
               temp='std',
               temp_units='C',
               rv='F1',
               wing_area=102,
               speed_units='kt',
               flap=0,
               prop_eff=0.78):
    tas_guess = A.eas2tas(eas_guess,
                          altitude,
                          temp=temp,
                          speed_units=speed_units)
    tas_guess_fts = U.speed_conv(tas_guess,
                                 from_units=speed_units,
                                 to_units='ft/s')
    power_avail = power * prop_eff

    drag = F.eas2drag(eas_guess,
                      weight,
                      wing_area,
                      rv=rv,
                      flap=flap,
                      speed_units=speed_units)
    power_req = tas_guess_fts * drag / 550.

    error = power_avail - power_req
    return error, tas_guess
Beispiel #5
0
def cl2cas(
    Cl,
    altitude,
    weight,
    wing_area,
    load_factor=1,
    speed_units=default_speed_units,
    alt_units=default_alt_units,
    weight_units=default_weight_units,
    area_units=default_area_units,
):
    """
    Returns the calibrated airspeed, given coefficient of lift, altitude, 
    weight, and wing area.

    Load factor is an optional input.  The load factor, if not provided, 
    defaults to 1.
    """

    weight = U.wt_conv(weight, from_units=weight_units, to_units='kg')
    wing_area = U.area_conv(wing_area, from_units=area_units, to_units='m**2')

    eas = ((((2. * weight) * g) * load_factor) /
           ((Rho0 * wing_area) * Cl))**0.5
    eas = U.speed_conv(eas, from_units='m/s', to_units=speed_units)
    cas = A.eas2cas(eas, altitude, speed_units, alt_units)

    return cas
Beispiel #6
0
def cd2drag(
    Cd,
    eas,
    wing_area,
    speed_units=default_speed_units,
    area_units=default_area_units,
    drag_units=default_weight_units,
    ):
    """
    Returns the drag, given coefficient of drag, equivalent airspeed, and wing
    area.
    
    Example:
    >>> cd2drag(.138, 100, 10, speed_units='km/h', area_units='m**2',\
    drag_units='N')
    652.19907407407425
    """

    eas = U.speed_conv(eas, from_units=speed_units, to_units='m/s')
    wing_area = U.area_conv(wing_area, from_units=area_units,
                            to_units='m**2')

    drag = (((0.5 * Rho0) * eas ** 2) * wing_area) * Cd
    drag = U.force_conv(drag, from_units='N', to_units=drag_units)

    return drag
def aoc(prop, altitude, eas, weight, power, rpm, temp = 'std', temp_units = 'C', \
    rv = '8', wing_area = 110, speed_units = 'kt', flap = 0):
    """
    Returns the climb or descent gradient.

    Runs with zero power at 1800 lb show best glide speed for RV-8 of:
    98 kt at 1800 lb
    86 kt at 1400 lb
    
    best angle of climb:
    66 kt at 1800 lb
    """ 
    tas = A.eas2tas(eas, altitude, temp = temp, speed_units = speed_units)
    tas_fts = U.speed_conv(tas, from_units = speed_units, to_units = 'ft/s')
    prop_eff = PM.prop_eff(prop, power, rpm, tas, altitude, temp = temp, \
        temp_units = 'C', speed_units = speed_units)
    power_avail = power * prop_eff

    drag = FT.eas2drag(eas, weight, wing_area, rv = rv, flap = flap, \
        speed_units = speed_units)
    power_req = tas_fts * drag / 550.
    
    excess_power = power_avail - power_req
    roc = excess_power * 550 / weight
    gradient = roc / tas_fts
    return gradient
Beispiel #8
0
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 run_tests(cd0 = 0.0221, e = 0.825):
    """
    Run all test cases to compare drag polar model against CAFE results.
    """
    sum_sq = 0
    wt_value_tot = 0
    wing_area = 110
    prop = PM.Prop('7666-4RV')
    for n, test in enumerate(level_test_cases):
        tas = test[0]
        dalt = test[1]
        wt = test[2]
        rpm = test[3]
        mp = test[4]
        wt_value = test[5]
    
        eas = A.tas2eas(tas, dalt, speed_units = 'mph')
        tas_fts = U.speed_conv(tas, from_units = 'mph', to_units = 'ft/s')
        cl = FT.eas2cl(eas, wt, wing_area, speed_units = 'mph')
        cd = FT.cl2cd_test(cl, cd0, e, flap = 0)
        drag = FT.cd2drag(cd, eas, wing_area, speed_units = 'mph')
        
        drag_power = drag * tas_fts / 550.
        power = IO.pwr(rpm, mp, dalt)
        prop_eff = PM.prop_eff(prop, power, rpm, tas, dalt, speed_units = 'mph')
        thrust_power = power * prop_eff
        excess_power = thrust_power - drag_power
        
        print 'Case', n, 'Altitude =', dalt, 'TAS =', tas, 'EAS =', eas, 'Excess power =', excess_power
        
        sum_sq += wt_value * excess_power ** 2
        wt_value_tot += wt_value
        
    print 'Average sum of squares of excess power =', \
        (sum_sq / wt_value_tot) ** 0.5
def temp2speed_of_sound(temp,
                        temp_units=default_temp_units,
                        speed_units=default_speed_units):
    """
    Return the speed of sound, given the air temperature.  
    
    The temperature units may be deg C, F, K or R ('C', 'F', 'K' or 'R').
    
    The speed units may be 'kt', 'mph', 'km/h', 'm/s' and 'ft/s'.

    If the units are not specified, the units in default_units.py are used.
    
    Examples:
    
    Determine speed of sound in knots at 15 deg (default temperature units):
    >>> temp2speed_of_sound(15)
    661.47882487301808
    
    Determine speed of sound in mph at 120 deg F:
    >>> temp2speed_of_sound(120, speed_units = 'mph', temp_units = 'F')
    804.73500154991291
    """

    # function tested in tests/test_std_atm.py

    temp = U.temp_conv(temp, from_units=temp_units, to_units='K')

    speed_of_sound = M.sqrt((1.4 * Rd) * temp)
    speed_of_sound = U.speed_conv(speed_of_sound,
                                  from_units='m/s',
                                  to_units=speed_units)

    return speed_of_sound
Beispiel #11
0
def cl2lift(
    Cl,
    eas,
    wing_area,
    speed_units=default_speed_units,
    lift_units=default_weight_units,
    area_units=default_area_units,
    ):
    """
    Returns the lift, given coefficient of lift, equivalent airspeed, and wing
    area.
    """

    eas = U.speed_conv(eas, from_units=speed_units, to_units='m/s')
    wing_area = U.area_conv(wing_area, from_units=area_units,
                            to_units='m**2')

    lift = (((0.5 * Rho0) * eas ** 2.) * wing_area) * Cl
    if lift_units == 'kg':
        lift = U.force_conv(lift, 'N', 'lb')
        lift = U.mass_conv(lift, 'lb', 'kg')
    else:
        lift = U.force_conv(lift, 'N', lift_units)

    return lift
Beispiel #12
0
def aoc(prop, altitude, eas, weight, power, rpm, temp = 'std', temp_units = 'C', \
    rv = '8', wing_area = 110, speed_units = 'kt', flap = 0):
    """
    Returns the climb or descent gradient.

    Runs with zero power at 1800 lb show best glide speed for RV-8 of:
    98 kt at 1800 lb
    86 kt at 1400 lb
    
    best angle of climb:
    66 kt at 1800 lb
    """
    tas = A.eas2tas(eas, altitude, temp=temp, speed_units=speed_units)
    tas_fts = U.speed_conv(tas, from_units=speed_units, to_units='ft/s')
    prop_eff = PM.prop_eff(prop, power, rpm, tas, altitude, temp = temp, \
        temp_units = 'C', speed_units = speed_units)
    power_avail = power * prop_eff

    drag = FT.eas2drag(eas, weight, wing_area, rv = rv, flap = flap, \
        speed_units = speed_units)
    power_req = tas_fts * drag / 550.

    excess_power = power_avail - power_req
    roc = excess_power * 550 / weight
    gradient = roc / tas_fts
    return gradient
Beispiel #13
0
def cl2cas(
    Cl,
    altitude,
    weight,
    wing_area,
    load_factor=1,
    speed_units=default_speed_units,
    alt_units=default_alt_units,
    weight_units=default_weight_units,
    area_units=default_area_units,
    ):
    """
    Returns the calibrated airspeed, given coefficient of lift, altitude, 
    weight, and wing area.

    Load factor is an optional input.  The load factor, if not provided, 
    defaults to 1.
    """

    weight = U.wt_conv(weight, from_units=weight_units, to_units='kg')
    wing_area = U.area_conv(wing_area, from_units=area_units,
                            to_units='m**2')

    eas = ((((2. * weight) * g) * load_factor) / ((Rho0 * wing_area)
            * Cl)) ** 0.5
    eas = U.speed_conv(eas, from_units='m/s', to_units=speed_units)
    cas = A.eas2cas(eas, altitude, speed_units, alt_units)

    return cas
Beispiel #14
0
def eff2thrust(eff, bhp, TAS, power_units="hp", speed_units="kt", thrust_units="lb"):
    """
    Returns thrust, given prop efficiency, true airspeed and brake power.
    
    Matches the results from the Hartzell prop map program fairly closely.
    """
    TAS = U.speed_conv(TAS, from_units=speed_units, to_units="m/s")
    bhp = U.power_conv(bhp, from_units=power_units, to_units="W")
    thrust = eff * bhp / TAS

    return U.force_conv(thrust, from_units="N", to_units=thrust_units)
Beispiel #15
0
def gps2stall(GS, TK, Hp, T, temp_units='C', alt_units=default_alt_units, speed_units=default_speed_units, GPS_units=default_speed_units):
    """
    Return the CAS at the stall, given four GPS ground speeds, GPS tracks, 
    altitude and temperature.
    
    speed_units = CAS units.  May be 'kt', 'mph', 'km/h', 'm/s' and 'ft/s'.
    GS_units = GPS ground speed units.  'kt', 'mph', 'km/h', 'm/s' and 'ft/s'.
    HP = pressure altitude.  May be feet ('ft'), metres ('m'), kilometres ('km'), 
    statute miles, ('sm') or nautical miles ('nm').

    The temperature may be in deg C, F, K or R. 

    If the units are not specified, the units in default_units.py are used.
    
    Conduct four stalls, in a four sided box pattern, with all stalls at the same
    pressure altitude.  The data reduction algorithm calculates the TAS using Doug
    Gray's GPS to TAS method, using four different combinations of three legs.  If
    the data quality is high, all four TAS values will be similar, with a low standard
    deviation.
    
    The TAS at the stall is converted to CAS, using pressure altitude and 
    temperature.
    
    Returns CAS and standard deviation of the CAS value.
    
    Examples:
    
    >>> gps2stall([44, 104, 157, 131], [258, 29, 91, 150], 7000, 14, temp_units='F', GPS_units='km/h')
    (50.322235245211225, 0.6583323098888626)

    """


    tas, std_dev = SSEC.gps2tas(GS, TK, verbose=1)
    tas = U.speed_conv(tas, from_units=GPS_units, to_units=speed_units)
    std_dev = U.speed_conv(std_dev, from_units=GPS_units, to_units=speed_units)
    cas = A.tas2cas(tas, Hp, T, temp_units=temp_units, alt_units=alt_units, speed_units=speed_units)
    std_dev = std_dev * cas / tas # factor standard deviation to reference CAS vs TAS

    return cas, std_dev
Beispiel #16
0
def eff2thrust(eff,
               bhp,
               TAS,
               power_units='hp',
               speed_units='kt',
               thrust_units='lb'):
    """
    Returns thrust, given prop efficiency, true airspeed and brake power.
    
    Matches the results from the Hartzell prop map program fairly closely.
    """
    TAS = U.speed_conv(TAS, from_units=speed_units, to_units='m/s')
    bhp = U.power_conv(bhp, from_units=power_units, to_units='W')
    thrust = eff * bhp / TAS

    return U.force_conv(thrust, from_units='N', to_units=thrust_units)
def _pwr_error(eas_guess, altitude, weight, power, rpm, temp = 'std', \
    temp_units = 'C', rv = 'F1', wing_area = 102, speed_units = 'kt', \
    flap = 0, prop_eff=0.78):
    tas_guess = A.eas2tas(eas_guess, altitude, temp = temp, \
        speed_units = speed_units)
    tas_guess_fts = U.speed_conv(tas_guess, from_units = speed_units, \
        to_units = 'ft/s')
    power_avail = power * prop_eff

    drag = F.eas2drag(eas_guess, weight, wing_area, rv = rv, flap = flap,\
        speed_units = speed_units)
    power_req = tas_guess_fts * drag / 550.
    

    error = power_avail - power_req
    return error, tas_guess
Beispiel #18
0
def _pwr_error(prop, eas_guess, altitude, weight, power, rpm, temp = 'std', \
    temp_units = 'C', rv = '8', wing_area = 110, speed_units = 'kt', \
    flap = 0, wheel_pants = 1):
    tas_guess = A.eas2tas(eas_guess, altitude, temp = temp, \
        speed_units = speed_units, temp_units = temp_units)
    tas_guess_fts = U.speed_conv(tas_guess, from_units = speed_units, \
        to_units = 'ft/s')
    prop_eff = PM.prop_eff(prop, power, rpm, tas_guess, altitude, temp = temp,\
        temp_units = temp_units, speed_units = speed_units)
    power_avail = power * prop_eff

    drag = FT.eas2drag(eas_guess, weight, wing_area, rv = rv, flap = flap,\
        speed_units = speed_units, wheel_pants = wheel_pants)
    power_req = tas_guess_fts * drag / 550.

    error = power_avail - power_req
    return error, tas_guess
Beispiel #19
0
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
Beispiel #20
0
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 _pwr_error(prop, eas_guess, altitude, weight, power, rpm, temp = 'std', \
    temp_units = 'C', rv = '8', wing_area = 110, speed_units = 'kt', \
    flap = 0, wheel_pants = 1):
    tas_guess = A.eas2tas(eas_guess, altitude, temp = temp, \
        speed_units = speed_units, temp_units = temp_units)
    tas_guess_fts = U.speed_conv(tas_guess, from_units = speed_units, \
        to_units = 'ft/s')
    prop_eff = PM.prop_eff(prop, power, rpm, tas_guess, altitude, temp = temp,\
        temp_units = temp_units, speed_units = speed_units)
    power_avail = power * prop_eff

    drag = FT.eas2drag(eas_guess, weight, wing_area, rv = rv, flap = flap,\
        speed_units = speed_units, wheel_pants = wheel_pants)
    power_req = tas_guess_fts * drag / 550.
    

    error = power_avail - power_req
    return error, tas_guess
Beispiel #22
0
def p(tas, dalt, wt, rpm, mp, prop):
    """
    test function for RV-8A drag, to compare against CAFE foundation level
    flt data.
    
    prop is a prop_map.Prop instance.
    """

    eas = A.tas2eas(tas, dalt, speed_units='mph')
    #   tas = A.cas2tas(cas, dalt, speed_units = 'mph')
    tas_fts = U.speed_conv(tas, from_units='mph', to_units='ft/s')
    drag = FT.eas2drag(eas, wt, 110, rv='8a', speed_units='mph')
    drag_power = drag * tas_fts / 550.
    power = IO.pwr(rpm, mp, dalt)
    prop_eff = PM.prop_eff(prop, power, rpm, tas, dalt, speed_units='mph')
    thrust_power = power * prop_eff
    excess_power = thrust_power - drag_power
    return excess_power
Beispiel #23
0
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 p(tas, dalt, wt, rpm, mp, prop):
    """
    test function for RV-8A drag, to compare against CAFE foundation level
    flt data.
    
    prop is a prop_map.Prop instance.
    """
    

    eas = A.tas2eas(tas, dalt, speed_units = 'mph')
#   tas = A.cas2tas(cas, dalt, speed_units = 'mph')
    tas_fts = U.speed_conv(tas, from_units = 'mph', to_units = 'ft/s')
    drag = FT.eas2drag(eas, wt, 110, rv = '8a', speed_units = 'mph')
    drag_power = drag * tas_fts / 550.
    power = IO.pwr(rpm, mp, dalt)
    prop_eff = PM.prop_eff(prop, power, rpm, tas, dalt, speed_units = 'mph')
    thrust_power = power * prop_eff
    excess_power = thrust_power - drag_power
    return excess_power
Beispiel #25
0
def roc(altitude, eas, weight, power, rpm, temp = 'std', temp_units = 'C', \
    rv = 'F1',  wing_area = 102, speed_units = 'kt', flap = 0, \
    prop_eff = 0.7, load_factor = 1):
    """
    Returns the rate of climb or descent.
    """
    # PM.read_data_files_csv(base_name = prop)
    tas = A.eas2tas(eas, altitude, temp=temp, speed_units=speed_units)
    tas_fts = U.speed_conv(tas, from_units=speed_units, to_units='ft/s')
    # prop_eff = PM.prop_eff(power, rpm, tas, altitude, temp = temp, \
    #     temp_units = 'C', speed_units = speed_units)
    power_avail = power * prop_eff

    drag = F.eas2drag(eas, weight, wing_area, rv = rv, flap = flap, \
        speed_units = speed_units, load_factor = load_factor)
    power_req = tas_fts * drag / 550.

    excess_power = power_avail - power_req
    roc = excess_power * 33000 / weight

    return roc
def roc(prop, altitude, eas, weight, power, rpm, temp = 'std', temp_units = 'C', \
    rv = '8',  wing_area = 110, speed_units = 'kt', flap = 0, \
    load_factor = 1, wheel_pants = 1, prop_factor=1):
    """
    Returns the rate of climb or descent.
    """ 
    # PM.read_data_files_csv(base_name = prop)
    tas = A.eas2tas(eas, altitude, temp = temp, speed_units = speed_units)
    tas_fts = U.speed_conv(tas, from_units = speed_units, to_units = 'ft/s')
    prop_eff = PM.prop_eff(prop, power, rpm, tas, altitude, temp = temp, \
        temp_units = 'C', speed_units = speed_units) * prop_factor
    power_avail = power * prop_eff

    drag = FT.eas2drag(eas, weight, wing_area, rv = rv, flap = flap, \
        speed_units = speed_units, load_factor = load_factor, wheel_pants = wheel_pants)
    power_req = tas_fts * drag / 550.
    
    excess_power = power_avail - power_req
    roc = excess_power * 33000 / weight

    return roc
def alt2FP_speed(engine, prop, blade_angle, alt, weight = 1800, temp = 'std', \
    temp_units = 'C', rv = '8', wing_area = 110, alt_units='ft', speed_units = 'kt' , \
    MP_loss = 1.322, ram = 0.5, pwr_factor=1, mixture='pwr', MP='WOT', wheel_pants=1):
    """
    Returns the predicted speed at full throttle for aircraft with fixed pitch prop.
    
    The MP_loss is the MP lost in the induction tract at full throttle at 2700
    rpm at MSL.  The default value is from the Lycoming power charts.
    The ram is the percentage of available ram recovery pressure that is
    achieved in the MP.
    """
    
    tas_low = 80
    tas_high = 250
    pwr_tolerance = .1
    
    while 1:
        tas_guess = (tas_low + tas_high) / 2.
        tas_guess_fts = U.speed_conv(tas_guess, from_units = speed_units, to_units = 'ft/s')
        rpm = tas2rpm(tas_guess, engine, prop, blade_angle, alt, temp=temp, alt_units=alt_units, temp_units=temp_units, speed_units=speed_units, MP=MP)
        if MP == 'WOT':
            MP = MP_pred(tas_guess, alt, rpm, rpm_base = 2700., MP_loss = MP_loss, ram = ram, temp=temp)
        bhp = engine.pwr(rpm, MP, alt, temp=temp, alt_units=alt_units, temp_units=temp_units)
        prop_eff = PM.prop_eff(prop, bhp, rpm, tas_guess, alt, temp = temp, temp_units = temp_units, speed_units = speed_units)
        power_avail = bhp * prop_eff
        eas_guess = A.tas2eas(tas_guess, alt, temp)
        drag = FT.eas2drag(eas_guess, weight, wing_area, rv = rv, flap = 0, speed_units = speed_units, wheel_pants = wheel_pants)
        power_req = tas_guess_fts * drag / 550.
        
        if M.fabs(power_avail - power_req) < pwr_tolerance:
#            print "MP = %.3f" % MP
#            print "Pwr = %.2f"% bhp 
#            print "Prop Efficiency = %.3f, and power available = %.1f thp" % (prop_eff, power_avail)
            return tas_guess, rpm, bhp
        
        if power_req > power_avail:
            tas_high = tas_guess
        else:
            tas_low = tas_guess
Beispiel #28
0
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
Beispiel #29
0
def cl2tas(
    Cl,
    altitude,
    weight,
    wing_area,
    temperature='std',
    load_factor=1,
    speed_units=default_speed_units,
    alt_units=default_alt_units,
    weight_units=default_weight_units,
    area_units=default_area_units,
    temp_units=default_temp_units,
    ):
    """
    Returns the true airspeed, given coefficient of lift, altitude, weight,
    and wing area.
    
    Temperature and load factor are optional inputs.  The temperature, if 
    not provided, defaults to the standard temperature for the altitude.  
    The load factor, if not provided, defaults to 1.
    """

    weight = U.wt_conv(weight, from_units=weight_units, to_units='kg')
    wing_area = U.area_conv(wing_area, from_units=area_units,
                            to_units='m**2')

    eas = ((((2. * weight) * g) * load_factor) / ((Rho0 * wing_area)
            * Cl)) ** 0.5
    eas = U.speed_conv(eas, from_units='m/s', to_units=speed_units)
    tas = A.eas2tas(
        eas,
        altitude,
        temperature,
        speed_units,
        alt_units,
        temp_units=temp_units,
        )

    return tas
Beispiel #30
0
def eas2cl(
    eas,
    weight,
    wing_area,
    load_factor=1,
    speed_units=default_speed_units,
    weight_units=default_weight_units,
    area_units=default_area_units,
    ):
    """
    Returns the coefficient of lift, given equivalent airspeed, weight, and 
    wing area.
    
    Load factor is an optional input.  The load factor, if not provided, 
    defaults to 1.
    
    Example:
    if the wing area is 110 square feet,
    and the weight is 1800 lb,
    and the eas is 55 kt,
    in straight and level flight (so the load factor = 1),
    
    then:
    >>> S = 110
    >>> W = 1800
    >>> EAS = 55
    >>> eas2cl(EAS, W, S, speed_units='kt', weight_units='lb', area_units='ft**2')
    1.597820083228606
    """

    eas = U.speed_conv(eas, from_units=speed_units, to_units='m/s')
    weight = U.wt_conv(weight, from_units=weight_units, to_units='kg')
    wing_area = U.area_conv(wing_area, from_units=area_units,
                            to_units='m**2')

    Cl = (((2. * weight) * g) * load_factor) / ((Rho0 * wing_area) * eas
             ** 2.)

    return Cl
Beispiel #31
0
def cl2tas(
    Cl,
    altitude,
    weight,
    wing_area,
    temperature='std',
    load_factor=1,
    speed_units=default_speed_units,
    alt_units=default_alt_units,
    weight_units=default_weight_units,
    area_units=default_area_units,
    temp_units=default_temp_units,
):
    """
    Returns the true airspeed, given coefficient of lift, altitude, weight,
    and wing area.
    
    Temperature and load factor are optional inputs.  The temperature, if 
    not provided, defaults to the standard temperature for the altitude.  
    The load factor, if not provided, defaults to 1.
    """

    weight = U.wt_conv(weight, from_units=weight_units, to_units='kg')
    wing_area = U.area_conv(wing_area, from_units=area_units, to_units='m**2')

    eas = ((((2. * weight) * g) * load_factor) /
           ((Rho0 * wing_area) * Cl))**0.5
    eas = U.speed_conv(eas, from_units='m/s', to_units=speed_units)
    tas = A.eas2tas(
        eas,
        altitude,
        temperature,
        speed_units,
        alt_units,
        temp_units=temp_units,
    )

    return tas
Beispiel #32
0
def eas2cl(
    eas,
    weight,
    wing_area,
    load_factor=1,
    speed_units=default_speed_units,
    weight_units=default_weight_units,
    area_units=default_area_units,
):
    """
    Returns the coefficient of lift, given equivalent airspeed, weight, and 
    wing area.
    
    Load factor is an optional input.  The load factor, if not provided, 
    defaults to 1.
    
    Example:
    if the wing area is 110 square feet,
    and the weight is 1800 lb,
    and the eas is 55 kt,
    in straight and level flight (so the load factor = 1),
    
    then:
    >>> S = 110
    >>> W = 1800
    >>> EAS = 55
    >>> eas2cl(EAS, W, S, speed_units='kt', weight_units='lb', area_units='ft**2')
    1.597820083228606
    """

    eas = U.speed_conv(eas, from_units=speed_units, to_units='m/s')
    weight = U.wt_conv(weight, from_units=weight_units, to_units='kg')
    wing_area = U.area_conv(wing_area, from_units=area_units, to_units='m**2')

    Cl = (((2. * weight) * g) * load_factor) / ((Rho0 * wing_area) * eas**2.)

    return Cl
Beispiel #33
0
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
Beispiel #34
0
def run_tests(cd0=0.0221, e=0.825):
    """
    Run all test cases to compare drag polar model against CAFE results.
    """
    sum_sq = 0
    wt_value_tot = 0
    wing_area = 110
    prop = PM.Prop('7666-4RV')
    for n, test in enumerate(level_test_cases):
        tas = test[0]
        dalt = test[1]
        wt = test[2]
        rpm = test[3]
        mp = test[4]
        wt_value = test[5]

        eas = A.tas2eas(tas, dalt, speed_units='mph')
        tas_fts = U.speed_conv(tas, from_units='mph', to_units='ft/s')
        cl = FT.eas2cl(eas, wt, wing_area, speed_units='mph')
        cd = FT.cl2cd_test(cl, cd0, e, flap=0)
        drag = FT.cd2drag(cd, eas, wing_area, speed_units='mph')

        drag_power = drag * tas_fts / 550.
        power = IO.pwr(rpm, mp, dalt)
        prop_eff = PM.prop_eff(prop, power, rpm, tas, dalt, speed_units='mph')
        thrust_power = power * prop_eff
        excess_power = thrust_power - drag_power

        print('Case', n, 'Altitude =', dalt, 'TAS =', tas, 'EAS =', eas,
              'Excess power =', excess_power)

        sum_sq += wt_value * excess_power**2
        wt_value_tot += wt_value

    print('Average sum of squares of excess power =', \
        (sum_sq / wt_value_tot) ** 0.5)
Beispiel #35
0
def cl2lift(
    Cl,
    eas,
    wing_area,
    speed_units=default_speed_units,
    lift_units=default_weight_units,
    area_units=default_area_units,
):
    """
    Returns the lift, given coefficient of lift, equivalent airspeed, and wing
    area.
    """

    eas = U.speed_conv(eas, from_units=speed_units, to_units='m/s')
    wing_area = U.area_conv(wing_area, from_units=area_units, to_units='m**2')

    lift = (((0.5 * Rho0) * eas**2.) * wing_area) * Cl
    if lift_units == 'kg':
        lift = U.force_conv(lift, 'N', 'lb')
        lift = U.mass_conv(lift, 'lb', 'kg')
    else:
        lift = U.force_conv(lift, 'N', lift_units)

    return lift
def descent_data(prop, weight=1600., alt_max=20000., fuel_units='USG', \
    alt_interval=500., isa_dev=0, temp_units='C', rv='8',  wing_area=110., \
    tas=180., ROD=-500., angle='', speed_units='kt', rpm=2100., sfc=0.45, output='raw'):
    """
    Returns a table of descent performance vs altitude.

    The items in each row of the table are altitude, time, fuel burned and distance.
    Time is in units of minutes, rounded to the nearest half minute.
    Fuel units are selectable, with a default of USG.
    Distances are in nm.
    
    The output may be specified as raw, latex (a LaTeX table for the POH), or array.
    
    tas is the TAS in descent (overridden by the angle, if the angle is provided).
    angle is the flight path angle in degrees.
    """
    tas_fts = U.speed_conv(tas, speed_units, 'ft/s')

    if angle:
        ROD = tas_fts * 60 * M.sin(angle * M.pi / 180)
        
    rod_fts = ROD / 60

    tas = U.speed_conv(tas, speed_units, 'kt')
    
    alt = alt_max + alt_interval
    temp = SA.isa2temp(isa_dev, alt, temp_units=temp_units)
    time = 0
    fuel_used = 0
    dist = 0
    
    if output == 'raw':
        print S.center('Altitude', 10),
        print S.center('ROD', 10),
        print S.center('Time', 10),
        print S.center('Fuel Used', 10),
        print S.center('Dist', 10),
        print S.center('Speed', 10)
        
        print S.center('(ft)', 10),
        print S.center('(ft/mn)', 10),
        print S.center('(mn)', 10),
        f_units = '(' + fuel_units + ')'
        print S.center(f_units, 10),
        print S.center('(nm)', 10),
        print S.center('(KCAS)', 10)
        
        # # data for max altitude
        # print S.rjust(locale.format('%.0f', alt_max, True), 7),
        # print S.rjust(locale.format('%.0f', round(ROD / 10.) * 10, True), 10),
        # print S.rjust('%.1f' % (0), 10),
        # print S.rjust('%.1f' % (fuel_used), 10),
        # print S.rjust('%.1f' % (dist), 10),
        # print S.rjust('%3d' % (A.tas2cas(tas, alt_max, temp, temp_units=temp_units)), 10)

    # elif output == 'latex':
    #     # temp = 15 + isa_dev
    #     MSL_line = []
    #     MSL_line.append(str(locale.format('%.0f', weight, True)))
    #     MSL_line.append('0')
    #     MSL_line.append(str(locale.format('%.0f', temp)))
    #     MSL_line.append(str(locale.format('%.0f', A.tas2cas(tas, alt, temp, temp_units=temp_units))))
    #     MSL_line.append(str(locale.format('%.0f', round(ROD / 10.) * 10, True)))
    #     MSL_line.append('0')
    #     MSL_line.append(str(fuel_used))
    #     MSL_line.append(str(dist))
    #     
    #     print '&'.join(MSL_line) + '\\\\'
    #     print '\\hline'
    # elif output == 'array':
    #     # no header rows, but make blank array
    #     array = [[alt_max,0,0,0]]
        

    alts = []
    RODs = []
    times_temp = []
    CASs = []
    dists_temp = []
    fuel_useds_temp = []
    temps = []

    calc_alt = alt_max - alt_interval / 2.
    while alt > 0:
        temp = SA.isa2temp(isa_dev, alt, temp_units = temp_units)
        eas = A.tas2eas(tas, alt)
        drag = FT.eas2drag(eas, weight)
        pwr_level_flt = tas_fts * drag / 550
        thrust_power = pwr_level_flt + FT.Pexcess_vs_roc(weight, ROD)
        prop_eff = PM.prop_eff(prop, thrust_power, rpm, tas, alt, temp, temp_units=temp_units)
        calc_pwr = thrust_power / prop_eff        
        #fuel_flow = IO.pwr2ff(calc_pwr, rpm, ff_units = 'lb/hr')
        fuel_flow = calc_pwr * sfc 
        # print "Level flt pwr = %.1f, thrust power = %.1f, prop eff = %.3f, fuel flow = %.3f" % (pwr_level_flt, thrust_power, prop_eff, fuel_flow)
        slice_time = alt_interval / rod_fts * -1.
        slice_dist = tas_fts * slice_time
        slice_fuel = fuel_flow * slice_time / 3600
        fuel_used += slice_fuel
        fuel_out = (U.avgas_conv(fuel_used, from_units = 'lb', \
            to_units = fuel_units))
        weight -= slice_fuel
        alt -= alt_interval
        cas_out = A.tas2cas(tas, alt, temp, temp_units=temp_units)
        temp_out = SA.isa2temp(isa_dev, alt)
        time += slice_time / 60.
        dist += slice_dist / 6076.115

        alts.append(alt)
        CASs.append(cas_out)
        RODs.append(ROD)
        times_temp.append(time)
        fuel_useds_temp.append(fuel_out)
        dists_temp.append(dist)
        temps.append(temp_out)
        
        calc_alt += alt_interval
        
    alts.reverse()
    CASs.reverse()
    RODs.reverse()
    temps.reverse()
    
    times = []
    fuel_useds = []
    dists = []
    
    for n, time in enumerate(times_temp):
        times.append(times_temp[-1] - time)
        fuel_useds.append(fuel_useds_temp[-1] - fuel_useds_temp[n])
        dists.append(dists_temp[-1] - dists_temp[n])
        
    times.reverse()
    fuel_useds.reverse()
    dists.reverse()
    
    if output == 'raw':
        for n, alt in enumerate(alts):            
            print S.rjust(locale.format('%.0f', alt, True), 7),
            # calculate ROC at the displayed altitude
            print S.rjust(locale.format('%.0f', RODs[n], True), 10),
            print S.rjust('%.1f' % (times[n]), 10),
            print S.rjust('%.1f' % (fuel_useds[n]), 10),
            print S.rjust('%.1f' % (dists[n]), 10),
            print S.rjust('%3d' % (int(CASs[n])), 10)
    elif output == 'latex':
        for n, alt in enumerate(alts):                    
            line = []
            line.append(str(locale.format('%.0f', alt, True)))
            line.append(str(locale.format('%.0f', round(temps[n]))))
            line.append(str(locale.format('%.0f', CASs[n])))
            line.append(str(locale.format('%.0f', round(RODs[n] / 10.) * 10, True)))
            line.append(str(locale.format('%.0f', times[n])))
            line.append(str(locale.format('%.1f', fuel_useds[n])))
            line.append(str(locale.format('%.0f', dists[n])))
            print '&' + '&'.join(line) + '\\\\'
            print '\\hline'
    elif output == 'array':
        array = []
        for n, alt in enumerate(alts):
            array.append([alt, times[n], fuel_useds[n], dists[n]])
        return array
Beispiel #37
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.speed_conv(1, from_units='m/s', to_units='ft/s')
     Truth = 1 / 0.3048
     self.assertTrue(RE(Value, Truth) <= 1e-8)
Beispiel #39
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_03(self):
     Value = U.speed_conv(1, from_units='km/h', to_units='m/s')
     Truth = 1000 / 3600.
     self.failUnless(RE(Value, Truth) <= 1e-8)
 def test_05(self):
     Value = U.speed_conv(1, from_units='ft/s', to_units='kt')
     Truth = 3600. / (1852. / 0.3048)
     self.failUnless(RE(Value, Truth) <= 1e-8)
 def test_03(self):
     Value = U.speed_conv(1, from_units='km/h', to_units='m/s')
     Truth = 1000 / 3600.
     self.failUnless(RE(Value, Truth) <= 1e-5)
 def test_04(self):
     Value = U.speed_conv(1, from_units='m/s', to_units='ft/s')
     Truth = 1 / 0.3048
     self.failUnless(RE(Value, Truth) <= 1e-5)
 def test_01(self):
     Value = U.speed_conv(1, from_units='kt', to_units='mph')
     Truth = (1852. / 0.3048) / 5280
     self.failUnless(RE(Value, Truth) <= 1e-5)
 def test_02(self):
     Value = U.speed_conv(1, from_units='mph', to_units='km/h')
     Truth = (5280 * 0.3048) / 1000
     self.failUnless(RE(Value, Truth) <= 1e-5)
 def test_02(self):
     Value = U.speed_conv(1, from_units='mph', to_units='km/h')
     Truth = (5280 * 0.3048) / 1000
     self.assertTrue(RE(Value, Truth) <= 1e-8)
 def test_03(self):
     Value = U.speed_conv(1, from_units='km/h', to_units='m/s')
     Truth = 1000 / 3600.
     self.assertTrue(RE(Value, Truth) <= 1e-8)
Beispiel #48
0
def descent_data(prop, weight=1600., alt_max=20000., fuel_units='USG', \
    alt_interval=500., isa_dev=0, temp_units='C', rv='8',  wing_area=110., \
    tas=180., ROD=-500., angle='', speed_units='kt', rpm=2100., sfc=0.45, output='raw'):
    """
    Returns a table of descent performance vs altitude.

    The items in each row of the table are altitude, time, fuel burned and distance.
    Time is in units of minutes, rounded to the nearest half minute.
    Fuel units are selectable, with a default of USG.
    Distances are in nm.
    
    The output may be specified as raw, latex (a LaTeX table for the POH), or array.
    
    tas is the TAS in descent (overridden by the angle, if the angle is provided).
    angle is the flight path angle in degrees.
    """
    tas_fts = U.speed_conv(tas, speed_units, 'ft/s')

    if angle:
        ROD = tas_fts * 60 * M.sin(angle * M.pi / 180)

    rod_fts = ROD / 60

    tas = U.speed_conv(tas, speed_units, 'kt')

    alt = alt_max + alt_interval
    temp = SA.isa2temp(isa_dev, alt, temp_units=temp_units)
    time = 0
    fuel_used = 0
    dist = 0

    if output == 'raw':
        print(S.center('Altitude', 10), end=' ')
        print(S.center('ROD', 10), end=' ')
        print(S.center('Time', 10), end=' ')
        print(S.center('Fuel Used', 10), end=' ')
        print(S.center('Dist', 10), end=' ')
        print(S.center('Speed', 10))

        print(S.center('(ft)', 10), end=' ')
        print(S.center('(ft/mn)', 10), end=' ')
        print(S.center('(mn)', 10), end=' ')
        f_units = '(' + fuel_units + ')'
        print(S.center(f_units, 10), end=' ')
        print(S.center('(nm)', 10), end=' ')
        print(S.center('(KCAS)', 10))

        # # data for max altitude
        # print S.rjust(locale.format('%.0f', alt_max, True), 7),
        # print S.rjust(locale.format('%.0f', round(ROD / 10.) * 10, True), 10),
        # print S.rjust('%.1f' % (0), 10),
        # print S.rjust('%.1f' % (fuel_used), 10),
        # print S.rjust('%.1f' % (dist), 10),
        # print S.rjust('%3d' % (A.tas2cas(tas, alt_max, temp, temp_units=temp_units)), 10)

    # elif output == 'latex':
    #     # temp = 15 + isa_dev
    #     MSL_line = []
    #     MSL_line.append(str(locale.format('%.0f', weight, True)))
    #     MSL_line.append('0')
    #     MSL_line.append(str(locale.format('%.0f', temp)))
    #     MSL_line.append(str(locale.format('%.0f', A.tas2cas(tas, alt, temp, temp_units=temp_units))))
    #     MSL_line.append(str(locale.format('%.0f', round(ROD / 10.) * 10, True)))
    #     MSL_line.append('0')
    #     MSL_line.append(str(fuel_used))
    #     MSL_line.append(str(dist))
    #
    #     print '&'.join(MSL_line) + '\\\\'
    #     print '\\hline'
    # elif output == 'array':
    #     # no header rows, but make blank array
    #     array = [[alt_max,0,0,0]]

    alts = []
    RODs = []
    times_temp = []
    CASs = []
    dists_temp = []
    fuel_useds_temp = []
    temps = []

    calc_alt = alt_max - alt_interval / 2.
    while alt > 0:
        temp = SA.isa2temp(isa_dev, alt, temp_units=temp_units)
        eas = A.tas2eas(tas, alt)
        drag = FT.eas2drag(eas, weight)
        pwr_level_flt = tas_fts * drag / 550
        thrust_power = pwr_level_flt + FT.Pexcess_vs_roc(weight, ROD)
        prop_eff = PM.prop_eff(prop,
                               thrust_power,
                               rpm,
                               tas,
                               alt,
                               temp,
                               temp_units=temp_units)
        calc_pwr = thrust_power / prop_eff
        #fuel_flow = IO.pwr2ff(calc_pwr, rpm, ff_units = 'lb/hr')
        fuel_flow = calc_pwr * sfc
        # print "Level flt pwr = %.1f, thrust power = %.1f, prop eff = %.3f, fuel flow = %.3f" % (pwr_level_flt, thrust_power, prop_eff, fuel_flow)
        slice_time = alt_interval / rod_fts * -1.
        slice_dist = tas_fts * slice_time
        slice_fuel = fuel_flow * slice_time / 3600
        fuel_used += slice_fuel
        fuel_out = (U.avgas_conv(fuel_used, from_units = 'lb', \
            to_units = fuel_units))
        weight -= slice_fuel
        alt -= alt_interval
        cas_out = A.tas2cas(tas, alt, temp, temp_units=temp_units)
        temp_out = SA.isa2temp(isa_dev, alt)
        time += slice_time / 60.
        dist += slice_dist / 6076.115

        alts.append(alt)
        CASs.append(cas_out)
        RODs.append(ROD)
        times_temp.append(time)
        fuel_useds_temp.append(fuel_out)
        dists_temp.append(dist)
        temps.append(temp_out)

        calc_alt += alt_interval

    alts.reverse()
    CASs.reverse()
    RODs.reverse()
    temps.reverse()

    times = []
    fuel_useds = []
    dists = []

    for n, time in enumerate(times_temp):
        times.append(times_temp[-1] - time)
        fuel_useds.append(fuel_useds_temp[-1] - fuel_useds_temp[n])
        dists.append(dists_temp[-1] - dists_temp[n])

    times.reverse()
    fuel_useds.reverse()
    dists.reverse()

    if output == 'raw':
        for n, alt in enumerate(alts):
            print(S.rjust(locale.format('%.0f', alt, True), 7), end=' ')
            # calculate ROC at the displayed altitude
            print(S.rjust(locale.format('%.0f', RODs[n], True), 10), end=' ')
            print(S.rjust('%.1f' % (times[n]), 10), end=' ')
            print(S.rjust('%.1f' % (fuel_useds[n]), 10), end=' ')
            print(S.rjust('%.1f' % (dists[n]), 10), end=' ')
            print(S.rjust('%3d' % (int(CASs[n])), 10))
    elif output == 'latex':
        for n, alt in enumerate(alts):
            line = []
            line.append(str(locale.format('%.0f', alt, True)))
            line.append(str(locale.format('%.0f', round(temps[n]))))
            line.append(str(locale.format('%.0f', CASs[n])))
            line.append(
                str(locale.format('%.0f',
                                  round(RODs[n] / 10.) * 10, True)))
            line.append(str(locale.format('%.0f', times[n])))
            line.append(str(locale.format('%.1f', fuel_useds[n])))
            line.append(str(locale.format('%.0f', dists[n])))
            print('&' + '&'.join(line) + '\\\\')
            print('\\hline')
    elif output == 'array':
        array = []
        for n, alt in enumerate(alts):
            array.append([alt, times[n], fuel_useds[n], dists[n]])
        return array
 def test_01(self):
     Value = U.speed_conv(1, from_units='kt', to_units='mph')
     Truth = (1852. / 0.3048) / 5280
     self.failUnless(RE(Value, Truth) <= 1e-8)
 def test_05(self):
     Value = U.speed_conv(1, from_units='ft/s', to_units='kt')
     Truth = 3600. / (1852. / 0.3048)
     self.failUnless(RE(Value, Truth) <= 1e-5)
 def test_02(self):
     Value = U.speed_conv(1, from_units='mph', to_units='km/h')
     Truth = (5280 * 0.3048) / 1000
     self.failUnless(RE(Value, Truth) <= 1e-8)
 def test_01(self):
     Value = U.speed_conv(1, from_units='kt', to_units='mph')
     Truth = (1852. / 0.3048) / 5280
     self.assertTrue(RE(Value, Truth) <= 1e-8)
 def test_04(self):
     Value = U.speed_conv(1, from_units='m/s', to_units='ft/s')
     Truth = 1 / 0.3048
     self.failUnless(RE(Value, Truth) <= 1e-8)
Beispiel #54
0
def climb_data(prop, weight = 1800., alt_max = 20000., TO_fuel = 0, TO_dist = 0, \
    fuel_units = 'USG', alt_interval = 500., isa_dev = 0, temp_units = 'C', \
    rv = '8', wing_area = 110., pwr = 'max', pwr_factor=1.0, \
    climb_speed = 'max', output = 'raw'):
    """
    Returns a table of climb performance vs altitude.

    The items in each row of the table are altitude, time, fuel burned and distance.
    Time is in units of minutes, rounded to the nearest half minute.
    Fuel units are selectable, with a default of USG.
    Distances are in nm.
    
    The output may be specified as raw, latex (a LaTeX table for the POH), or array.
    
    pwr may be 'max', 'cc' (cruise climb = 2500 rpm and 25") or 2500 (2500 rpm and full throttle)
    climb_speed may be 'max' (Vy), 'cc' (120 kt to 10,000 ft, then reducing by 4 kt/1000 ft) or
                'norm' (100 kt to 10,000 ft, then reducing by 2 kt/1000 ft)
                
    Note: compared cruise range for all climb speed and power.  The predicted results are all 
          within 1.5 nm of range.  Thus there is no advantage to using anything but Vy and max
          power.
    """
    def _alt2ROC(prop, alt):
        """
        calculate ROC for an altitude
        """
        temp = SA.isa2temp(isa_dev, alt)
        calc_pwr = alt2pwr(alt, rpm=rpm, MP_max=MP_max, temp=temp) * pwr_factor
        cas = alt2roc_speed(alt, climb_speed=climb_speed)
        eas = A.cas2eas(cas, alt)
        ROC = roc(prop, alt, eas, weight, calc_pwr, rpm, rv = rv, \
            wing_area = wing_area)

        return ROC

    alt = 0
    time = 0
    fuel_used = U.avgas_conv(TO_fuel, from_units=fuel_units, to_units='lb')
    weight = weight - fuel_used
    dist = TO_dist
    if pwr == 'max':
        # rpm = 2700
        rpm = 2650
        MP_max = 30
    elif pwr == 'cc':
        rpm = 2500
        MP_max = 25
    elif pwr == 2500:
        rpm = 2500
        MP_max = 30
    else:
        raise ValueError("pwr must be one of 'max', 'cc', or 2500")

    if output == 'raw':
        print(S.center('Altitude', 10), end=' ')
        print(S.center('ROC', 10), end=' ')
        print(S.center('Time', 10), end=' ')
        print(S.center('Fuel Used', 10), end=' ')
        print(S.center('Dist', 10), end=' ')
        print(S.center('Speed', 10))

        print(S.center('(ft)', 10), end=' ')
        print(S.center('(ft/mn)', 10), end=' ')
        print(S.center('(mn)', 10), end=' ')
        f_units = '(' + fuel_units + ')'
        print(S.center(f_units, 10), end=' ')
        print(S.center('(nm)', 10), end=' ')
        print(S.center('(KCAS)', 10))

        # data for MSL
        print(S.rjust(locale.format('%.0f', 0, True), 7), end=' ')
        # calculate ROC at MSL
        print(S.rjust(locale.format('%.0f', round(_alt2ROC(prop, 0) / 10.) * 10, \
            True), 10), end=' ')
        print(S.rjust('%.1f' % (0), 10), end=' ')
        print(S.rjust('%.1f' % (TO_fuel), 10), end=' ')
        print(S.rjust('%.1f' % (TO_dist), 10), end=' ')
        print(S.rjust('%3d' % (alt2roc_speed(0, climb_speed=climb_speed)), 10))

    elif output == 'latex':
        temp = 15 + isa_dev
        MSL_line = []
        MSL_line.append(str(locale.format('%.0f', weight, True)))
        MSL_line.append('0')
        MSL_line.append(str(locale.format('%.0f', temp)))
        MSL_line.append(str(locale.format('%.0f', alt2roc_speed(0, \
            climb_speed = climb_speed))))
        MSL_line.append(str(locale.format('%.0f', round(_alt2ROC(prop, 0) / 10.)\
          * 10, True)))
        MSL_line.append('0')
        MSL_line.append(str(TO_fuel))
        MSL_line.append(str(TO_dist))

        print('&'.join(MSL_line) + '\\\\')
        print('\\hline')
    elif output == 'array':
        # no header rows, but make blank array
        array = [[0, 0, TO_fuel, 0]]

    calc_alt = alt_interval / 2.
    while calc_alt < alt_max:
        temp = SA.isa2temp(isa_dev, calc_alt)
        pwr = alt2pwr(calc_alt, rpm=rpm, MP_max=MP_max, temp=temp)
        calc_pwr = pwr * pwr_factor
        cas = alt2roc_speed(calc_alt, climb_speed=climb_speed)
        eas = A.cas2eas(cas, calc_alt)
        tas = A.cas2tas(cas, calc_alt, temp=temp, temp_units=temp_units)
        tas_fts = U.speed_conv(tas, from_units='kt', to_units='ft/s')
        ROC = roc(prop, calc_alt, eas, weight, calc_pwr, rpm, rv = rv, \
            wing_area = wing_area)
        roc_fts = ROC / 60
        fuel_flow = IO.pwr2ff(pwr, rpm, ff_units='lb/hr')
        slice_time = alt_interval / roc_fts
        slice_dist = tas_fts * slice_time
        slice_fuel = fuel_flow * slice_time / 3600
        fuel_used += slice_fuel
        fuel_out = (U.avgas_conv(fuel_used, from_units = 'lb', \
            to_units = fuel_units))
        weight -= slice_fuel
        alt += alt_interval
        cas_out = alt2roc_speed(alt, climb_speed=climb_speed)
        temp_out = SA.isa2temp(isa_dev, alt)
        ROC = _alt2ROC(prop, alt)
        time += slice_time / 60
        dist += slice_dist / 6076.115

        if output == 'raw':
            print(S.rjust(locale.format('%.0f', alt, True), 7), end=' ')
            # calculate ROC at the displayed altitude
            print(S.rjust(locale.format('%.0f', ROC, True), 10), end=' ')
            print(S.rjust('%.1f' % (time), 10), end=' ')
            print(S.rjust('%.1f' % (fuel_out), 10), end=' ')
            print(S.rjust('%.1f' % (dist), 10), end=' ')
            print(S.rjust('%3d' % (int(cas_out)), 10))
        elif output == 'latex':
            line = []
            line.append(str(locale.format('%.0f', alt, True)))
            line.append(str(locale.format('%.0f', round(temp_out))))
            line.append(str(locale.format('%.0f', cas_out)))
            line.append(str(locale.format('%.0f',
                                          round(ROC / 10.) * 10, True)))
            line.append(str(locale.format('%.0f', time)))
            line.append(str(locale.format('%.1f', fuel_out)))
            line.append(str(locale.format('%.0f', dist)))
            print('&' + '&'.join(line) + '\\\\')
            print('\\hline')
        elif output == 'array':
            array.append([alt, time, fuel_out, dist])
        calc_alt += alt_interval
    if output == 'array':
        return array
def climb_data(prop, weight = 1800., alt_max = 20000., TO_fuel = 0, TO_dist = 0, \
    fuel_units = 'USG', alt_interval = 500., isa_dev = 0, temp_units = 'C', \
    rv = '8', wing_area = 110., pwr = 'max', pwr_factor=1.0, \
    climb_speed = 'max', output = 'raw'):
    """
    Returns a table of climb performance vs altitude.

    The items in each row of the table are altitude, time, fuel burned and distance.
    Time is in units of minutes, rounded to the nearest half minute.
    Fuel units are selectable, with a default of USG.
    Distances are in nm.
    
    The output may be specified as raw, latex (a LaTeX table for the POH), or array.
    
    pwr may be 'max', 'cc' (cruise climb = 2500 rpm and 25") or 2500 (2500 rpm and full throttle)
    climb_speed may be 'max' (Vy), 'cc' (120 kt to 10,000 ft, then reducing by 4 kt/1000 ft) or
                'norm' (100 kt to 10,000 ft, then reducing by 2 kt/1000 ft)
                
    Note: compared cruise range for all climb speed and power.  The predicted results are all 
          within 1.5 nm of range.  Thus there is no advantage to using anything but Vy and max
          power.
    """
    def _alt2ROC(prop, alt):
        """
        calculate ROC for an altitude
        """
        temp = SA.isa2temp(isa_dev, alt)
        calc_pwr = alt2pwr(alt, rpm = rpm, MP_max = MP_max, temp = temp) * pwr_factor
        cas = alt2roc_speed(alt, climb_speed = climb_speed)
        eas = A.cas2eas(cas, alt)
        ROC = roc(prop, alt, eas, weight, calc_pwr, rpm, rv = rv, \
            wing_area = wing_area)
        
        return ROC
    
    alt = 0
    time = 0
    fuel_used = U.avgas_conv(TO_fuel, from_units = fuel_units, to_units = 'lb')
    weight = weight - fuel_used
    dist = TO_dist
    if pwr == 'max':
        # rpm = 2700
        rpm = 2650
        MP_max = 30
    elif pwr == 'cc':
        rpm = 2500
        MP_max = 25
    elif pwr == 2500:
        rpm = 2500
        MP_max = 30
    else:
        raise ValueError, "pwr must be one of 'max', 'cc', or 2500"
    

    if output == 'raw':
        print S.center('Altitude', 10),
        print S.center('ROC', 10),
        print S.center('Time', 10),
        print S.center('Fuel Used', 10),
        print S.center('Dist', 10),
        print S.center('Speed', 10)
        
        print S.center('(ft)', 10),
        print S.center('(ft/mn)', 10),
        print S.center('(mn)', 10),
        f_units = '(' + fuel_units + ')'
        print S.center(f_units, 10),
        print S.center('(nm)', 10),
        print S.center('(KCAS)', 10)
        
        # data for MSL
        print S.rjust(locale.format('%.0f', 0, True), 7),
        # calculate ROC at MSL
        print S.rjust(locale.format('%.0f', round(_alt2ROC(prop, 0) / 10.) * 10, \
            True), 10),
        print S.rjust('%.1f' % (0), 10),
        print S.rjust('%.1f' % (TO_fuel), 10),
        print S.rjust('%.1f' % (TO_dist), 10),
        print S.rjust('%3d' % (alt2roc_speed(0, climb_speed = climb_speed)), 10)

    elif output == 'latex':
        temp = 15 + isa_dev
        MSL_line = []
        MSL_line.append(str(locale.format('%.0f', weight, True)))
        MSL_line.append('0')
        MSL_line.append(str(locale.format('%.0f', temp)))
        MSL_line.append(str(locale.format('%.0f', alt2roc_speed(0, \
            climb_speed = climb_speed))))
        MSL_line.append(str(locale.format('%.0f', round(_alt2ROC(prop, 0) / 10.)\
          * 10, True)))
        MSL_line.append('0')
        MSL_line.append(str(TO_fuel))
        MSL_line.append(str(TO_dist))
        
        print '&'.join(MSL_line) + '\\\\'
        print '\\hline'
    elif output == 'array':
        # no header rows, but make blank array
        array = [[0,0,TO_fuel,0]]
        
    calc_alt = alt_interval / 2.
    while calc_alt < alt_max:
        temp = SA.isa2temp(isa_dev, calc_alt)
        pwr = alt2pwr(calc_alt, rpm = rpm, MP_max = MP_max, temp = temp)
        calc_pwr = pwr * pwr_factor
        cas = alt2roc_speed(calc_alt, climb_speed = climb_speed)
        eas = A.cas2eas(cas, calc_alt)
        tas = A.cas2tas(cas, calc_alt, temp = temp, temp_units = temp_units)
        tas_fts = U.speed_conv(tas, from_units = 'kt', to_units = 'ft/s')
        ROC = roc(prop, calc_alt, eas, weight, calc_pwr, rpm, rv = rv, \
            wing_area = wing_area)
        roc_fts = ROC / 60
        fuel_flow = IO.pwr2ff(pwr, rpm, ff_units = 'lb/hr')
        slice_time = alt_interval / roc_fts
        slice_dist = tas_fts * slice_time
        slice_fuel = fuel_flow * slice_time / 3600
        fuel_used += slice_fuel
        fuel_out = (U.avgas_conv(fuel_used, from_units = 'lb', \
            to_units = fuel_units))
        weight -= slice_fuel
        alt += alt_interval
        cas_out = alt2roc_speed(alt, climb_speed = climb_speed)
        temp_out = SA.isa2temp(isa_dev, alt)
        ROC = _alt2ROC(prop, alt)
        time += slice_time / 60
        dist += slice_dist / 6076.115

        if output == 'raw':
            print S.rjust(locale.format('%.0f', alt, True), 7),
            # calculate ROC at the displayed altitude
            print S.rjust(locale.format('%.0f', ROC, True), 10),
            print S.rjust('%.1f' % (time), 10),
            print S.rjust('%.1f' % (fuel_out), 10),
            print S.rjust('%.1f' % (dist), 10),
            print S.rjust('%3d' % (int(cas_out)), 10)
        elif output == 'latex':
            line = []
            line.append(str(locale.format('%.0f', alt, True)))
            line.append(str(locale.format('%.0f', round(temp_out))))
            line.append(str(locale.format('%.0f', cas_out)))
            line.append(str(locale.format('%.0f', round(ROC / 10.) * 10, True)))
            line.append(str(locale.format('%.0f', time)))
            line.append(str(locale.format('%.1f', fuel_out)))
            line.append(str(locale.format('%.0f', dist)))
            print '&' + '&'.join(line) + '\\\\'
            print '\\hline'
        elif output == 'array':
            array.append([alt, time, fuel_out, dist])
        calc_alt += alt_interval
    if output == 'array':
        return array
 def test_05(self):
     Value = U.speed_conv(1, from_units='ft/s', to_units='kt')
     Truth = 3600. / (1852. / 0.3048)
     self.assertTrue(RE(Value, Truth) <= 1e-8)