コード例 #1
0
    def getAppliedForce(self, rocketState, time, environment, CG):
        Aref = self.rocket.Aref
        Mach = AeroParameters.getMachNumber(rocketState, environment)

        # Normal Force --------------------------------------------------------------------------------
        # TODO: Account for rate of pitch/yaw rotation in AOA calculation? Or do separate Pitch/Yaw damping moments?
        AOA = AeroParameters.getTotalAOA(rocketState, environment)
        normalForceCoefficient = AeroFunctions.Barrowman_GetCN(
            AOA, Aref, 0, self.baseArea)

        # Drag Force ---------------------------------------------------------------------------------------------
        #### Skin Friction ####
        skinFrictionDragCoefficient, rollDampingMoment = AeroFunctions.getCylindricalSkinFrictionDragCoefficientAndRollDampingMoment(rocketState, environment, self.length, Mach,  \
            self.surfaceRoughness, self.wettedArea, Aref, self.rocket.finenessRatio, self.rocket.fullyTurbulentBL)

        #### Pressure ####
        pressureDragCoefficient = self._getCd_Pressure(Mach)

        totalDragCoefficient = pressureDragCoefficient + skinFrictionDragCoefficient

        # Damping moments --------------------------------------------------------------------------------------
        # Roll damping due to skin friction
        dampingMoments = rollDampingMoment

        # Combine forces and return total -------------------------------------------------------------------------------------
        return AeroFunctions.forceFromCdCN(rocketState,
                                           environment,
                                           totalDragCoefficient,
                                           normalForceCoefficient,
                                           self.CPLocation,
                                           Aref,
                                           moment=dampingMoments)
コード例 #2
0
    def test_getSubsonicCompressibilityCorrectionFactor(self):
        smooth = True
        Mach = 0.5
        expected = 0.975
        self.assertAlmostEqual(
            AeroFunctions._subSonicSkinFrictionCompressiblityCorrectionFactor(
                Mach, smooth), expected)

        smooth = False
        Mach = 0.5
        expected = 0.97
        self.assertAlmostEqual(
            AeroFunctions._subSonicSkinFrictionCompressiblityCorrectionFactor(
                Mach, smooth), expected)
コード例 #3
0
    def test_CPZ(self):
        force = Vector(0, 1, 0)
        location = Vector(0, 0, 0)
        moment = Vector(1, 0, 0)
        testForce = ForceMomentSystem(force, location, moment)

        expectedCPZ = -1
        calculatedCPZ = AeroFunctions._getCPZ(testForce)
        self.assertAlmostEqual(expectedCPZ, calculatedCPZ)
コード例 #4
0
 def test_BarrowmanGetCN(self):
     AOA = 0.1  #rad
     Aref = 1
     xArea_top = 1
     xArea_bottom = 2
     expected = 0.199666833
     self.assertAlmostEqual(
         AeroFunctions.Barrowman_GetCN(AOA, Aref, xArea_top, xArea_bottom),
         expected)
コード例 #5
0
 def checkSkinFriction(Re,
                       roughness,
                       Mach,
                       expectedCf,
                       fullyTurbulent=True):
     state = createStateWithRe(Re, env, length)
     coeff = AeroFunctions.getSkinFrictionCoefficient(
         state, env, length, Mach, roughness, fullyTurbulent)
     self.assertAlmostEqual(coeff, expectedCf)
コード例 #6
0
 def test_getDragToAxialForceFactor(self):
     # Should be 0 at 0, 1.3 at 17, and 0 at 90
     AOAsToTest = [0, 17, 90]
     AOAsToTest = [math.radians(AOA) for AOA in AOAsToTest]
     results = [
         AeroFunctions.getDragToAxialForceFactor(AOA) for AOA in AOAsToTest
     ]
     expectedResults = [1, 1.3, 0]
     for i in range(3):
         self.assertAlmostEqual(results[i], expectedResults[i], 3)
コード例 #7
0
    def test_BarrowmanCPLocation(self):
        length = 1
        xArea_top = 1
        xArea_bottom = 2
        vol = 1.5

        expected = Vector(0, 0, -0.5)
        assertVectorsAlmostEqual(
            self, expected,
            AeroFunctions.Barrowman_GetCPLocation(length, xArea_top,
                                                  xArea_bottom, vol))

        xArea_top = 1
        xArea_bottom = 1
        expected = Vector(0, 0, -0.5)
        assertVectorsAlmostEqual(
            self, expected,
            AeroFunctions.Barrowman_GetCPLocation(length, xArea_top,
                                                  xArea_bottom, vol))
