def test_logic(types):
    for option_set in [
            types["scalar"],
            types["vector"],
            types["matrix"],
    ]:
        for x in option_set:
            for y in option_set:
                ### Comparisons
                """
                Note: if warnings appear here, they're from `np.array(1) == cas.MX(1)` - 
                sensitive to order, as `cas.MX(1) == np.array(1)` is fine.
                
                However, checking the outputs, these seem to be yielding correct results despite
                the warning sooo...
                """
                x == y  # Warnings coming from here
                x != y  # Warnings coming from here
                x > y
                x >= y
                x < y
                x <= y

                ### Conditionals
                np.where(x > 1, x**2, 0)

                ### Elementwise min/max
                np.fmax(x, y)
                np.fmin(x, y)

    for x in types["all"]:
        np.fabs(x)
        np.floor(x)
        np.ceil(x)
        np.clip(x, 0, 1)
예제 #2
0
def solar_azimuth_angle(latitude, day_of_year, time):
    """
    Azimuth angle of the sun [degrees] for a local observer.
    :param latitude: Latitude [degrees]
    :param day_of_year: Julian day (1 == Jan. 1, 365 == Dec. 31)
    :param time: Time after local solar noon [seconds]
    :return: Solar azimuth angle [degrees] (the compass direction from which the sunlight is coming).
    """

    # Solar azimuth angle (including seasonality, latitude, and time of day)
    # Source: https://www.pveducation.org/pvcdrom/properties-of-sunlight/azimuth-angle
    declination = declination_angle(day_of_year)
    sdec = np.sind(declination)
    cdec = np.cosd(declination)
    slat = np.sind(latitude)
    clat = np.cosd(latitude)
    ctime = np.cosd(time / 86400 * 360)

    elevation = solar_elevation_angle(latitude, day_of_year, time)
    cele = np.cosd(elevation)

    cos_azimuth = (sdec * clat - cdec * slat * ctime) / cele
    cos_azimuth = np.clip(cos_azimuth, -1, 1)

    azimuth_raw = np.arccosd(cos_azimuth)

    is_solar_morning = np.mod(time, 86400) > 43200

    solar_azimuth_angle = np.where(
        is_solar_morning,
        azimuth_raw,
        360 - azimuth_raw
    )

    return solar_azimuth_angle
예제 #3
0
def oswalds_efficiency(
        taper_ratio: float,
        aspect_ratio: float,
        sweep: float = 0.,
        fuselage_diameter_to_span_ratio: float = 0.,
) -> float:
    """
    Computes the Oswald's efficiency factor for a planar, tapered, swept wing.

    Based on "Estimating the Oswald Factor from Basic Aircraft Geometrical Parameters"
    by M. Nita, D. Scholz; Hamburg Univ. of Applied Sciences, 2012.

    Implementation of Section 5 from the above paper.

    Only valid for backwards-swept wings; i.e. 0 <= sweep < 90.

    Args:
        taper_ratio: Taper ratio of the wing (tip_chord / root_chord) [-]
        aspect_ratio: Aspect ratio of the wing (b^2 / S) [-]
        sweep: Wing quarter-chord sweep angle [deg]

    Returns: Oswald's efficiency factor [-]

    """
    sweep = np.clip(sweep, 0, 90)  # TODO input proper analytic continuation

    def f(l):  # f(lambda), given as Eq. 36 in the Nita and Scholz paper (see parent docstring).
        return (
                0.0524 * l ** 4
                - 0.15 * l ** 3
                + 0.1659 * l ** 2
                - 0.0706 * l
                + 0.0119
        )

    delta_lambda = -0.357 + 0.45 * np.exp(-0.0375 * sweep)
    # Eq. 37 in Nita & Scholz.
    # Note: there is a typo in the cited paper; the negative in the exponent was omitted.
    # A bit of thinking about this reveals that this omission must be erroneous.

    e_theo = 1 / (
            1 + f(taper_ratio - delta_lambda) * aspect_ratio
    )

    fuselage_wake_contraction_correction_factor = 1 - 2 * (fuselage_diameter_to_span_ratio) ** 2

    e = e_theo * fuselage_wake_contraction_correction_factor

    return e
예제 #4
0
def scattering_factor(elevation_angle):
    """
    Calculates a scattering factor (a factor that gives losses due to atmospheric scattering at low elevation angles).
    Source: AeroSandbox/studies/SolarPanelScattering
    :param elevation_angle: Angle between the horizon and the sun [degrees]
    :return: Fraction of the light that is not lost to scattering.
    """
    elevation_angle = np.clip(elevation_angle, 0, 90)
    theta = 90 - elevation_angle  # Angle between panel normal and the sun, in degrees

    # # Model 1
    # c = (
    #     0.27891510500505767300438719757949,
    #     -0.015994330894744987481281839336589,
    #     -19.707332432605799255043166340329,
    #     -0.66260979582573353852126274432521
    # )
    # scattering_factor = c[0] + c[3] * theta_rad + cas.exp(
    #     c[1] * (
    #             cas.tan(theta_rad) + c[2] * theta_rad
    #     )
    # )

    # Model 2
    c = (
        -0.04636,
        -0.3171
    )
    scattering_factor = np.exp(
        c[0] * (
                np.tand(theta * 0.999) + c[1] * np.radians(theta)
        )
    )

    # # Model 3
    # p1 = -21.74
    # p2 = 282.6
    # p3 = -1538
    # p4 = 1786
    # q1 = -923.2
    # q2 = 1456
    # x = theta_rad
    # scattering_factor = ((p1*x**3 + p2*x**2 + p3*x + p4) /
    #            (x**2 + q1*x + q2))

    # Keep this:
    # scattering_factor = cas.fmin(cas.fmax(scattering_factor, 0), 1)
    return scattering_factor
예제 #5
0
def length_day(latitude, day_of_year):
    """
    For what length of time is the sun above the horizon on a given day?

    :param latitude: Latitude [degrees]
    :param day_of_year: Julian day (1 == Jan. 1, 365 == Dec. 31)
    :return: Seconds of sunlight in a given day
    """
    dec = declination_angle(day_of_year)

    constant = -np.sind(dec) * np.sind(latitude) / (np.cosd(dec) * np.cosd(latitude))
    constant = np.clip(constant, -1, 1)

    sun_time_nondim = 2 * np.arccos(constant)
    sun_time = sun_time_nondim / (2 * np.pi) * 86400

    return sun_time
예제 #6
0
def optimal_taper_ratio(sweep=0., ) -> float:
    """
    Computes the optimal (minimum-induced-drag) taper ratio for a given quarter-chord sweep angle.

    Based on "Estimating the Oswald Factor from Basic Aircraft Geometrical Parameters"
    by M. Nita, D. Scholz; Hamburg Univ. of Applied Sciences, 2012.

    Only valid for backwards-swept wings; i.e. 0 <= sweep < 90.

    Args:
        sweep: Wing quarter-chord sweep angle [deg]

    Returns: Optimal taper ratio

    """
    sweep = np.clip(sweep, 0, 90)  # TODO input proper analytic continuation
    return 0.45 * np.exp(-0.0375 * sweep)