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
def CL_over_Cl(aspect_ratio: float, mach: float = 0., sweep: float = 0.) -> float: """ Returns the ratio of 3D lift coefficient (with compressibility) to 2D lift coefficient (incompressible). :param aspect_ratio: Aspect ratio :param mach: Mach number :param sweep: Sweep angle [deg] :return: """ beta = np.where(1 - mach**2 >= 0, np.fmax(1 - mach**2, 0)**0.5, 0) # return aspect_ratio / (aspect_ratio + 2) # Equivalent to equation in Drela's FVA in incompressible, 2*pi*alpha limit. # return aspect_ratio / (2 + cas.sqrt(4 + aspect_ratio ** 2)) # more theoretically sound at low aspect_ratio eta = 0.95 return aspect_ratio / (2 + np.sqrt(4 + (aspect_ratio * beta / eta)**2 * (1 + (np.tand(sweep) / beta)**2)) ) # From Raymer, Sect. 12.4.1; citing DATCOM
def CL_over_Cl( aspect_ratio: float, mach: float = 0., sweep: float = 0., Cl_is_compressible: bool = True ) -> float: """ Returns the ratio of 3D lift coefficient (with compressibility) to the 2D lift coefficient. Specifically: CL_3D / CL_2D Args: aspect_ratio: The aspect ratio of the wing. mach: The freestream Mach number. sweep: The sweep of the wing, in degrees. To be most accurate, this should be the sweep at the locus of thickest points along the wing. Cl_is_compressible: This flag indicates whether the 2D airfoil data already has compressibility effects modeled. For example: * If this flag is True, this function returns: CL_3D / CL_2D, where CL_2D is the sectional lift coefficient based on the local profile at the freestream mach number. * If this flag is False, this function returns: CL_3D / CL_2D_at_mach_zero, where CL_2D_... is the sectional lift coefficient based on the local profile at mach zero. For most accurate results, set this flag to True, and then model profile characteristics separately. """ prandtl_glauert_beta_squared_ideal = 1 - mach ** 2 # beta_squared = 1 - mach ** 2 beta_squared = np.softmax( prandtl_glauert_beta_squared_ideal, -prandtl_glauert_beta_squared_ideal, hardness=3.0 ) ### Alternate formulations # CL_ratio = aspect_ratio / (aspect_ratio + 2) # Equivalent to equation in Drela's FVA in incompressible, 2*pi*alpha limit. # CL_ratio = aspect_ratio / (2 + np.sqrt(4 + aspect_ratio ** 2)) # more theoretically sound at low aspect_ratio ### Formulation from Raymer, Sect. 12.4.1; citing DATCOM. # Comparison to experiment suggests this is the most accurate. # Symbolically simplified to remove the PG singularity. eta = 0.95 CL_ratio = aspect_ratio / ( 2 + ( 4 + (aspect_ratio ** 2 * beta_squared / eta ** 2) + (np.tand(sweep) * aspect_ratio / eta) ** 2 ) ** 0.5 ) if Cl_is_compressible: CL_ratio = CL_ratio * beta_squared ** 0.5 return CL_ratio