コード例 #8
0
def computeSubsonicPolyCoeffs(coneHalfAngle):
    ''' 
        Computes coefficients for a power law drag relationship up to Mach 1 (Niskanen Appendix B eq. B.5)
        Pass in half angle in radians
    '''
    gamma = AeroFunctions.getGamma()
    dCd_dMa_M1 = 4 / (gamma + 1) * (1 - 0.5 * math.sin(coneHalfAngle))
    Cd_M1 = math.sin(coneHalfAngle)

    return [Cd_M1, (dCd_dMa_M1 / Cd_M1)]
コード例 #9
0
 def checkSkinFriction(Re,
                       roughness,
                       Mach,
                       finenessRatio,
                       expectedCf,
                       fullyTurbulent=True):
     state = createStateWithRe(Re, env, length)
     coeff, rollDamping = AeroFunctions.getCylindricalSkinFrictionDragCoefficientAndRollDampingMoment(
         state, env, length, Mach, roughness, 1, 1, finenessRatio,
         fullyTurbulent)
     self.assertAlmostEqual(coeff, expectedCf)
     self.assertAlmostEqual(rollDamping.length(), 0)
コード例 #10
0
def computeTransonicPolyCoeffs(coneHalfAngle):
    ''' 
        Computes coefficients for a cubic drag interpolation based on Mach Number b/w Mach 1 and 1.3 (Niskanen Appendix B eq. B.5)
        Pass in half angle in radians
    '''
    gamma = AeroFunctions.getGamma()
    dCd_dMa_M1 = 4 / (gamma + 1) * (1 - 0.5 * math.sin(coneHalfAngle))
    Cd_M1 = math.sin(coneHalfAngle)

    Cd_M13 = getSupersonicPressureDragCoeff_Hoerner(coneHalfAngle, 1.3)
    Cd_M1301 = getSupersonicPressureDragCoeff_Hoerner(coneHalfAngle, 1.301)
    dCd_dMa_M13 = (Cd_M1301 - Cd_M13) / 0.001

    return Interpolation.calculateCubicInterpCoefficients(
        1.0, 1.3, Cd_M1, Cd_M13, dCd_dMa_M1, dCd_dMa_M13)
コード例 #11
0
    def test_BarrowmanCPLocation(self):
        # Check that for a cone, XCP = 0.666 Length
        length = 1
        baseArea = 1
        tipArea = 0
        volume = baseArea * length / 3
        XCP_cone = AeroFunctions.Barrowman_GetCPLocation(
            length, tipArea, baseArea, volume)
        self.assertAlmostEqual(XCP_cone.Z, -0.666666666)

        # Check that for a tangent ogive nosecone, XCP = 0.466 Length
        SimRunner = Simulation("MAPLEAF/Examples/Simulations/test3.mapleaf",
                               silent=True)
        rocket = SimRunner.createRocket()
        rocketNosecone = rocket.stages[0].getComponentsOfType(NoseCone)[0]
        noseconeLength = rocketNosecone.length
        expectedCp = rocketNosecone.position + Vector(
            0, 0, -0.46666 * noseconeLength)
        actualCp = rocketNosecone.CPLocation
        assertVectorsAlmostEqual(self, expectedCp, actualCp, 2)
コード例 #12
0
    def _precomputeGeometry(self):
        self.length = self.baseDiameter * self.aspectRatio
        self.volume = self._getVolume()
        self.planformArea = self._getPlanformArea()
        self.wettedArea = self._getWettedArea()

        # Using Barrowman's method, the CP Location is a constant
        self.baseArea = self.baseDiameter**2 * math.pi / 4
        self.CPLocation = AeroFunctions.Barrowman_GetCPLocation(
            self.length, 0, self.baseArea, self.volume)

        # Precompute coefficients for pressure drag interpolation-------------------------------------------
        #  Niskanen 3.4 and Appendix B
        self.coneHalfAngle = abs(
            math.atan((self.baseDiameter / 2) / self.length))

        self.SubsonicCdPolyCoeffs = computeSubsonicPolyCoeffs(
            self.coneHalfAngle)
        self.TransonicCdPolyCoeffs = computeTransonicPolyCoeffs(
            self.coneHalfAngle)
コード例 #13
0
ファイル: rocket.py プロジェクト: henrystoldt/MAPLEAF
    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