def test_getReynoldsNumber(self): environment = self.environment.getAirProperties(Vector(0,0,0)) self.assertAlmostEqual(AeroParameters.getReynoldsNumber(self.rocketState1, environment, 1), 13701279.02972, 2)
def _getAppliedForce(self, time, state): ''' Get the total force currently being experienced by the rocket, used by self.rigidBody to calculate the rocket's acceleration ''' ### Precomputations and Logging ### environment = self._getEnvironmentalConditions(time, state) # Get and log current air/wind properties rocketInertia = self.getInertia(time, state) # Get and log current rocket inertia if self.derivativeEvaluationLog is not None: self.derivativeEvaluationLog.newLogRow(time) self.derivativeEvaluationLog.logValue("Position(m)", state.position) self.derivativeEvaluationLog.logValue("Velocity(m/s)", state.velocity) ### Component Forces ### if not self.isUnderChute: # Precompute and log Mach = AeroParameters.getMachNumber(state, environment) unitRe = AeroParameters.getReynoldsNumber(state, environment, 1.0) AOA = AeroParameters.getTotalAOA(state, environment) rollAngle = AeroParameters.getRollAngle(state, environment) if self.derivativeEvaluationLog is not None: self.derivativeEvaluationLog.logValue("Mach", Mach) self.derivativeEvaluationLog.logValue("UnitRe", unitRe) self.derivativeEvaluationLog.logValue("AOA(deg)", math.degrees(AOA)) self.derivativeEvaluationLog.logValue("RollAngle(deg)", rollAngle) self.derivativeEvaluationLog.logValue("OrientationQuaternion", state.orientation) self.derivativeEvaluationLog.logValue("AngularVelocity(rad/s)", state.angularVelocity) # This function will be the inherited function CompositeObject.getAppliedForce componentForces = self.getAppliedForce(state, time, environment, rocketInertia.CG) else: # When under chute, neglect forces from other components componentForces = self.recoverySystem.getAppliedForce(state, time, environment, Vector(0,0,-1)) # Log the recovery system's applied force (Normally handled in CompositeObject.getAppliedForce) if hasattr(self.recoverySystem, "forcesLog"): self.recoverySystem.forcesLog.append(componentForces.force) self.recoverySystem.momentsLog.append(componentForces.moment) # Move Force-Moment system to rocket CG componentForces = componentForces.getAt(rocketInertia.CG) ### Gravity ### gravityForce = self.environment.getGravityForce(rocketInertia, state) totalForce = componentForces + gravityForce ### Launch Rail ### totalForce = self.environment.applyLaunchTowerForce(state, time, totalForce) if self.derivativeEvaluationLog is not None: self.derivativeEvaluationLog.logValue("Wind(m/s)", environment.Wind) self.derivativeEvaluationLog.logValue("AirDensity(kg/m^3)", environment.Density) self.derivativeEvaluationLog.logValue("CG(m)", rocketInertia.CG) self.derivativeEvaluationLog.logValue("MOI(kg*m^2)", rocketInertia.MOI) self.derivativeEvaluationLog.logValue("Mass(kg)", rocketInertia.mass) CPZ = AeroFunctions._getCPZ(componentForces) self.derivativeEvaluationLog.logValue("CPZ(m)", CPZ) self.derivativeEvaluationLog.logValue("AeroF(N)", componentForces.force) self.derivativeEvaluationLog.logValue("AeroM(Nm)", componentForces.moment) self.derivativeEvaluationLog.logValue("GravityF(N)", gravityForce.force) self.derivativeEvaluationLog.logValue("TotalF(N)", totalForce.force) return totalForce
def getSkinFrictionCoefficient(state, environment, length, Mach, surfaceRoughness, assumeFullyTurbulent=True): ''' Calculates the skin friction drag coefficient (normalized by wetted area, not cross-sectional area). Uses the methods described in (Barrowman, 1967, pg. 43-48) and in (Niskanen, 2009, pg. 43-46) Used for skin friction calculations for all external rocket components Inputs: * state: (RigidBodyState) * environment: (EnvironmentalConditions) * length: (float) - reference length for the current rocket component, used for Reynolds number calculation * Mach: (float) - current Mach number * surfaceRoughness (float) - micrometers Outputs: * Returns the skin friction coefficient normalized by **wetted area**, must be converted to be normalized by cross-sectional area before summing with other coefficients. ''' Re = AeroParameters.getReynoldsNumber(state, environment, length) smoothSurface = (surfaceRoughness == 0) # True or False if smoothSurface: # Very large (unreachable) number criticalRe = 1e100 else: criticalRe = 51 * (surfaceRoughness / length)**( -1.039) # Eqn 4-7 (Barrowman) # Get skin friction factor (Mach number independent) if Re > criticalRe: # Re is above Critical value # Friction determined by roughness skinFrictionCoefficient = 0.032 * (surfaceRoughness / length)**0.2 elif assumeFullyTurbulent: if Re < 1e4: # Limit for low Reynolds numbers skinFrictionCoefficient = 0.0148 # Eqn 3.81 (Niskanen) - match up with turbulent flow correlation else: # Eqn from Niskanen skinFrictionCoefficient = 1 / ((1.5 * math.log(Re) - 5.6)**2) else: # Laminar / Transitional flow if Re < 1e4: # Limit for low Reynolds numbers skinFrictionCoefficient = 0.01328 # Match up with transitional flow eqn elif Re < 5e5: # Laminar flow skinFrictionCoefficient = 1.328 / math.sqrt( Re) # Eqn 4-2 (Barrowman) else: # Transitional Flow skinFrictionCoefficient = 1 / ( (1.5 * math.log(Re) - 5.6)**2 ) - 1700 / Re # Eqn 4-6 (Barrowman), subtraction term from from Prandtl # Calculate compressibility correction if Mach < 0.9: # Subsonic compressibilityCorrectionFactor = _subSonicSkinFrictionCompressiblityCorrectionFactor( Mach, smoothSurface) elif Mach < 1.1: # Transonic subsonicFactor = _subSonicSkinFrictionCompressiblityCorrectionFactor( Mach, smoothSurface) supersonicFactor = _supersonicSkinFrictionCompressiblityCorrectionFactor( Mach, smoothSurface) # Linearly interpolate in the Mach 0.9-1.1 region - same method as that used in OpenRocket v15.03 compressibilityCorrectionFactor = subsonicFactor + ( (supersonicFactor - subsonicFactor) * (Mach - 0.9) / 0.2) else: # Supersonic compressibilityCorrectionFactor = _supersonicSkinFrictionCompressiblityCorrectionFactor( Mach, smoothSurface) # Return corrected factor return skinFrictionCoefficient * compressibilityCorrectionFactor