Esempio n. 1
0
    def setUp(self):
        self.sandbox = SandBox()
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml')

        # The aircraft c172x does not contain an <input> tag so we need
        # to add one.
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
        self.root = tree.getroot()
        input_tag = et.SubElement(self.root, 'input')
        input_tag.attrib['port']='1137'
        tree.write(self.sandbox('aircraft', aircraft_name,  aircraft_name+'.xml'))

        self.fdm = CreateFDM(self.sandbox)
        self.fdm.set_aircraft_path('aircraft')
        self.fdm.load_script(script_path)
        self.fdm.run_ic()
        self.fdm.hold()

        # Execute JSBSim in a separate thread
        self.cond = threading.Condition()
        self.thread = JSBSimThread(self.fdm, self.cond, 5., time.time())
        self.thread.start()

        # Wait for the thread to be started before connecting a telnet session
        self.cond.acquire()
        self.cond.wait()
        self.tn = telnetlib.Telnet("localhost", 1137)
        self.cond.release()
Esempio n. 2
0
    def test_pitot_angle(self):
        script_name = 'ball_chute.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)

        # Add a Pitot angle to the Cessna 172
        tree, aircraft_name, path_to_jsbsim_aircrafts = CopyAircraftDef(
            script_path, self.sandbox)
        root = tree.getroot()
        pitot_angle_deg = 5.0
        self.addPitotTube(root, 5.0)
        contact_tag = root.find('./ground_reactions/contact')
        contact_tag.attrib['type'] = 'STRUCTURE'
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model('ball')
        pitot_angle = pitot_angle_deg * math.pi / 180.
        weight = fdm['inertia/weight-lbs']
        spring_tag = contact_tag.find('./spring_coeff')
        spring_coeff = float(spring_tag.text)
        print("Weight=%d Spring=%d" % (weight, spring_coeff))
        fdm['ic/h-sl-ft'] = weight / spring_coeff
        fdm['forces/hold-down'] = 1.0
        fdm.run_ic()

        ExecuteUntil(fdm, 10.)

        for i in range(36):
            for j in range(-9, 10):
                angle = math.pi * i / 18.0
                angle2 = math.pi * j / 18.0
                ca2 = math.cos(angle2)
                fdm['atmosphere/wind-north-fps'] = 10. * math.cos(angle) * ca2
                fdm['atmosphere/wind-east-fps'] = 10. * math.sin(angle) * ca2
                fdm['atmosphere/wind-down-fps'] = 10. * math.sin(angle2)
                fdm.run()

                vg = fdm['velocities/vg-fps']
                self.assertAlmostEqual(vg, 0.0, delta=1E-7)

                vt = fdm['velocities/vt-fps']
                self.assertAlmostEqual(vt, 10., delta=1E-7)

                mach = vt / fdm['atmosphere/a-fps']
                P = fdm['atmosphere/P-psf']
                pt = P * math.pow(1 + 0.2 * mach * mach, 3.5)
                psl = fdm['atmosphere/P-sl-psf']
                rhosl = fdm['atmosphere/rho-sl-slugs_ft3']
                A = math.pow((pt - P) / psl + 1.0, 1.0 / 3.5)
                alpha = fdm['aero/alpha-rad']
                beta = fdm['aero/beta-rad']
                vc = math.sqrt(
                    7.0 * psl / rhosl *
                    (A - 1.0)) * math.cos(alpha + pitot_angle) * math.cos(beta)

                self.assertAlmostEqual(fdm['velocities/vc-kts'],
                                       max(0.0, vc) / 1.68781,
                                       delta=1E-7)
Esempio n. 3
0
    def test_fuel_tanks_inertia(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml')

        # The aircraft c172x does not contain an <inertia_factor> tag so we
        # need to add one.
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
        tank_tag = tree.getroot().find('propulsion/tank')
        inertia_factor = et.SubElement(tank_tag, 'inertia_factor')
        inertia_factor.text = '1.0'
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        contents0 = fdm['propulsion/tank/contents-lbs']
        ixx0 = fdm['propulsion/tank/local-ixx-slug_ft2']
        iyy0 = fdm['propulsion/tank/local-iyy-slug_ft2']
        izz0 = fdm['propulsion/tank/local-izz-slug_ft2']

        # Remove half of the tank contents and check that the inertias are
        # updated accordingly
        fdm['propulsion/tank/contents-lbs'] = 0.5*contents0
        contents = fdm['propulsion/tank/contents-lbs']
        ixx = fdm['propulsion/tank/local-ixx-slug_ft2']
        iyy = fdm['propulsion/tank/local-iyy-slug_ft2']
        izz = fdm['propulsion/tank/local-izz-slug_ft2']

        self.assertAlmostEqual(contents, 0.5*contents0, delta=1E-7,
                               msg="The tank content (%f lbs) should be %f lbs" % (contents, 0.5*contents0))
        self.assertAlmostEqual(ixx, 0.5*ixx0, delta=1E-7,
                               msg="The tank inertia Ixx (%f slug*ft^2) should be %f slug*ft^2" % (ixx, 0.5*ixx0))
        self.assertAlmostEqual(iyy, 0.5*iyy0, delta=1E-7,
                               msg="The tank inertia Iyy (%f slug*ft^2) should be %f slug*ft^2" % (iyy, 0.5*iyy0))
        self.assertAlmostEqual(izz, 0.5*izz0, delta=1E-7,
                               msg="The tank inertia Izz (%f slug*ft^2) should be %f slug*ft^2" % (izz, 0.5*izz0))

        # Execute the script and check that the fuel inertias have been updated
        # along with the consumption.
        ExecuteUntil(fdm, 200.0)

        contents = fdm['propulsion/tank/contents-lbs']
        ixx = fdm['propulsion/tank/local-ixx-slug_ft2']
        iyy = fdm['propulsion/tank/local-iyy-slug_ft2']
        izz = fdm['propulsion/tank/local-izz-slug_ft2']

        contents_ratio = contents / contents0
        ixx_ratio = ixx / ixx0
        iyy_ratio = iyy / iyy0
        izz_ratio = izz / izz0

        self.assertAlmostEqual(contents_ratio, ixx_ratio, delta=1E-7,
                               msg="Ixx does not vary as the tank content does\nIxx ratio=%f\nContents ratio=%f" % (ixx_ratio, contents_ratio))
        self.assertAlmostEqual(contents_ratio, iyy_ratio, delta=1E-7,
                               msg="Iyy does not vary as the tank content does\nIyy ratio=%f\nContents ratio=%f" % (iyy_ratio, contents_ratio))
        self.assertAlmostEqual(contents_ratio, izz_ratio, delta=1E-7,
                               msg="Izz does not vary as the tank content does\nIzz ratio=%f\nContents ratio=%f" % (izz_ratio, contents_ratio))
Esempio n. 4
0
    def setUp(self):
        JSBSimTestCase.setUp(self)
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'c1724.xml')

        # Since we will alter the aircraft definition file, we need make a copy
        # of it and of all the files it is refering to.
        self.tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(self.script_path, self.sandbox)
Esempio n. 5
0
    def test_fuel_tanks_inertia(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml')

        # The aircraft c172x does not contain an <inertia_factor> tag so we need
        # to add one.
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
        tank_tag = tree.getroot().find('./propulsion/tank')
        inertia_factor = et.SubElement(tank_tag, 'inertia_factor')
        inertia_factor.text = '1.0'
        tree.write(self.sandbox('aircraft', aircraft_name,  aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        contents0 = fdm.get_property_value('propulsion/tank/contents-lbs')
        ixx0 = fdm.get_property_value('propulsion/tank/local-ixx-slug_ft2')
        iyy0 = fdm.get_property_value('propulsion/tank/local-iyy-slug_ft2')
        izz0 = fdm.get_property_value('propulsion/tank/local-izz-slug_ft2')

        # Remove half of the tank contents and check that the inertias are
        # updated accordingly
        fdm.set_property_value('propulsion/tank/contents-lbs', 0.5*contents0)
        contents = fdm.get_property_value('propulsion/tank/contents-lbs')
        ixx = fdm.get_property_value('propulsion/tank/local-ixx-slug_ft2')
        iyy = fdm.get_property_value('propulsion/tank/local-iyy-slug_ft2')
        izz = fdm.get_property_value('propulsion/tank/local-izz-slug_ft2')

        self.assertTrue(abs(contents-0.5*contents0) < 1E-7,
                        msg="The tank content (%f lbs) should be %f lbs" % (contents, 0.5*contents0))
        self.assertTrue(abs(ixx-0.5*ixx0) < 1E-7,
                        msg="The tank inertia Ixx (%f slug*ft^2) should be %f slug*ft^2" % (ixx, 0.5*ixx0))
        self.assertTrue(abs(iyy-0.5*iyy0) < 1E-7,
                        msg="The tank inertia Iyy (%f slug*ft^2) should be %f slug*ft^2" % (iyy, 0.5*iyy0))
        self.assertTrue(abs(izz-0.5*izz0) < 1E-7,
                        msg="The tank inertia Izz (%f slug*ft^2) should be %f slug*ft^2" % (izz, 0.5*izz0))

        # Execute the script and check that the fuel inertias have been updated
        # along with the consumption.
        ExecuteUntil(fdm, 200.0)

        contents = fdm.get_property_value('propulsion/tank/contents-lbs')
        ixx = fdm.get_property_value('propulsion/tank/local-ixx-slug_ft2')
        iyy = fdm.get_property_value('propulsion/tank/local-iyy-slug_ft2')
        izz = fdm.get_property_value('propulsion/tank/local-izz-slug_ft2')

        contents_ratio = contents / contents0
        ixx_ratio = ixx / ixx0
        iyy_ratio = iyy / iyy0
        izz_ratio = izz / izz0

        self.assertTrue(abs(contents_ratio - ixx_ratio) < 1E-7,
                        msg="Ixx does not vary as the tank content does\nIxx ratio=%f\nContents ratio=%f" % (ixx_ratio, contents_ratio))
        self.assertTrue(abs(contents_ratio - iyy_ratio) < 1E-7,
                        msg="Iyy does not vary as the tank content does\nIyy ratio=%f\nContents ratio=%f" % (iyy_ratio, contents_ratio))
        self.assertTrue(abs(contents_ratio - izz_ratio) < 1E-7,
                        msg="Izz does not vary as the tank content does\nIzz ratio=%f\nContents ratio=%f" % (izz_ratio, contents_ratio))
Esempio n. 6
0
    def test_pitot_angle(self):
        script_name = 'ball_chute.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)

        # Add a Pitot angle to the Cessna 172
        tree, aircraft_name, path_to_jsbsim_aircrafts = CopyAircraftDef(script_path, self.sandbox)
        root = tree.getroot()
        pitot_angle_deg = 5.0
        self.addPitotTube(root, 5.0)
        contact_tag = root.find('./ground_reactions/contact')
        contact_tag.attrib['type'] = 'STRUCTURE'
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model('ball')
        pitot_angle = pitot_angle_deg * math.pi / 180.
        weight = fdm['inertia/weight-lbs']
        spring_tag = contact_tag.find('./spring_coeff')
        spring_coeff = float(spring_tag.text)
        print "Weight=%d Spring=%d" % (weight, spring_coeff)
        fdm['ic/h-sl-ft'] = weight / spring_coeff
        fdm['forces/hold-down'] = 1.0
        fdm.run_ic()

        ExecuteUntil(fdm, 10.)

        for i in xrange(36):
            for j in xrange(-9, 10):
                angle = math.pi * i / 18.0
                angle2 = math.pi * j / 18.0
                ca2 = math.cos(angle2)
                fdm['atmosphere/wind-north-fps'] = 10. * math.cos(angle) * ca2
                fdm['atmosphere/wind-east-fps'] = 10. * math.sin(angle) * ca2
                fdm['atmosphere/wind-down-fps'] = 10. * math.sin(angle2)
                fdm.run()

                vg = fdm['velocities/vg-fps']
                self.assertAlmostEqual(vg, 0.0, delta=1E-7)

                vt = fdm['velocities/vt-fps']
                self.assertAlmostEqual(vt, 10., delta=1E-7)

                mach = vt / fdm['atmosphere/a-fps']
                P = fdm['atmosphere/P-psf']
                pt = P * math.pow(1+0.2*mach*mach, 3.5)
                psl = fdm['atmosphere/P-sl-psf']
                rhosl = fdm['atmosphere/rho-sl-slugs_ft3']
                A = math.pow((pt-P)/psl+1.0, 1.0/3.5)
                alpha = fdm['aero/alpha-rad']
                beta = fdm['aero/beta-rad']
                vc = math.sqrt(7.0*psl/rhosl*(A-1.0))*math.cos(alpha+pitot_angle)*math.cos(beta)

                self.assertAlmostEqual(fdm['velocities/vc-kts'],
                                       max(0.0, vc) / 1.68781, delta=1E-7)
Esempio n. 7
0
    def test_steer_type(self):
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'c1721.xml')
        self.tree, self.aircraft_name, b = CopyAircraftDef(
            self.script_path, self.sandbox)
        root = self.tree.getroot()
        self.max_steer_tag = root.find('ground_reactions/contact/max_steer')

        # Check the fixed type
        self.max_steer_tag.text = '0.0'
        fdm = self.steerType(False, False, False)
        del fdm

        # Check the castered type
        self.max_steer_tag.text = '360.0'
        self.isCastered()

        # Check the steered type
        self.max_steer_tag.text = '10.0'
        fdm = self.steerType(True, False, False)
        fdm['fcs/steer-cmd-norm'] = 0.5
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 5.0)
        del fdm

        bogey_tag = root.find('ground_reactions/contact//max_steer/..')
        castered_tag = et.SubElement(bogey_tag, 'castered')
        castered_tag.text = '1.0'

        # Check that the bogey is castered no matter what is the value
        # of <max_steer>
        self.max_steer_tag.text = '10.0'
        self.isCastered()

        self.max_steer_tag.text = '0.0'
        self.isCastered()

        self.max_steer_tag.text = '360.0'
        self.isCastered()

        # Check the fixed type
        castered_tag.text = '0.0'
        self.max_steer_tag.text = '0.0'
        fdm = self.steerType(False, False, False)
        del fdm

        # Check the steered type
        self.max_steer_tag.text = '10.0'
        self.isSteered()

        # Check the steered type with 360.0
        self.max_steer_tag.text = '360.0'
        self.isSteered()
Esempio n. 8
0
    def setUp(self):
        JSBSimTestCase.setUp(self)

        self.fdm = CreateFDM(self.sandbox)
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'x153.xml')
        self.tree, self.aircraft_name, b = CopyAircraftDef(
            self.script_path, self.sandbox)

        self.aero2wind = np.mat(np.identity(3))
        self.aero2wind[0, 0] *= -1.0
        self.aero2wind[2, 2] *= -1.0
        self.auxilliary = self.fdm.get_auxiliary()
Esempio n. 9
0
    def test_moment(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                       'ball_chute.xml')
        tree, aircraft_name, aircraft_path = CopyAircraftDef(
            script_path, self.sandbox)
        extReact_element = tree.getroot().find('external_reactions')
        moment_element = et.SubElement(extReact_element, 'moment')
        moment_element.attrib['name'] = 'parachute'
        moment_element.attrib['frame'] = 'WIND'
        direction_element = et.SubElement(moment_element, 'direction')
        x_element = et.SubElement(direction_element, 'x')
        x_element.text = '0.2'
        y_element = et.SubElement(direction_element, 'y')
        y_element.text = '0.0'
        z_element = et.SubElement(direction_element, 'z')
        z_element.text = '-1.5'

        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        mDir = np.array([0.2, 0.0, -1.5])
        mDir /= np.linalg.norm(mDir)
        self.assertAlmostEqual(fdm['external_reactions/parachute/l'], mDir[0])
        self.assertAlmostEqual(fdm['external_reactions/parachute/m'], mDir[1])
        self.assertAlmostEqual(fdm['external_reactions/parachute/n'], mDir[2])

        fdm['external_reactions/parachute/magnitude-lbsft'] = -3.5

        while fdm.run():
            Tw2b = fdm.get_auxiliary().get_Tw2b()
            mag = fdm['aero/qbar-psf'] * fdm[
                'fcs/parachute_reef_pos_norm'] * 20.0
            f = Tw2b * np.mat([-1.0, 0.0, 0.0]).T * mag
            self.assertAlmostEqual(fdm['forces/fbx-external-lbs'], f[0, 0])
            self.assertAlmostEqual(fdm['forces/fby-external-lbs'], f[1, 0])
            self.assertAlmostEqual(fdm['forces/fbz-external-lbs'], f[2, 0])

            m = -3.5 * Tw2b * np.mat(mDir).T
            fm = np.cross(self.getLeverArm(fdm, 'parachute'),
                          np.array([f[0, 0], f[1, 0], f[2, 0]]))
            self.assertAlmostEqual(fdm['moments/l-external-lbsft'],
                                   m[0, 0] + fm[0])
            self.assertAlmostEqual(fdm['moments/m-external-lbsft'],
                                   m[1, 0] + fm[1])
            self.assertAlmostEqual(fdm['moments/n-external-lbsft'],
                                   m[2, 0] + fm[2])
Esempio n. 10
0
    def setUp(self):
        self.sandbox = SandBox()
        self.script_path = self.sandbox.path_to_jsbsim_file("scripts", "c1724.xml")

        # Since we will alter the aircraft definition file, we need make a copy
        # of it and of all the files it is refering to.
        self.tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(self.script_path, self.sandbox)
Esempio n. 11
0
    def testIndependenceOfInitialLocation(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts/ball.xml')
        tree, aircraft_name, _ = CopyAircraftDef(script_path, self.sandbox)
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))
        # Alter the initial conditions XML file to force the initial latitude
        # to 90 degrees.
        _, IC_tree, IC_file = self.getElementTrees(script_path)
        IC_root = IC_tree.getroot()
        lat_tag = IC_root.find('latitude')
        psi_tag = IC_root.find('psi')
        alt_tag = IC_root.find('altitude')
        psi_tag.text = '90.0'  # Heading East
        lat_tag.text = '89.9'  # Above the North Pole
        h0 = float(alt_tag.text)
        IC_tree.write(os.path.join('aircraft', aircraft_name, IC_file))

        fdm = self.create_fdm()
        fdm.set_aircraft_path('aircraft')
        self.load_script('ball.xml')
        fdm.run_ic()

        p = fdm['ic/p-rad_sec']
        q = fdm['ic/q-rad_sec']
        r = fdm['ic/r-rad_sec']

        self.delete_fdm()

        # Since the equatorial radius is 70159 ft larger than the polar radius
        # we need to decrease the altitude by the same amount in order to
        # initialize the vehicle at the same radius.
        alt_tag.text = str(h0 - 70159)
        psi_tag.text = '0.0'  # Heading North
        lat_tag.text = '0.0'  # Above equator
        # Longitude at which the polar orbit tested above would cross the equator
        lon_tag = IC_root.find('longitude')
        lon_tag.text = '90.0'
        IC_tree.write(os.path.join('aircraft', aircraft_name, IC_file))

        fdm = self.create_fdm()
        fdm.set_aircraft_path('aircraft')
        self.load_script('ball.xml')
        fdm.run_ic()

        self.assertAlmostEqual(fdm['ic/p-rad_sec'], p)
        self.assertAlmostEqual(fdm['ic/q-rad_sec'], q)
        self.assertAlmostEqual(fdm['ic/r-rad_sec'], r)
Esempio n. 12
0
    def test_moment(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                       'ball_chute.xml')
        tree, aircraft_name, aircraft_path = CopyAircraftDef(script_path,
                                                             self.sandbox)
        extReact_element = tree.getroot().find('external_reactions')
        moment_element = et.SubElement(extReact_element, 'moment')
        moment_element.attrib['name'] = 'parachute'
        moment_element.attrib['frame'] = 'WIND'
        direction_element = et.SubElement(moment_element, 'direction')
        x_element = et.SubElement(direction_element, 'x')
        x_element.text = '0.2'
        y_element = et.SubElement(direction_element, 'y')
        y_element.text = '0.0'
        z_element = et.SubElement(direction_element, 'z')
        z_element.text = '-1.5'

        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        mDir = np.array([0.2, 0.0, -1.5])
        mDir /= np.linalg.norm(mDir)
        self.assertAlmostEqual(fdm['external_reactions/parachute/l'], mDir[0])
        self.assertAlmostEqual(fdm['external_reactions/parachute/m'], mDir[1])
        self.assertAlmostEqual(fdm['external_reactions/parachute/n'], mDir[2])

        fdm['external_reactions/parachute/magnitude-lbsft'] = -3.5

        while fdm.run():
            Tw2b = fdm.get_auxiliary().get_Tw2b()
            mag = fdm['aero/qbar-psf'] * fdm['fcs/parachute_reef_pos_norm']*20.0
            f = Tw2b * np.mat([-1.0, 0.0, 0.0]).T * mag
            self.assertAlmostEqual(fdm['forces/fbx-external-lbs'], f[0, 0])
            self.assertAlmostEqual(fdm['forces/fby-external-lbs'], f[1, 0])
            self.assertAlmostEqual(fdm['forces/fbz-external-lbs'], f[2, 0])

            m = -3.5 * Tw2b * np.mat(mDir).T
            fm = np.cross(self.getLeverArm(fdm,'parachute'),
                          np.array([f[0,0], f[1,0], f[2, 0]]))
            self.assertAlmostEqual(fdm['moments/l-external-lbsft'], m[0, 0] + fm[0])
            self.assertAlmostEqual(fdm['moments/m-external-lbsft'], m[1, 0] + fm[1])
            self.assertAlmostEqual(fdm['moments/n-external-lbsft'], m[2, 0] + fm[2])
Esempio n. 13
0
    def setUp(self):
        JSBSimTestCase.setUp(self)
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'c1724.xml')

        # Since we will alter the aircraft definition file, we need make a copy
        # of it and of all the files it is refering to.
        self.tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(self.script_path, self.sandbox)
Esempio n. 14
0
    def test_CAS_ic(self):
        script_name = 'Short_S23_3.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)

        # Add a Pitot angle to the Short S23
        tree, aircraft_name, path_to_jsbsim_aircrafts = CopyAircraftDef(script_path, self.sandbox)
        self.addPitotTube(tree.getroot(), 5.0)
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        # Read the CAS specified in the IC file
        tree = et.parse(script_path)
        use_element = tree.getroot().find('use')
        IC_file = use_element.attrib['initialize']
        tree = et.parse(os.path.join(path_to_jsbsim_aircrafts,
                                     append_xml(IC_file)))
        vc_tag = tree.getroot().find('./vc')
        VCAS = float(vc_tag.text)
        if 'unit' in vc_tag.attrib and vc_tag.attrib['unit'] == 'FT/SEC':
            VCAS /= 1.68781  # Converts in kts

        # Run the IC and check that the model is initialized correctly
        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        self.assertAlmostEqual(fdm['ic/vc-kts'], VCAS, delta=1E-7)
        self.assertAlmostEqual(fdm['velocities/vc-kts'], VCAS, delta=1E-7)
Esempio n. 15
0
    def testKinematicNoScale(self):
        # Test the <nocale/> feature
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1721.xml')
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
        kinematic_tag = tree.getroot().find('flight_control/channel/kinematic')
        et.SubElement(kinematic_tag, 'noscale')
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model(aircraft_name)

        fdm.load_ic('reset00', True)
        fdm.run_ic()
        fdm['fcs/flap-cmd-norm'] = 12.
        ExecuteUntil(fdm, 2.2)
        self.assertAlmostEqual(fdm['fcs/flap-pos-deg'], 12.)
Esempio n. 16
0
    def testKinematicNoScale(self):
        # Test the <nocale/> feature
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1721.xml')
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
        kinematic_tag = tree.getroot().find('flight_control/channel/kinematic')
        et.SubElement(kinematic_tag, 'noscale')
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model(aircraft_name)

        fdm.load_ic(self.sandbox.path_to_jsbsim_file('aircraft', aircraft_name,
                                                     'reset00'), False)
        fdm.run_ic()
        fdm['fcs/flap-cmd-norm'] = 12.
        ExecuteUntil(fdm, 2.2)
        self.assertAlmostEqual(fdm['fcs/flap-pos-deg'], 12.)
Esempio n. 17
0
    def test_alt_mod_vs_CAS(self):
        script_name = 'Short_S23_3.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)

        # Add a Pitot angle to the Short S23
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
        self.addPitotTube(tree.getroot(), 10.0)
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))
        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model('Short_S23')
        fdm['ic/beta-deg'] = 15.0  # Add some sideslip
        fdm['ic/vc-kts'] = 172.0
        fdm['ic/h-sl-ft'] = 15000.
        self.assertAlmostEqual(fdm['ic/vc-kts'], 172.0, delta=1E-7)
        self.assertAlmostEqual(fdm['ic/beta-deg'], 15.0, delta=1E-7)
        fdm.run_ic()
        self.assertAlmostEqual(fdm['velocities/vc-kts'], 172.0, delta=1E-7)
        self.assertAlmostEqual(fdm['aero/beta-deg'], 15.0, delta=1E-7)
Esempio n. 18
0
    def test_steer_type(self):
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'c1721.xml')
        self.tree, self.aircraft_name, b = CopyAircraftDef(self.script_path,
                                                           self.sandbox)
        root = self.tree.getroot()
        self.max_steer_tag = root.find('ground_reactions/contact/max_steer')

        # Check the fixed type
        self.max_steer_tag.text = '0.0'
        fdm = self.steerType(False, False, False)
        del fdm

        # Check the castered type
        self.max_steer_tag.text = '360.0'
        self.isCastered()

        # Check the steered type
        self.max_steer_tag.text = '10.0'
        fdm = self.steerType(True, False, False)
        fdm['fcs/steer-cmd-norm'] = 0.5
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 5.0)
        del fdm

        bogey_tag = root.find('ground_reactions/contact//max_steer/..')
        castered_tag = et.SubElement(bogey_tag, 'castered')
        castered_tag.text = '1.0'

        # Check that the bogey is castered no matter what is the value
        # of <max_steer>
        self.max_steer_tag.text = '10.0'
        self.isCastered()

        self.max_steer_tag.text = '0.0'
        self.isCastered()

        self.max_steer_tag.text = '360.0'
        self.isCastered()

        # Check the fixed type
        castered_tag.text = '0.0'
        self.max_steer_tag.text = '0.0'
        fdm = self.steerType(False, False, False)
        del fdm

        # Check the steered type
        self.max_steer_tag.text = '10.0'
        self.isSteered()

        # Check the steered type with 360.0
        self.max_steer_tag.text = '360.0'
        self.isSteered()
Esempio n. 19
0
    def setUp(self):
        JSBSimTestCase.setUp(self)

        self.fdm = CreateFDM(self.sandbox)
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'x153.xml')
        self.tree, self.aircraft_name, b = CopyAircraftDef(self.script_path, self.sandbox)

        self.aero2wind = np.mat(np.identity(3));
        self.aero2wind[0,0] *= -1.0
        self.aero2wind[2,2] *= -1.0
        self.auxilliary = self.fdm.get_auxiliary()
Esempio n. 20
0
    def test_grain_tanks_content(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml')
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)

        id = 0
        for tank in tree.getroot().findall('propulsion/tank'):
            grain_config = tank.find('grain_config')
            if grain_config and grain_config.attrib['type'] == 'CYLINDRICAL':
                break
            ++id

        capacity = float(tank.find('capacity').text)
        tank.find('contents').text = str(0.5 * capacity)
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        radius_tag = tank.find('radius')
        radius = float(radius_tag.text)
        if 'unit' in radius_tag.attrib and radius_tag.attrib['unit'] == 'IN':
            radius /= 12.0

        bore_diameter_tag = tank.find('grain_config/bore_diameter')
        bore_radius = 0.5 * float(bore_diameter_tag.text)
        if 'unit' in bore_diameter_tag.attrib and bore_diameter_tag.attrib[
                'unit'] == 'IN':
            bore_radius /= 12.0

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        tank_name = 'propulsion/tank[%g]' % (id, )

        self.assertAlmostEqual(fdm[tank_name + '/contents-lbs'],
                               0.5 * capacity)
        fdm['propulsion/tank/contents-lbs'] = capacity
        mass = capacity / 32.174049  # Converting lbs to slugs
        ixx = 0.5 * mass * (radius * radius + bore_radius * bore_radius)
        self.assertAlmostEqual(fdm[tank_name + 'local-ixx-slug_ft2'], ixx)

        del fdm

        tank.find('contents').text = '0.0'
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        self.assertAlmostEqual(fdm[tank_name + '/contents-lbs'], 0.0)
        fdm['propulsion/tank/contents-lbs'] = capacity
Esempio n. 21
0
    def test_trim_with_actuator_delay(self):
        # This is a regression test that checks that actuators delays are
        # disabled when the trim takes place (GitHub issue #293).
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml')
        aircraft_tree, aircraft_name, _ = CopyAircraftDef(
            script_path, self.sandbox)
        root = aircraft_tree.getroot()
        elevator_actuator = root.find(
            "flight_control/channel/actuator[@name='fcs/elevator-actuator']")
        delay = et.SubElement(elevator_actuator, 'delay')
        delay.text = '0.1'
        aircraft_tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        fdm = self.create_fdm()
        fdm.set_aircraft_path(self.sandbox('aircraft'))
        fdm.load_script(script_path)
        fdm.run_ic()

        while fdm.run():
            if fdm['simulation/trim-completed'] == 1:
                break
Esempio n. 22
0
    def testNorthPoleInitialization(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts/ball.xml')
        tree, aircraft_name, _ = CopyAircraftDef(script_path, self.sandbox)
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))
        # Alter the initial conditions XML file to force the initial latitude
        # to 90 degrees.
        _, IC_tree, IC_file = self.getElementTrees(script_path)
        IC_root = IC_tree.getroot()
        lat_tag = IC_root.find('latitude')
        lat_tag.text = '90.0'
        IC_tree.write(os.path.join('aircraft', aircraft_name, IC_file))

        fdm = self.create_fdm()
        fdm.set_aircraft_path('aircraft')

        fpectl.turnon_sigfpe()
        self.load_script('ball.xml')
        fdm.run_ic()
        self.assertAlmostEqual(fdm['ic/lat-gc-deg'], 90.)

        while fdm['simulation/sim-time-sec'] < 1.:
            fdm.run()
        fpectl.turnoff_sigfpe()
Esempio n. 23
0
    def test_trim_westward(self):
        # This is a regression test after the bug reported in GitHub issue #163
        # which reports a trim failure when the heading is set to 270 degrees or
        # -90 degrees i.e. westward.
        script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                       '737_cruise.xml')
        aircraft_tree, aircraft_name, b = CopyAircraftDef(
            script_path, self.sandbox)
        aircraft_tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        IC_file = self.sandbox('aircraft', aircraft_name, 'cruise_init.xml')
        tree = et.parse(IC_file)
        heading_el = tree.find('psi')
        heading_el.text = '270.0'
        tree.write(IC_file)

        fdm = self.create_fdm()
        fdm.set_aircraft_path(self.sandbox('aircraft'))
        fdm.load_script(script_path)
        fdm.run_ic()

        while fdm['simulation/sim-time-sec'] < 6.0:
            fdm.run()
Esempio n. 24
0
    def test_grain_tanks_content(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml')
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)

        id = 0
        for tank in tree.getroot().findall('propulsion/tank'):
            grain_config = tank.find('grain_config')
            if grain_config and grain_config.attrib['type'] == 'CYLINDRICAL':
                break
            ++id

        capacity = float(tank.find('capacity').text)
        tank.find('contents').text = str(0.5*capacity)
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        radius_tag = tank.find('radius')
        radius = float(radius_tag.text)
        if 'unit' in radius_tag.attrib and radius_tag.attrib['unit'] == 'IN':
            radius /= 12.0

        bore_diameter_tag = tank.find('grain_config/bore_diameter')
        bore_radius = 0.5*float(bore_diameter_tag.text)
        if 'unit' in bore_diameter_tag.attrib and bore_diameter_tag.attrib['unit'] == 'IN':
            bore_radius /= 12.0

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        tank_name = 'propulsion/tank[%g]' % (id,)

        self.assertAlmostEqual(fdm[tank_name+'/contents-lbs'], 0.5*capacity)
        fdm['propulsion/tank/contents-lbs'] = capacity
        mass = capacity / 32.174049  # Converting lbs to slugs
        ixx = 0.5 * mass * (radius * radius + bore_radius*bore_radius)
        self.assertAlmostEqual(fdm[tank_name+'local-ixx-slug_ft2'], ixx)

        del fdm

        tank.find('contents').text = '0.0'
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        fdm.run_ic()

        self.assertAlmostEqual(fdm[tank_name+'/contents-lbs'], 0.0)
        fdm['propulsion/tank/contents-lbs'] = capacity
Esempio n. 25
0
    def BuildReference(self, script_name):
        # Run the script
        self.script = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.sandbox.delete_csv_files()
        fdm = CreateFDM(self.sandbox)
        fdm.set_output_directive(
            self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))
        fdm.load_script(self.script)
        fdm['simulation/randomseed'] = 0.0

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

        self.ref = pd.read_csv("output.csv", index_col=0)

        # Since the script will work with modified versions of the aircraft XML
        # definition file, we need to make a copy of the directory that
        # contains all the input data of that aircraft

        tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(
            self.script, self.sandbox)
        self.aircraft_path = os.path.join('aircraft', self.aircraft_name)
Esempio n. 26
0
    def test_point_mass_inertia(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml')
        fdm = CreateFDM(self.sandbox)
        fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests',
                                                                  'output.xml'))
        fdm.load_script(script_path)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

        ref = Table()
        ref.ReadCSV(self.sandbox("output.csv"))

        tree, aircraft_name, path_to_jsbsim_aircrafts = CopyAircraftDef(script_path, self.sandbox)

        pointmass_element = tree.getroot().find('mass_balance/pointmass//form/..')
        weight_element = pointmass_element.find('weight')
        weight = float(weight_element.text)
        form_element = pointmass_element.find('form')
        radius_element = form_element.find('radius')
        radius, length = (0.0, 0.0)
        if radius_element is not None:
            radius = float(radius_element.text)
        length_element = form_element.find('length')
        if length_element is not None:
            length = float(length_element.text)
        shape = form_element.attrib['shape']
        pointmass_element.remove(form_element)

        inertia = numpy.zeros((3,3))
        if string.strip(shape) == 'tube':
            inertia[0,0] = radius * radius
            inertia[1,1] = (6.0 * inertia[0,0] + length * length) / 12.0
            inertia[2,2] = inertia[1,1]

        inertia = inertia * weight / 32.174049 # conversion between slug and lb

        ixx_element = et.SubElement(pointmass_element, 'ixx')
        ixx_element.text = str(inertia[0,0])
        iyy_element = et.SubElement(pointmass_element, 'iyy')
        iyy_element.text = str(inertia[1,1])
        izz_element = et.SubElement(pointmass_element, 'izz')
        izz_element.text = str(inertia[2,2])

        tree.write(self.sandbox('aircraft', aircraft_name, aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests',
                                                                  'output.xml'))
        fdm.load_script(script_path)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

        mod = Table()
        mod.ReadCSV(self.sandbox("output.csv"))

        diff = ref.compare(mod)
        self.assertTrue(diff.empty(),
                        msg='\n'+repr(diff))
Esempio n. 27
0
class TestAeroFuncFrame(JSBSimTestCase):
    def setUp(self):
        JSBSimTestCase.setUp(self)

        self.fdm = CreateFDM(self.sandbox)
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'x153.xml')
        self.tree, self.aircraft_name, b = CopyAircraftDef(self.script_path, self.sandbox)

        self.aero2wind = np.mat(np.identity(3));
        self.aero2wind[0,0] *= -1.0
        self.aero2wind[2,2] *= -1.0
        self.auxilliary = self.fdm.get_auxiliary()

    def tearDown(self):
        del self.fdm
        JSBSimTestCase.tearDown(self)

    def getTs2b(self):
        alpha = self.fdm['aero/alpha-rad']
        ca = math.cos(alpha)
        sa = math.sin(alpha)
        Ts2b = np.mat([[ca, 0., -sa],
                       [0., 1., 0.],
                       [sa, 0., ca]])
        return Ts2b

    def checkForcesAndMoments(self, getForces, getMoment, aeroFunc):
        self.fdm.load_script(self.script_path)
        self.fdm.run_ic()

        rp = np.mat([self.fdm['metrics/aero-rp-x-in'],
                     -self.fdm['metrics/aero-rp-y-in'],
                     self.fdm['metrics/aero-rp-z-in']])
        result = {}

        while self.fdm.run():
            for axis in aeroFunc.keys():
                result[axis] = 0.0

                for func in aeroFunc[axis]:
                    result[axis] += self.fdm[func]

            Fa, Fb = getForces(result)
            Tb2s = self.getTs2b().T
            Fs = self.aero2wind * (Tb2s * Fb)

            Mb_MRC = getMoment(result)
            cg = np.mat([self.fdm['inertia/cg-x-in'],
                         -self.fdm['inertia/cg-y-in'],
                         self.fdm['inertia/cg-z-in']])
            arm_ft = (cg - rp)/12.0 # Convert from inches to ft
            Mb = Mb_MRC + np.cross(arm_ft, Fb.T)
            Tb2w = self.auxilliary.get_Tb2w()
            Mw = Tb2w * Mb.T
            Ms = Tb2s * Mb.T

            self.assertAlmostEqual(Fa[0,0], self.fdm['forces/fwx-aero-lbs'])
            self.assertAlmostEqual(Fa[1,0], self.fdm['forces/fwy-aero-lbs'])
            self.assertAlmostEqual(Fa[2,0], self.fdm['forces/fwz-aero-lbs'])
            self.assertAlmostEqual(Fb[0,0], self.fdm['forces/fbx-aero-lbs'])
            self.assertAlmostEqual(Fb[1,0], self.fdm['forces/fby-aero-lbs'])
            self.assertAlmostEqual(Fb[2,0], self.fdm['forces/fbz-aero-lbs'])
            self.assertAlmostEqual(Fs[0,0], self.fdm['forces/fsx-aero-lbs'])
            self.assertAlmostEqual(Fs[1,0], self.fdm['forces/fsy-aero-lbs'])
            self.assertAlmostEqual(Fs[2,0], self.fdm['forces/fsz-aero-lbs'])
            self.assertAlmostEqual(Mb[0,0], self.fdm['moments/l-aero-lbsft'])
            self.assertAlmostEqual(Mb[0,1], self.fdm['moments/m-aero-lbsft'])
            self.assertAlmostEqual(Mb[0,2], self.fdm['moments/n-aero-lbsft'])
            self.assertAlmostEqual(Ms[0,0], self.fdm['moments/roll-stab-aero-lbsft'])
            self.assertAlmostEqual(Ms[1,0], self.fdm['moments/pitch-stab-aero-lbsft'])
            self.assertAlmostEqual(Ms[2,0], self.fdm['moments/yaw-stab-aero-lbsft'])
            self.assertAlmostEqual(Mw[0,0], self.fdm['moments/roll-wind-aero-lbsft'])
            self.assertAlmostEqual(Mw[1,0], self.fdm['moments/pitch-wind-aero-lbsft'])
            self.assertAlmostEqual(Mw[2,0], self.fdm['moments/yaw-wind-aero-lbsft'])

    def checkAerodynamicsFrame(self, newAxisName, getForces, getMoment, frame):
        aeroFunc = {}

        for axis in self.tree.findall('aerodynamics/axis'):
            axisName = newAxisName[axis.attrib['name']]
            axis.attrib['name'] = axisName
            if frame:
                axis.attrib['frame'] = frame
            aeroFunc[axisName] = []

            for func in axis.findall('function'):
                aeroFunc[axisName].append(func.attrib['name'])

                if (frame == 'BODY' or len(frame) == 0) and (axisName == 'X' or axisName == 'Z'):
                    # Convert the signs of X and Z forces so that the force
                    # along X is directed backward and the force along Z is
                    # directed upward.
                    product_tag = func.find('product')
                    value_tag = et.SubElement(product_tag, 'value')
                    value_tag.text = '-1.0'

        self.tree.write(self.sandbox('aircraft', self.aircraft_name,
                                     self.aircraft_name+'.xml'))
        self.fdm.set_aircraft_path('aircraft')

        self.checkForcesAndMoments(getForces, getMoment, aeroFunc)

    def checkBodyFrame(self, frame):
        newAxisName = {'DRAG': 'X', 'SIDE': 'Y', 'LIFT': 'Z',
                       'ROLL': 'ROLL', 'PITCH': 'PITCH', 'YAW': 'YAW'}

        def getForces(result):
            Tb2w = self.auxilliary.get_Tb2w()
            Fb = np.mat([result['X'], result['Y'], result['Z']]).T
            Fw = Tb2w * Fb
            Fa = self.aero2wind * Fw
            return Fa, Fb

        def getMoment(result):
            return np.mat([result['ROLL'], result['PITCH'], result['YAW']])

        self.checkAerodynamicsFrame(newAxisName, getForces, getMoment, '')

    def testBodyFrame(self):
        self.checkBodyFrame('')

    def testBodyFrameAltSyntax(self):
        self.checkBodyFrame('BODY')

    def testAxialFrame(self):
        newAxisName = {'DRAG': 'AXIAL', 'SIDE': 'SIDE', 'LIFT': 'NORMAL',
                       'ROLL': 'ROLL', 'PITCH': 'PITCH', 'YAW': 'YAW'}

        def getForces(result):
            Tb2w = self.auxilliary.get_Tb2w()
            Fnative = np.mat([result['AXIAL'], result['SIDE'], result['NORMAL']]).T
            Fb = self.aero2wind * Fnative
            Fw = Tb2w * Fb
            Fa = self.aero2wind * Fw
            return Fa, Fb

        def getMoment(result):
            return np.mat([result['ROLL'], result['PITCH'], result['YAW']])

        self.checkAerodynamicsFrame(newAxisName, getForces, getMoment, '')

    def testWindFrame(self):
        newAxisName = {'DRAG': 'X', 'SIDE': 'Y', 'LIFT': 'Z',
                       'ROLL': 'ROLL', 'PITCH': 'PITCH', 'YAW': 'YAW'}

        def getForces(result):
            Tw2b = self.auxilliary.get_Tw2b()
            Fa = np.mat([result['X'], result['Y'], result['Z']]).T
            Fw = self.aero2wind * Fa
            Fb = Tw2b * Fw
            return Fa, Fb

        def getMoment(result):
            Tw2b = self.auxilliary.get_Tw2b()
            Mw = np.mat([result['ROLL'], result['PITCH'], result['YAW']]).T
            Mb = Tw2b*Mw
            return Mb.T

        self.checkAerodynamicsFrame(newAxisName, getForces, getMoment, 'WIND')

    def testAeroFrame(self):
        aeroFunc = {}

        for axis in self.tree.findall('aerodynamics/axis'):
            axisName = axis.attrib['name']
            aeroFunc[axisName] = []

            for func in axis.findall('function'):
                aeroFunc[axisName].append(func.attrib['name'])

        def getForces(result):
            Tw2b = self.auxilliary.get_Tw2b()
            Fa = np.mat([result['DRAG'], result['SIDE'], result['LIFT']]).T
            Fw = self.aero2wind * Fa
            Fb = Tw2b * Fw
            return Fa, Fb

        def getMoment(result):
            return np.mat([result['ROLL'], result['PITCH'], result['YAW']])

        self.checkForcesAndMoments(getForces, getMoment, aeroFunc)

    def testStabilityFrame(self):
        newAxisName = {'DRAG': 'X', 'SIDE': 'Y', 'LIFT': 'Z',
                       'ROLL': 'ROLL', 'PITCH': 'PITCH', 'YAW': 'YAW'}

        def getForces(result):
            Tb2w = self.auxilliary.get_Tb2w()
            Ts2b = self.getTs2b()
            Fs = np.mat([result['X'], result['Y'], result['Z']]).T
            Fb = Ts2b * (self.aero2wind * Fs)
            Fw = Tb2w * Fb
            Fa = self.aero2wind * Fw
            return Fa, Fb

        def getMoment(result):
            Ts2b = self.getTs2b()
            Ms = np.mat([result['ROLL'], result['PITCH'], result['YAW']]).T
            Mb = Ts2b*Ms
            return Mb.T

        self.checkAerodynamicsFrame(newAxisName, getForces, getMoment, 'STABILITY')
Esempio n. 28
0
            sys.exit(-1)

sandbox = SandBox()

# First, the execution time of the script c1724.xml is measured. It will be used
# as a reference to check if JSBSim hangs or not.
script_path = sandbox.path_to_jsbsim_file('scripts', 'c1724.xml')
fdm = CreateFDM(sandbox)
start_time = time.time()
ScriptExecution(fdm, script_path)
exec_time = time.time() - start_time

# Since we will alter the aircraft definition file, we need make a copy of it
# and all the files it is refering to.

tree, aircraft_name, path_to_jsbsim_aircrafts = CopyAircraftDef(script_path, sandbox)

# Now the copy of the aircraft definition file will be altered: the <rate_limit>
# element is split in two: one with sense 'decr', the other with sense 'incr'.
actuator_element = tree.getroot().find('flight_control/channel/actuator//rate_limit/..')
rate_element = actuator_element.find('rate_limit')
rate_element.attrib['sense'] = 'decr'
new_rate_element = et.SubElement(actuator_element, 'rate_limit')
new_rate_element.attrib['sense'] = 'incr'
new_rate_element.text = str(float(rate_element.text) * 0.5)

tree.write(sandbox('aircraft', aircraft_name, aircraft_name+'.xml'))

# Run the script with the modified aircraft
fdm = CreateFDM(sandbox)
fdm.set_aircraft_path('aircraft')
Esempio n. 29
0
class CheckFGBug1503(JSBSimTestCase):
    def setUp(self):
        JSBSimTestCase.setUp(self)
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'c1724.xml')

        # Since we will alter the aircraft definition file, we need make a copy
        # of it and of all the files it is refering to.
        self.tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(self.script_path, self.sandbox)

    def ScriptExecution(self, fdm, time_limit=1E+9):
        fdm.load_script(self.script_path)
        fdm.run_ic()

        while fdm.run() and fdm.get_sim_time() < time_limit:
            aileron_pos = fdm['fcs/left-aileron-pos-rad']
            self.assertEqual(aileron_pos, 0.0,
                            msg="Failed running the script %s at time step %f\nProperty fcs/left-aileron-pos-rad is non-zero (%f)" % (self.script_path, fdm.get_sim_time(), aileron_pos))

    def SubProcessScriptExecution(self, sandbox, script_path, aircraft_path, time_limit):
        self.script_path = script_path
        self.sandbox = sandbox
        fdm = CreateFDM(sandbox)
        fdm.set_aircraft_path(aircraft_path)
        self.ScriptExecution(fdm, time_limit)

    def CheckRateValue(self, fdm, output_prop, rate_value):
        aileron_course = []

        t0 = fdm.get_sim_time()
        while fdm.run() and fdm.get_sim_time() <= t0 + 1.0:
            aileron_course += [(fdm.get_sim_time(), fdm[output_prop])]

        # Thanks to a linear regression on the values, we can check that the
        # value is following a slope equal to the rate limit. The correlation
        # coefficient r_value is also checked to verify that the output is
        # evolving linearly.
        slope, intercept, r_value, p_value, std_err = stats.linregress(aileron_course)
        self.assertTrue(abs(slope - rate_value) < 1E-9 and abs(1.0 - abs(r_value)) < 1E-9,
                        msg="The actuator rate is not linear")

    def CheckRateLimit(self, input_prop, output_prop, incr_limit, decr_limit):
        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')

        self.ScriptExecution(fdm, 1.0)

        fdm[input_prop] = 1.0

        self.CheckRateValue(fdm, output_prop, incr_limit)

        fdm[input_prop] = 0.0
        self.CheckRateValue(fdm, output_prop, decr_limit)

        # Because JSBSim internals use static pointers, we cannot rely on
        # Python garbage collector to decide when the FDM is destroyed
        # otherwise we can get dangling pointers.
        del fdm

    def test_regression_bug_1503(self):
        # First, the execution time of the script c1724.xml is measured. It
        # will be used as a reference to check if JSBSim hangs or not.
        fdm = CreateFDM(self.sandbox)
        start_time = time.time()
        self.ScriptExecution(fdm)
        exec_time = time.time() - start_time
        del fdm

        # Now the copy of the aircraft definition file will be altered: the
        # <rate_limit> element is split in two: one with the 'decr' sense, the
        # other with 'incr' sense.
        actuator_element = self.tree.getroot().find('flight_control/channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        rate_element.attrib['sense'] = 'decr'
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = str(float(rate_element.text) * 0.5)

        self.tree.write(self.sandbox('aircraft', self.aircraft_name,
                                     self.aircraft_name+'.xml'))

        # Run the script with the modified aircraft
        aircraft_path = 'aircraft'

        # A new process is created that launches the script. We wait for 10
        # times the reference execution time for the script completion. Beyond
        # that time, if the process is not completed, it is terminated and the
        # test is failed.
        p = Process(target=SubProcessScriptExecution, args=(self.sandbox, self.script_path, aircraft_path,))
        p.start()
        p.join(exec_time * 10.0)  # Wait 10 times the reference time
        alive = p.is_alive()
        if alive:
            p.terminate()
        self.assertFalse(alive, msg="The script has hung")

    def test_actuator_rate_from_property(self):
        # Second part of the test.
        # #######################
        #
        # The test is run again but this time, <rate_limit> will be read from a
        # property instead of being read from a value hard coded in the
        # aircraft definition file. It has been reported in the bug 1503 of
        # FlightGear that for such a configuration the <actuator> output is
        # constantly increasing even if the input is null. For this script the
        # <actuator> output is stored in the property
        # fcs/left-aileron-pos-rad. The function ScriptExecution will monitor
        # that property and if it changes then the test is failed.

        tree = et.parse(os.path.join(self.path_to_jsbsim_aircrafts, self.aircraft_name+'.xml'))
        actuator_element = tree.getroot().find('flight_control/channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        flight_control_element = tree.getroot().find('flight_control')
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value'
        property.attrib['value'] = rate_element.text
        actuator_element = flight_control_element.find('channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        rate_element.attrib['sense'] = 'decr'
        rate_element.text = property.text
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = rate_element.text

        tree.write(self.sandbox('aircraft', self.aircraft_name, self.aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        self.ScriptExecution(fdm)
        del fdm

    def test_actuator_rate_is_linear(self):
        # Third part of the test.
        ########################
        #
        # The test is run again but this time we are checking that rate_limit
        # drives the actuator output value as expected. The idea is to store
        # the output value of the actuator output vs the time and check with a
        # linear regression that
        # 1. The actuator output value is evolving linearly
        # 2. The slope of the actuator output is equal to the rate_limit value
        # The test is run with the rate_limit given by a value, a property,
        # different values of the ascending and descending rates and a number
        # of combinations thereof.

        # The aircraft file definition is modified such that the actuator
        # element input is driven by a unique property. The name of this unique
        # property is built in the variable 'input_prop' below. When setting
        # that property to 1.0 (resp. -1.0) the ascending (resp. descending)
        # rate is triggered.
        tree = et.parse(os.path.join(self.path_to_jsbsim_aircrafts,
                                     self.aircraft_name+'.xml'))
        flight_control_element = tree.getroot().find('flight_control')
        actuator_element = flight_control_element.find('channel/actuator//rate_limit/..')

        # Remove the hysteresis. We want to make sure we are measuring the
        # rate_limit and just that.
        hysteresis_element = actuator_element.find('hysteresis')
        actuator_element.remove(hysteresis_element)
        input_element = actuator_element.find('input')
        input_prop = actuator_element.attrib['name'].split('-')
        input_prop[-1] = 'input'
        input_prop = '-'.join(input_prop)
        input_element.text = input_prop
        output_element = actuator_element.find('output')
        output_prop = output_element.text.strip()

        # Add the new properties to <flight_control> so that we can make
        # reference to them without JSBSim complaining
        property = et.SubElement(flight_control_element, 'property')
        property.text = input_prop
        property.attrib['value'] = '0.0'
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value'
        property.attrib['value'] = '0.15'
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value2'
        property.attrib['value'] = '0.05'

        # First check with rate_limit set to 0.1

        rate_element = actuator_element.find('rate_limit')
        rate_element.text = '0.1'

        output_file = os.path.join('aircraft', self.aircraft_name,
                                   self.aircraft_name+'.xml')
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.1, -0.1)

        # Check when rate_limit is set by the property 'fcs/rate-limit-value'

        tree = et.parse(output_file)
        flight_control_element = tree.getroot().find('flight_control')
        actuator_element = flight_control_element.find('channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.15, -0.15)

        # Checking when the ascending and descending rates are different.
        # First with the 2 rates set by hard coded values (0.1 and 0.2
        # respectively)

        rate_element.attrib['sense'] = 'decr'
        rate_element.text = '0.1'
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = '0.2'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.2, -0.1)

        # Check when the descending rate is set by a property and the ascending
        # rate is set by a value.

        rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.2, -0.15)

        # Check when the ascending rate is set by a property and the descending
        # rate is set by a value.

        rate_element.text = '0.1'
        new_rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.15, -0.1)

        # Check when the ascending and descending rates are set by properties

        rate_element.text = 'fcs/rate-limit-value2'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.15, -0.05)
Esempio n. 30
0
class TestActuator(JSBSimTestCase):
    def setUp(self):
        JSBSimTestCase.setUp(self)
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'c1724.xml')

        # Since we will alter the aircraft definition file, we need make a copy
        # of it and of all the files it is refering to.
        self.tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(
            self.script_path, self.sandbox)

    def ScriptExecution(self, fdm, time_limit=1E+9):
        fdm.load_script(self.script_path)
        fdm.run_ic()

        while fdm.run() and fdm.get_sim_time() < time_limit:
            aileron_pos = fdm['fcs/left-aileron-pos-rad']
            self.assertEqual(
                aileron_pos,
                0.0,
                msg=
                "Failed running the script %s at time step %f\nProperty fcs/left-aileron-pos-rad is non-zero (%f)"
                % (self.script_path, fdm.get_sim_time(), aileron_pos))

    def CheckRateValue(self, fdm, rate_value):
        aileron_course = []

        t0 = fdm.get_sim_time()
        while fdm.run() and fdm.get_sim_time() <= t0 + 1.0:
            aileron_course += [(fdm.get_sim_time(), fdm[self.output_prop])]

        # Thanks to a linear regression on the values, we can check that the
        # value is following a slope equal to the rate limit. The correlation
        # coefficient r_value is also checked to verify that the output is
        # evolving linearly.
        slope, intercept, r_value, p_value, std_err = stats.linregress(
            aileron_course)
        self.assertTrue(abs(slope - rate_value) < 1E-9
                        and abs(1.0 - abs(r_value)) < 1E-9,
                        msg="The actuator rate is not linear")

    def CheckRateLimit(self, incr_limit, decr_limit):
        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')

        self.ScriptExecution(fdm, 1.0)

        fdm[self.input_prop] = 1.0
        self.CheckRateValue(fdm, incr_limit)

        fdm[self.input_prop] = 0.0
        self.CheckRateValue(fdm, decr_limit)

        # Because JSBSim internals use static pointers, we cannot rely on
        # Python garbage collector to decide when the FDM is destroyed
        # otherwise we can get dangling pointers.
        del fdm

    def test_regression_bug_1503(self):
        # First, the execution time of the script c1724.xml is measured. It
        # will be used as a reference to check if JSBSim hangs or not.
        fdm = CreateFDM(self.sandbox)
        start_time = time.time()
        self.ScriptExecution(fdm)
        exec_time = time.time() - start_time

        # Delete the FDM instance to make sure that all files are closed and
        # released before running the same script in another process.
        del fdm

        # Now the copy of the aircraft definition file will be altered: the
        # <rate_limit> element is split in two: one with the 'decr' sense, the
        # other with 'incr' sense.
        actuator_element = self.tree.getroot().find(
            'flight_control/channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        rate_element.attrib['sense'] = 'decr'
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = str(float(rate_element.text) * 0.5)

        self.tree.write(
            os.path.join('aircraft', self.aircraft_name,
                         self.aircraft_name + '.xml'))

        # A new process is created that launches the script. We wait for 10
        # times the reference execution time for the script completion. Beyond
        # that time, if the process is not completed, it is terminated and the
        # test is failed.
        p = Process(target=SubProcessScriptExecution,
                    args=(self.sandbox, self.script_path))
        p.start()
        p.join(exec_time * 20.0)  # Wait 20 times the reference time
        alive = p.is_alive()
        if alive:
            p.terminate()
        self.assertFalse(alive, msg="The script has hung")

    def test_actuator_rate_from_property(self):
        # Second part of the test.
        # #######################
        #
        # The test is run again but this time, <rate_limit> will be read from a
        # property instead of being read from a value hard coded in the
        # aircraft definition file. It has been reported in the bug 1503 of
        # FlightGear that for such a configuration the <actuator> output is
        # constantly increasing even if the input is null. For this script the
        # <actuator> output is stored in the property
        # fcs/left-aileron-pos-rad. The function ScriptExecution will monitor
        # that property and if it changes then the test is failed.

        tree = et.parse(
            os.path.join(self.path_to_jsbsim_aircrafts,
                         self.aircraft_name + '.xml'))
        root = tree.getroot()
        flight_control_element = root.find('flight_control')
        actuator_element = flight_control_element.find(
            'channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value'
        property.attrib['value'] = rate_element.text
        rate_element.attrib['sense'] = 'decr'
        rate_element.text = property.text
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = rate_element.text
        output_element = root.find('output')
        output_element.attrib['name'] = 'test.csv'

        tree.write(
            os.path.join('aircraft', self.aircraft_name,
                         self.aircraft_name + '.xml'))

        fdm = self.create_fdm()
        fdm.set_aircraft_path('aircraft')
        self.ScriptExecution(fdm)

    def prepare_actuator(self):
        tree = et.parse(
            os.path.join(self.path_to_jsbsim_aircrafts,
                         self.aircraft_name + '.xml'))
        flight_control_element = tree.getroot().find('flight_control')
        actuator_element = flight_control_element.find(
            'channel/actuator//rate_limit/..')

        # Remove the hysteresis. We want to make sure we are measuring the
        # rate_limit and just that.
        hysteresis_element = actuator_element.find('hysteresis')
        actuator_element.remove(hysteresis_element)
        input_element = actuator_element.find('input')
        self.input_prop = actuator_element.attrib['name'].split('-')
        self.input_prop[-1] = 'input'
        self.input_prop = '-'.join(self.input_prop)
        input_element.text = self.input_prop
        self.output_prop = actuator_element.find('output').text
        property = et.SubElement(flight_control_element, 'property')
        property.text = self.input_prop
        property.attrib['value'] = '0.0'

        return (tree, flight_control_element, actuator_element)

    def test_actuator_rate_is_linear(self):
        # Third part of the test.
        ########################
        #
        # The test is run again but this time we are checking that rate_limit
        # drives the actuator output value as expected. The idea is to store
        # the output value of the actuator output vs the time and check with a
        # linear regression that
        # 1. The actuator output value is evolving linearly
        # 2. The slope of the actuator output is equal to the rate_limit value
        # The test is run with the rate_limit given by a value, a property,
        # different values of the ascending and descending rates and a number
        # of combinations thereof.

        # The aircraft file definition is modified such that the actuator
        # element input is driven by a unique property. The name of this unique
        # property is built in the variable 'input_prop' below. When setting
        # that property to 1.0 (resp. -1.0) the ascending (resp. descending)
        # rate is triggered.
        tree, flight_control_element, actuator_element = self.prepare_actuator(
        )

        # Add the new properties to <flight_control> so that we can make
        # reference to them without JSBSim complaining
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value'
        property.attrib['value'] = '0.15'
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value2'
        property.attrib['value'] = '0.05'

        # First check with rate_limit set to 0.1

        rate_element = actuator_element.find('rate_limit')
        rate_element.text = '0.1'

        output_file = os.path.join('aircraft', self.aircraft_name,
                                   self.aircraft_name + '.xml')
        tree.write(output_file)

        self.CheckRateLimit(0.1, -0.1)

        # Check when rate_limit is set by the property 'fcs/rate-limit-value'

        tree = et.parse(output_file)
        flight_control_element = tree.getroot().find('flight_control')
        actuator_element = flight_control_element.find(
            'channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(0.15, -0.15)

        # Checking when the ascending and descending rates are different.
        # First with the 2 rates set by hard coded values (0.1 and 0.2
        # respectively)

        rate_element.attrib['sense'] = 'decr'
        rate_element.text = '0.1'
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = '0.2'
        tree.write(output_file)

        self.CheckRateLimit(0.2, -0.1)

        # Check when the descending rate is set by a property and the ascending
        # rate is set by a value.

        rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(0.2, -0.15)

        # Check when the ascending rate is set by a property and the descending
        # rate is set by a value.

        rate_element.text = '0.1'
        new_rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(0.15, -0.1)

        # Check when the ascending and descending rates are set by properties

        rate_element.text = 'fcs/rate-limit-value2'
        tree.write(output_file)

        self.CheckRateLimit(0.15, -0.05)

    def CheckClip(self, clipmin, clipmax, rate_limit):
        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()

        fdm[self.input_prop] = 2.0 * clipmax
        dt = clipmax / rate_limit
        while fdm['simulation/sim-time-sec'] <= dt:
            self.assertFalse(fdm[self.saturated_prop])
            fdm.run()

        self.assertTrue(fdm[self.saturated_prop])
        self.assertAlmostEqual(fdm[self.output_prop], clipmax)

        # Check that the actuator output can't go beyond clipmax
        t = fdm['simulation/sim-time-sec']
        while fdm['simulation/sim-time-sec'] <= t + dt:
            fdm.run()
            self.assertTrue(fdm[self.saturated_prop])
            self.assertAlmostEqual(fdm[self.output_prop], clipmax)

        fdm[self.input_prop] = 2.0 * clipmin
        dt = (2.0 * clipmax - clipmin) / rate_limit
        t = fdm['simulation/sim-time-sec']
        while fdm['simulation/sim-time-sec'] <= t + dt:
            if fdm[self.output_prop] < clipmax:
                self.assertFalse(fdm[self.saturated_prop])
            else:
                self.assertTrue(fdm[self.saturated_prop])
            fdm.run()

        self.assertTrue(fdm[self.saturated_prop])
        self.assertAlmostEqual(fdm[self.output_prop], clipmin)

        # Check that the actuator output can't go below clipmin
        t = fdm['simulation/sim-time-sec']
        while fdm['simulation/sim-time-sec'] <= t + dt:
            fdm.run()
            self.assertTrue(fdm[self.saturated_prop])
            self.assertAlmostEqual(fdm[self.output_prop], clipmin)

        fdm[self.input_prop] = 1E-6
        dt = (fdm[self.input_prop] - 2.0 * clipmin) / rate_limit
        t = fdm['simulation/sim-time-sec']
        while fdm['simulation/sim-time-sec'] <= t + 2.0 * dt:
            if fdm[self.output_prop] > clipmin:
                self.assertFalse(fdm[self.saturated_prop])
            else:
                self.assertTrue(fdm[self.saturated_prop])
            fdm.run()

        self.assertAlmostEqual(fdm[self.output_prop], fdm[self.input_prop])

        fdm[self.fail_hardover] = 1.0
        dt = (clipmax - fdm[self.input_prop]) / rate_limit
        t = fdm['simulation/sim-time-sec']
        while fdm['simulation/sim-time-sec'] <= t + dt:
            if fdm[self.output_prop] < clipmax:
                self.assertFalse(fdm[self.saturated_prop])
            else:
                self.assertTrue(fdm[self.saturated_prop])
            fdm.run()

        self.assertTrue(fdm[self.saturated_prop])
        self.assertAlmostEqual(fdm[self.output_prop], clipmax)

        fdm[self.input_prop] = -1E-6
        dt = (clipmax - clipmin) / rate_limit
        t = fdm['simulation/sim-time-sec']
        while fdm['simulation/sim-time-sec'] <= t + dt:
            if fdm[self.output_prop] > clipmin and fdm[
                    self.output_prop] < clipmax:
                self.assertFalse(fdm[self.saturated_prop])
            else:
                self.assertTrue(fdm[self.saturated_prop])
            fdm.run()

        self.assertTrue(fdm[self.saturated_prop])
        self.assertAlmostEqual(fdm[self.output_prop], clipmin)

        del fdm

    def test_clipto(self):
        tree, flight_control_element, actuator_element = self.prepare_actuator(
        )
        rate_limit = float(actuator_element.find('rate_limit').text)
        self.saturated_prop = actuator_element.attrib['name'] + "/saturated"
        self.fail_hardover = actuator_element.attrib[
            'name'] + "/malfunction/fail_hardover"
        clipto = actuator_element.find('clipto')
        clipmax = clipto.find('max')
        clipmin = clipto.find('min')
        output_file = os.path.join('aircraft', self.aircraft_name,
                                   self.aircraft_name + '.xml')
        tree.write(output_file)

        self.CheckClip(float(clipmin.text), float(clipmax.text), rate_limit)

        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/clip-min-value'
        property.attrib['value'] = '-0.15'
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/clip-max-value'
        property.attrib['value'] = '0.05'

        # Check a property for min and a value for max
        clipmin.text = 'fcs/clip-min-value'
        tree.write(output_file)

        self.CheckClip(-0.15, float(clipmax.text), rate_limit)

        # Check a property with minus sign for min and a value for max
        clipmin.text = '-fcs/clip-max-value'
        tree.write(output_file)

        self.CheckClip(-0.05, float(clipmax.text), rate_limit)

        # Check a property for max and a value for min
        clipmin.text = '-0.1'
        clipmax.text = 'fcs/clip-max-value'
        tree.write(output_file)

        self.CheckClip(-0.1, 0.05, rate_limit)

        # Check a property with minus sign for max and a value for min
        clipmax.text = '-fcs/clip-min-value'
        tree.write(output_file)

        self.CheckClip(-0.1, 0.15, rate_limit)

        # Check a property for max and min
        clipmin.text = '-fcs/clip-max-value'
        clipmax.text = 'fcs/clip-max-value'
        tree.write(output_file)

        self.CheckClip(-0.05, 0.05, rate_limit)

        # Check the cyclic clip
        clipmin.text = str(-math.pi)
        clipmax.text = str(math.pi)
        clipto.attrib['type'] = 'cyclic'
        tree.write(output_file)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()

        fdm[self.input_prop] = 2.0 * math.pi
        dt = math.pi / rate_limit
        while fdm['simulation/sim-time-sec'] <= dt:
            self.assertTrue(fdm[self.output_prop] <= math.pi)
            self.assertTrue(fdm[self.output_prop] >= 0.0)
            self.assertAlmostEqual(fdm[self.output_prop],
                                   fdm['simulation/sim-time-sec'] * rate_limit)
            fdm.run()

        while fdm['simulation/sim-time-sec'] <= 2.0 * dt:
            self.assertTrue(fdm[self.output_prop] >= -math.pi)
            self.assertTrue(fdm[self.output_prop] <= 0.0)
            self.assertAlmostEqual(
                fdm[self.output_prop],
                fdm['simulation/sim-time-sec'] * rate_limit - 2.0 * math.pi)
            fdm.run()

        # Check that the output value does not go beyond 0.0
        self.assertAlmostEqual(fdm[self.output_prop], 0.0)
        fdm.run()
        self.assertAlmostEqual(fdm[self.output_prop], 0.0)

        t = fdm['simulation/sim-time-sec']
        fdm[self.input_prop] = -0.5 * math.pi

        while fdm['simulation/sim-time-sec'] <= t + dt:
            self.assertTrue(fdm[self.output_prop] >= -math.pi)
            self.assertTrue(fdm[self.output_prop] <= 0.0)
            self.assertAlmostEqual(fdm[self.output_prop],
                                   (t - fdm['simulation/sim-time-sec']) *
                                   rate_limit)
            fdm.run()

        while fdm['simulation/sim-time-sec'] <= t + 1.5 * dt:
            self.assertTrue(fdm[self.output_prop] <= math.pi)
            self.assertTrue(fdm[self.output_prop] >= -0.5 * math.pi)
            self.assertAlmostEqual(
                fdm[self.output_prop],
                (t - fdm['simulation/sim-time-sec']) * rate_limit +
                2.0 * math.pi)
            fdm.run()

        del fdm

        # Check the cyclic clip handles correctly negative numbers (GH issue
        # #211)
        # Case 1 : The interval is positive
        clipmin.text = '0.0'
        clipmax.text = str(math.pi)
        tree.write(output_file)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()

        fdm[self.input_prop] = -2.0 * math.pi
        t0 = math.pi / rate_limit
        t = fdm['simulation/sim-time-sec']
        while t <= t0:
            self.assertTrue(fdm[self.output_prop] <= math.pi)
            self.assertTrue(fdm[self.output_prop] >= 0.0)
            if t == 0:
                self.assertAlmostEqual(fdm[self.output_prop], 0.0)
            else:
                self.assertAlmostEqual(fdm[self.output_prop],
                                       math.pi - t * rate_limit)
            fdm.run()
            t = fdm['simulation/sim-time-sec']

        while t <= 2.0 * t0:
            self.assertTrue(fdm[self.output_prop] <= math.pi)
            self.assertTrue(fdm[self.output_prop] >= 0.0)
            self.assertAlmostEqual(fdm[self.output_prop],
                                   math.pi - (t - t0) * rate_limit)
            fdm.run()
            t = fdm['simulation/sim-time-sec']

        del fdm

        # Case 2 : The interval is negative
        clipmin.text = str(-math.pi)
        clipmax.text = '0.0'
        tree.write(output_file)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()

        fdm[self.input_prop] = math.pi
        dt = math.pi / rate_limit
        t = fdm['simulation/sim-time-sec']
        while t <= dt:
            self.assertAlmostEqual(fdm[self.output_prop],
                                   t * rate_limit - math.pi)
            self.assertTrue(fdm[self.output_prop] >= -math.pi - 1E-8)
            self.assertTrue(fdm[self.output_prop] <= 0.0)
            fdm.run()
            t = fdm['simulation/sim-time-sec']

        t0 = t
        fdm[self.input_prop] = -2.0 * math.pi
        fdm.run()
        t = fdm['simulation/sim-time-sec']

        while t <= t0 + dt:
            self.assertTrue(fdm[self.output_prop] >= -math.pi)
            self.assertTrue(fdm[self.output_prop] <= 0.0)
            self.assertAlmostEqual(fdm[self.output_prop],
                                   (t0 - t) * rate_limit)
            fdm.run()
            t = fdm['simulation/sim-time-sec']

        t0 += dt

        while t <= t0 + dt:
            self.assertTrue(fdm[self.output_prop] >= -math.pi)
            self.assertTrue(fdm[self.output_prop] <= 0.0)
            self.assertAlmostEqual(fdm[self.output_prop],
                                   (t0 - t) * rate_limit)
            fdm.run()
            t = fdm['simulation/sim-time-sec']

    # Regression test for the bug reported in issue #200
    # JSBSim crashes when "fail hardover" is set while no <clipto> element is
    # specified.
    def test_failhardover_without_clipto(self):
        tree, flight_control_element, actuator_element = self.prepare_actuator(
        )
        rate_limit = float(actuator_element.find('rate_limit').text)
        fail_hardover = actuator_element.attrib[
            'name'] + "/malfunction/fail_hardover"
        clipto = actuator_element.find('clipto')
        clipmax = float(clipto.find('max').text)
        actuator_element.remove(clipto)
        output_file = os.path.join('aircraft', self.aircraft_name,
                                   self.aircraft_name + '.xml')
        tree.write(output_file)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()

        # Displace the actuator in the maximum position.
        fdm[self.input_prop] = clipmax
        t = fdm['simulation/sim-time-sec']
        dt = clipmax / rate_limit
        while fdm['simulation/sim-time-sec'] <= t + dt:
            fdm.run()

        # Check the maximum position has been reached.
        self.assertAlmostEqual(fdm[self.output_prop], clipmax)

        # Trigger "fail hardover"
        fdm[fail_hardover] = 1.0
        t = fdm['simulation/sim-time-sec']
        dt = clipmax / rate_limit
        while fdm['simulation/sim-time-sec'] <= t + dt:
            fdm.run()

        # Check the actuator is failed in neutral position
        self.assertAlmostEqual(fdm[self.output_prop], 0.0)

        # Check that setting an input different from the neutral position does
        # not result in a modification of the actuator position.
        fdm[self.input_prop] = clipmax
        t = fdm['simulation/sim-time-sec']
        dt = clipmax / rate_limit
        while fdm['simulation/sim-time-sec'] <= t + dt:
            fdm.run()
            self.assertAlmostEqual(fdm[self.output_prop], 0.0)
Esempio n. 31
0
 def AddAccelerometersToAircraft(self, script_path):
     tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
     system_tag = et.SubElement(tree.getroot(), 'system')
     system_tag.attrib['file'] = 'accelerometers'
     tree.write(
         self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))
Esempio n. 32
0
    def test_point_mass_inertia(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml')
        fdm = CreateFDM(self.sandbox)
        fdm.set_output_directive(
            self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))
        fdm.load_script(script_path)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

        ref = pd.read_csv("output.csv", index_col=0)

        tree, aircraft_name, path_to_jsbsim_aircrafts = CopyAircraftDef(
            script_path, self.sandbox)

        pointmass_element = tree.getroot().find(
            'mass_balance/pointmass//form/..')
        weight_element = pointmass_element.find('weight')
        weight = float(weight_element.text)
        form_element = pointmass_element.find('form')
        radius_element = form_element.find('radius')
        radius, length = (0.0, 0.0)
        if radius_element is not None:
            radius = float(radius_element.text)
        length_element = form_element.find('length')
        if length_element is not None:
            length = float(length_element.text)
        shape = form_element.attrib['shape']
        pointmass_element.remove(form_element)

        inertia = np.zeros((3, 3))
        if string.strip(shape) == 'tube':
            inertia[0, 0] = radius * radius
            inertia[1, 1] = (6.0 * inertia[0, 0] + length * length) / 12.0
            inertia[2, 2] = inertia[1, 1]

        inertia = inertia * weight / 32.174049  # converting slugs to lbs

        ixx_element = et.SubElement(pointmass_element, 'ixx')
        ixx_element.text = str(inertia[0, 0])
        iyy_element = et.SubElement(pointmass_element, 'iyy')
        iyy_element.text = str(inertia[1, 1])
        izz_element = et.SubElement(pointmass_element, 'izz')
        izz_element.text = str(inertia[2, 2])

        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        # Because JSBSim internals use static pointers, we cannot rely on
        # Python garbage collector to decide when the FDM is destroyed
        # otherwise we can get dangling pointers.
        del fdm

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.set_output_directive(
            self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))
        fdm.load_script(script_path)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

        mod = pd.read_csv("output.csv", index_col=0)

        # Check the data are matching i.e. the time steps are the same between
        # the two data sets and that the output data are also the same.
        self.assertTrue(isDataMatching(ref, mod))

        # Find all the data that are differing by more than 1E-8 between the
        # two data sets.
        diff = FindDifferences(ref, mod, 1E-8)
        self.longMessage = True
        self.assertEqual(len(diff), 0, msg='\n' + diff.to_string())
Esempio n. 33
0
    def test_input_socket(self):
        # The aircraft c172x does not contain an <input> tag so we need
        # to add one.
        tree, aircraft_name, b = CopyAircraftDef(self.script_path, self.sandbox)
        self.root = tree.getroot()
        input_tag = et.SubElement(self.root, 'input')
        input_tag.attrib['port'] = '1137'
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()
        fdm.hold()

        tn = TelnetInterface(fdm, 5., 1137)
        self.sanityCheck(tn)

        # Check the aircraft name and its version
        msg = string.split(tn.sendCommand("info"), '\n')
        self.assertEqual(string.strip(string.split(msg[2], ':')[1]),
                         string.strip(self.root.attrib['name']))
        self.assertEqual(string.strip(string.split(msg[1], ':')[1]),
                         string.strip(self.root.attrib['version']))

        # Check that the simulation time is 0.0
        self.assertEqual(float(string.strip(string.split(msg[3], ':')[1])), 0.0)
        self.assertEqual(tn.getSimTime(), 0.0)
        self.assertEqual(tn.getPropertyValue("simulation/sim-time-sec"), 0.0)

        # Check that 'iterate' iterates the correct number of times
        tn.sendCommand("iterate 19")
        self.assertEqual(tn.getSimTime(), 19. * tn.getDeltaT())
        self.assertAlmostEqual(tn.getPropertyValue("simulation/sim-time-sec"),
                               tn.getSimTime(), delta=1E-5)

        # Wait a little bit and make sure that the simulation time has not
        # changed meanwhile thus confirming that the simulation is on hold.
        tn.wait(0.1)
        self.assertEqual(tn.getSimTime(), 19. * tn.getDeltaT())
        self.assertAlmostEqual(tn.getPropertyValue("simulation/sim-time-sec"),
                               tn.getSimTime(), delta=1E-5)

        # Modify the tank[0] contents via the "send" command
        half_contents = 0.5 * tn.getPropertyValue("propulsion/tank/contents-lbs")
        tn.sendCommand("set propulsion/tank/contents-lbs " + str(half_contents))
        self.assertEqual(tn.getPropertyValue("propulsion/tank/contents-lbs"),
                         half_contents)

        # Check the resume/hold commands
        tn.setRealTime(True)
        t = tn.getSimTime()
        tn.sendCommand("resume")
        tn.wait(0.5)
        self.assertNotEqual(tn.getSimTime(), t)
        tn.wait(0.5)
        tn.sendCommand("hold")
        tn.setRealTime(False)
        t = tn.getSimTime()
        self.assertAlmostEqual(tn.getPropertyValue("simulation/sim-time-sec"),
                               t, delta=1E-5)

        # Wait a little bit and make sure that the simulation time has not
        # changed meanwhile thus confirming that the simulation is on hold.
        tn.wait(0.1)
        self.assertEqual(tn.getSimTime(), t)
        self.assertAlmostEqual(tn.getPropertyValue("simulation/sim-time-sec"),
                               t, delta=1E-5)
Esempio n. 34
0
 def AddAccelerometersToAircraft(self, script_path):
     tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
     system_tag = et.SubElement(tree.getroot(), 'system')
     system_tag.attrib['file'] = 'accelerometers'
     tree.write(self.sandbox('aircraft', aircraft_name, aircraft_name+'.xml'))
Esempio n. 35
0
class TestLGearSteer(JSBSimTestCase):
    def test_direct_steer(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_model('c172r')
        aircraft_path = self.sandbox.path_to_jsbsim_file('aircraft')
        fdm.load_ic(os.path.join(aircraft_path, 'c172r', 'reset00'), False)
        fdm.run_ic()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 0.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 0.0)

        # Should be part of a unit test in C++ ?
        fpectl.turnon_sigfpe()

        grndreact = fdm.get_ground_reactions()
        for i in xrange(grndreact.get_num_gear_units()):
            gear = grndreact.get_gear_unit(i)
            self.assertEqual(gear.get_steer_norm(), 0.0)

        fpectl.turnoff_sigfpe()

        fdm['fcs/steer-pos-deg'] = 5.0
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 5.0)
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 0.0)
        fdm['fcs/steer-cmd-norm'] = 1.0
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 10.0)

    def test_steer_with_fcs(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_model('L410')
        aircraft_path = self.sandbox.path_to_jsbsim_file('aircraft')
        fdm.load_ic(os.path.join(aircraft_path, 'L410', 'reset00'), False)
        fdm.run_ic()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 0.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 0.0)
        fdm['fcs/steer-cmd-norm'] = 1.0
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 5.0)
        fdm['/controls/switches/full-steering-sw'] = 1.0
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 0.0)
        fdm['/controls/switches/full-steering-sw'] = 2.0
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 45.0)
        fdm['fcs/steer-cmd-norm'] = -0.5
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], -0.5)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], -22.5)

    def steerType(self, hasSteerPosDeg, hasSteeringAngle, hasCastered):
        self.tree.write(self.sandbox('aircraft', self.aircraft_name,
                                     self.aircraft_name+'.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()
        pm = fdm.get_property_manager()
        self.assertTrue(pm.hasNode('fcs/steer-pos-deg') == hasSteerPosDeg)
        self.assertTrue(pm.hasNode('gear/unit/steering-angle-deg')
                        == hasSteeringAngle)
        self.assertTrue(pm.hasNode('gear/unit/castered') == hasCastered)

        return fdm

    def isCastered(self):
        fdm = self.steerType(True, True, True)
        self.assertTrue(fdm['gear/unit/castered'])
        fdm['fcs/steer-cmd-norm'] = 0.5
        fdm.run()
        self.assertEqual(fdm['gear/unit/steering-angle-deg'], 0.0)
        # self.assertEqual(fdm['fcs/steer-pos-deg'],
        #                  fdm['gear/unit/steering-angle-deg'])

        fdm['fcs/steer-pos-deg'] = 20.0
        self.assertEqual(fdm['gear/unit/steering-angle-deg'], 0.0)
        # self.assertEqual(fdm['fcs/steer-pos-deg'],
        #                  fdm['gear/unit/steering-angle-deg'])

        fdm['gear/unit/castered'] = 0.0
        fdm['fcs/steer-cmd-norm'] = 1.0
        fdm.run()
        self.assertEqual(fdm['gear/unit/steering-angle-deg'],
                         float(self.max_steer_tag.text))
        # self.assertEqual(fdm['fcs/steer-pos-deg'],
        #                  fdm['gear/unit/steering-angle-deg'])
        del fdm

    def isSteered(self):
        fdm = self.steerType(True, False, False)
        fdm['fcs/steer-cmd-norm'] = 0.5
        fdm.run()
        self.assertEqual(fdm['fcs/steer-pos-deg'],
                         0.5*float(self.max_steer_tag.text))
        del fdm

    def test_steer_type(self):
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'c1721.xml')
        self.tree, self.aircraft_name, b = CopyAircraftDef(self.script_path,
                                                           self.sandbox)
        root = self.tree.getroot()
        self.max_steer_tag = root.find('ground_reactions/contact/max_steer')

        # Check the fixed type
        self.max_steer_tag.text = '0.0'
        fdm = self.steerType(False, False, False)
        del fdm

        # Check the castered type
        self.max_steer_tag.text = '360.0'
        self.isCastered()

        # Check the steered type
        self.max_steer_tag.text = '10.0'
        fdm = self.steerType(True, False, False)
        fdm['fcs/steer-cmd-norm'] = 0.5
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 5.0)
        del fdm

        bogey_tag = root.find('ground_reactions/contact//max_steer/..')
        castered_tag = et.SubElement(bogey_tag, 'castered')
        castered_tag.text = '1.0'

        # Check that the bogey is castered no matter what is the value
        # of <max_steer>
        self.max_steer_tag.text = '10.0'
        self.isCastered()

        self.max_steer_tag.text = '0.0'
        self.isCastered()

        self.max_steer_tag.text = '360.0'
        self.isCastered()

        # Check the fixed type
        castered_tag.text = '0.0'
        self.max_steer_tag.text = '0.0'
        fdm = self.steerType(False, False, False)
        del fdm

        # Check the steered type
        self.max_steer_tag.text = '10.0'
        self.isSteered()

        # Check the steered type with 360.0
        self.max_steer_tag.text = '360.0'
        self.isSteered()
Esempio n. 36
0
class TestAeroFuncFrame(JSBSimTestCase):
    def setUp(self):
        JSBSimTestCase.setUp(self)

        self.fdm = CreateFDM(self.sandbox)
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'x153.xml')
        self.tree, self.aircraft_name, b = CopyAircraftDef(
            self.script_path, self.sandbox)

        self.aero2wind = np.mat(np.identity(3))
        self.aero2wind[0, 0] *= -1.0
        self.aero2wind[2, 2] *= -1.0
        self.auxilliary = self.fdm.get_auxiliary()

    def tearDown(self):
        del self.fdm
        JSBSimTestCase.tearDown(self)

    def getTs2b(self):
        alpha = self.fdm['aero/alpha-rad']
        ca = math.cos(alpha)
        sa = math.sin(alpha)
        Ts2b = np.mat([[ca, 0., -sa], [0., 1., 0.], [sa, 0., ca]])
        return Ts2b

    def checkForcesAndMoments(self, getForces, getMoment, aeroFunc):
        self.fdm.load_script(self.script_path)
        self.fdm.run_ic()

        rp = np.mat([
            self.fdm['metrics/aero-rp-x-in'],
            -self.fdm['metrics/aero-rp-y-in'], self.fdm['metrics/aero-rp-z-in']
        ])
        result = {}

        while self.fdm.run():
            for axis in aeroFunc.keys():
                result[axis] = 0.0

                for func in aeroFunc[axis]:
                    result[axis] += self.fdm[func]

            Fa, Fb = getForces(result)
            Tb2s = self.getTs2b().T
            Fs = self.aero2wind * (Tb2s * Fb)

            Mb_MRC = getMoment(result)
            cg = np.mat([
                self.fdm['inertia/cg-x-in'], -self.fdm['inertia/cg-y-in'],
                self.fdm['inertia/cg-z-in']
            ])
            arm_ft = (cg - rp) / 12.0  # Convert from inches to ft
            Mb = Mb_MRC + np.cross(arm_ft, Fb.T)
            Tb2w = self.auxilliary.get_Tb2w()
            Mw = Tb2w * Mb.T
            Ms = Tb2s * Mb.T

            self.assertAlmostEqual(Fa[0, 0], self.fdm['forces/fwx-aero-lbs'])
            self.assertAlmostEqual(Fa[1, 0], self.fdm['forces/fwy-aero-lbs'])
            self.assertAlmostEqual(Fa[2, 0], self.fdm['forces/fwz-aero-lbs'])
            self.assertAlmostEqual(Fb[0, 0], self.fdm['forces/fbx-aero-lbs'])
            self.assertAlmostEqual(Fb[1, 0], self.fdm['forces/fby-aero-lbs'])
            self.assertAlmostEqual(Fb[2, 0], self.fdm['forces/fbz-aero-lbs'])
            self.assertAlmostEqual(Fs[0, 0], self.fdm['forces/fsx-aero-lbs'])
            self.assertAlmostEqual(Fs[1, 0], self.fdm['forces/fsy-aero-lbs'])
            self.assertAlmostEqual(Fs[2, 0], self.fdm['forces/fsz-aero-lbs'])
            self.assertAlmostEqual(Mb[0, 0], self.fdm['moments/l-aero-lbsft'])
            self.assertAlmostEqual(Mb[0, 1], self.fdm['moments/m-aero-lbsft'])
            self.assertAlmostEqual(Mb[0, 2], self.fdm['moments/n-aero-lbsft'])
            self.assertAlmostEqual(Ms[0, 0],
                                   self.fdm['moments/roll-stab-aero-lbsft'])
            self.assertAlmostEqual(Ms[1, 0],
                                   self.fdm['moments/pitch-stab-aero-lbsft'])
            self.assertAlmostEqual(Ms[2, 0],
                                   self.fdm['moments/yaw-stab-aero-lbsft'])
            self.assertAlmostEqual(Mw[0, 0],
                                   self.fdm['moments/roll-wind-aero-lbsft'])
            self.assertAlmostEqual(Mw[1, 0],
                                   self.fdm['moments/pitch-wind-aero-lbsft'])
            self.assertAlmostEqual(Mw[2, 0],
                                   self.fdm['moments/yaw-wind-aero-lbsft'])

    def checkAerodynamicsFrame(self, newAxisName, getForces, getMoment, frame):
        aeroFunc = {}

        for axis in self.tree.findall('aerodynamics/axis'):
            axisName = newAxisName[axis.attrib['name']]
            axis.attrib['name'] = axisName
            if frame:
                axis.attrib['frame'] = frame
            aeroFunc[axisName] = []

            for func in axis.findall('function'):
                aeroFunc[axisName].append(func.attrib['name'])

                if (frame == 'BODY' or len(frame) == 0) and (axisName == 'X' or
                                                             axisName == 'Z'):
                    # Convert the signs of X and Z forces so that the force
                    # along X is directed backward and the force along Z is
                    # directed upward.
                    product_tag = func.find('product')
                    value_tag = et.SubElement(product_tag, 'value')
                    value_tag.text = '-1.0'

        self.tree.write(
            self.sandbox('aircraft', self.aircraft_name,
                         self.aircraft_name + '.xml'))
        self.fdm.set_aircraft_path('aircraft')

        self.checkForcesAndMoments(getForces, getMoment, aeroFunc)

    def checkBodyFrame(self, frame):
        newAxisName = {
            'DRAG': 'X',
            'SIDE': 'Y',
            'LIFT': 'Z',
            'ROLL': 'ROLL',
            'PITCH': 'PITCH',
            'YAW': 'YAW'
        }

        def getForces(result):
            Tb2w = self.auxilliary.get_Tb2w()
            Fb = np.mat([result['X'], result['Y'], result['Z']]).T
            Fw = Tb2w * Fb
            Fa = self.aero2wind * Fw
            return Fa, Fb

        def getMoment(result):
            return np.mat([result['ROLL'], result['PITCH'], result['YAW']])

        self.checkAerodynamicsFrame(newAxisName, getForces, getMoment, '')

    def testBodyFrame(self):
        self.checkBodyFrame('')

    def testBodyFrameAltSyntax(self):
        self.checkBodyFrame('BODY')

    def testAxialFrame(self):
        newAxisName = {
            'DRAG': 'AXIAL',
            'SIDE': 'SIDE',
            'LIFT': 'NORMAL',
            'ROLL': 'ROLL',
            'PITCH': 'PITCH',
            'YAW': 'YAW'
        }

        def getForces(result):
            Tb2w = self.auxilliary.get_Tb2w()
            Fnative = np.mat(
                [result['AXIAL'], result['SIDE'], result['NORMAL']]).T
            Fb = self.aero2wind * Fnative
            Fw = Tb2w * Fb
            Fa = self.aero2wind * Fw
            return Fa, Fb

        def getMoment(result):
            return np.mat([result['ROLL'], result['PITCH'], result['YAW']])

        self.checkAerodynamicsFrame(newAxisName, getForces, getMoment, '')

    def testWindFrame(self):
        newAxisName = {
            'DRAG': 'X',
            'SIDE': 'Y',
            'LIFT': 'Z',
            'ROLL': 'ROLL',
            'PITCH': 'PITCH',
            'YAW': 'YAW'
        }

        def getForces(result):
            Tw2b = self.auxilliary.get_Tw2b()
            Fa = np.mat([result['X'], result['Y'], result['Z']]).T
            Fw = self.aero2wind * Fa
            Fb = Tw2b * Fw
            return Fa, Fb

        def getMoment(result):
            Tw2b = self.auxilliary.get_Tw2b()
            Mw = np.mat([result['ROLL'], result['PITCH'], result['YAW']]).T
            Mb = Tw2b * Mw
            return Mb.T

        self.checkAerodynamicsFrame(newAxisName, getForces, getMoment, 'WIND')

    def testAeroFrame(self):
        aeroFunc = {}

        for axis in self.tree.findall('aerodynamics/axis'):
            axisName = axis.attrib['name']
            aeroFunc[axisName] = []

            for func in axis.findall('function'):
                aeroFunc[axisName].append(func.attrib['name'])

        def getForces(result):
            Tw2b = self.auxilliary.get_Tw2b()
            Fa = np.mat([result['DRAG'], result['SIDE'], result['LIFT']]).T
            Fw = self.aero2wind * Fa
            Fb = Tw2b * Fw
            return Fa, Fb

        def getMoment(result):
            return np.mat([result['ROLL'], result['PITCH'], result['YAW']])

        self.checkForcesAndMoments(getForces, getMoment, aeroFunc)

    def testStabilityFrame(self):
        newAxisName = {
            'DRAG': 'X',
            'SIDE': 'Y',
            'LIFT': 'Z',
            'ROLL': 'ROLL',
            'PITCH': 'PITCH',
            'YAW': 'YAW'
        }

        def getForces(result):
            Tb2w = self.auxilliary.get_Tb2w()
            Ts2b = self.getTs2b()
            Fs = np.mat([result['X'], result['Y'], result['Z']]).T
            Fb = Ts2b * (self.aero2wind * Fs)
            Fw = Tb2w * Fb
            Fa = self.aero2wind * Fw
            return Fa, Fb

        def getMoment(result):
            Ts2b = self.getTs2b()
            Ms = np.mat([result['ROLL'], result['PITCH'], result['YAW']]).T
            Mb = Ts2b * Ms
            return Mb.T

        self.checkAerodynamicsFrame(newAxisName, getForces, getMoment,
                                    'STABILITY')
Esempio n. 37
0
    def test_point_mass_inertia(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml')
        fdm = CreateFDM(self.sandbox)
        fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests',
                                                                  'output.xml'))
        fdm.load_script(script_path)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

        ref = pd.read_csv("output.csv", index_col=0)

        tree, aircraft_name, path_to_jsbsim_aircrafts = CopyAircraftDef(script_path, self.sandbox)

        pointmass_element = tree.getroot().find('mass_balance/pointmass//form/..')
        weight_element = pointmass_element.find('weight')
        weight = float(weight_element.text)
        form_element = pointmass_element.find('form')
        radius_element = form_element.find('radius')
        radius, length = (0.0, 0.0)
        if radius_element is not None:
            radius = float(radius_element.text)
        length_element = form_element.find('length')
        if length_element is not None:
            length = float(length_element.text)
        shape = form_element.attrib['shape']
        pointmass_element.remove(form_element)

        inertia = np.zeros((3, 3))
        if string.strip(shape) == 'tube':
            inertia[0, 0] = radius * radius
            inertia[1, 1] = (6.0 * inertia[0, 0] + length * length) / 12.0
            inertia[2, 2] = inertia[1, 1]

        inertia = inertia * weight / 32.174049  # converting slugs to lbs

        ixx_element = et.SubElement(pointmass_element, 'ixx')
        ixx_element.text = str(inertia[0, 0])
        iyy_element = et.SubElement(pointmass_element, 'iyy')
        iyy_element.text = str(inertia[1, 1])
        izz_element = et.SubElement(pointmass_element, 'izz')
        izz_element.text = str(inertia[2, 2])

        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        # Because JSBSim internals use static pointers, we cannot rely on
        # Python garbage collector to decide when the FDM is destroyed
        # otherwise we can get dangling pointers.
        del fdm

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests',
                                                                  'output.xml'))
        fdm.load_script(script_path)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

        mod = pd.read_csv("output.csv", index_col=0)

        # Check the data are matching i.e. the time steps are the same between
        # the two data sets and that the output data are also the same.
        self.assertTrue(isDataMatching(ref, mod))

        # Find all the data that are differing by more than 1E-8 between the
        # two data sets.
        diff = FindDifferences(ref, mod, 1E-8)
        self.longMessage = True
        self.assertEqual(len(diff), 0, msg='\n'+diff.to_string())
Esempio n. 38
0
    def test_input_socket(self):
        # The aircraft c172x does not contain an <input> tag so we need
        # to add one.
        tree, aircraft_name, b = CopyAircraftDef(self.script_path,
                                                 self.sandbox)
        self.root = tree.getroot()
        input_tag = et.SubElement(self.root, 'input')
        input_tag.attrib['port'] = '1137'
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()
        fdm.hold()

        tn = TelnetInterface(fdm, 5., 1137)
        self.sanityCheck(tn)

        # Check the aircraft name and its version
        msg = string.split(tn.sendCommand("info"), '\n')
        self.assertEqual(string.strip(string.split(msg[2], ':')[1]),
                         string.strip(self.root.attrib['name']))
        self.assertEqual(string.strip(string.split(msg[1], ':')[1]),
                         string.strip(self.root.attrib['version']))

        # Check that the simulation time is 0.0
        self.assertEqual(float(string.strip(string.split(msg[3], ':')[1])),
                         0.0)
        self.assertEqual(tn.getSimTime(), 0.0)
        self.assertEqual(tn.getPropertyValue("simulation/sim-time-sec"), 0.0)

        # Check that 'iterate' iterates the correct number of times
        tn.sendCommand("iterate 19")
        self.assertEqual(tn.getSimTime(), 19. * tn.getDeltaT())
        self.assertAlmostEqual(tn.getPropertyValue("simulation/sim-time-sec"),
                               tn.getSimTime(),
                               delta=1E-5)

        # Wait a little bit and make sure that the simulation time has not
        # changed meanwhile thus confirming that the simulation is on hold.
        tn.wait(0.1)
        self.assertEqual(tn.getSimTime(), 19. * tn.getDeltaT())
        self.assertAlmostEqual(tn.getPropertyValue("simulation/sim-time-sec"),
                               tn.getSimTime(),
                               delta=1E-5)

        # Modify the tank[0] contents via the "send" command
        half_contents = 0.5 * tn.getPropertyValue(
            "propulsion/tank/contents-lbs")
        tn.sendCommand("set propulsion/tank/contents-lbs " +
                       str(half_contents))
        self.assertEqual(tn.getPropertyValue("propulsion/tank/contents-lbs"),
                         half_contents)

        # Check the resume/hold commands
        tn.setRealTime(True)
        t = tn.getSimTime()
        tn.sendCommand("resume")
        tn.wait(0.5)
        self.assertNotEqual(tn.getSimTime(), t)
        tn.wait(0.5)
        tn.sendCommand("hold")
        tn.setRealTime(False)
        t = tn.getSimTime()
        self.assertAlmostEqual(tn.getPropertyValue("simulation/sim-time-sec"),
                               t,
                               delta=1E-5)

        # Wait a little bit and make sure that the simulation time has not
        # changed meanwhile thus confirming that the simulation is on hold.
        tn.wait(0.1)
        self.assertEqual(tn.getSimTime(), t)
        self.assertAlmostEqual(tn.getPropertyValue("simulation/sim-time-sec"),
                               t,
                               delta=1E-5)
Esempio n. 39
0
class TestLGearSteer(JSBSimTestCase):
    def test_direct_steer(self):
        fdm = self.create_fdm()
        fdm.load_model('c172r')
        fdm.load_ic('reset00', True)
        fdm.run_ic()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 0.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 0.0)

        # Should be part of a unit test in C++ ?
        fpectl.turnon_sigfpe()

        grndreact = fdm.get_ground_reactions()
        for i in range(grndreact.get_num_gear_units()):
            gear = grndreact.get_gear_unit(i)
            self.assertEqual(gear.get_steer_norm(), 0.0)

        fpectl.turnoff_sigfpe()

        fdm['fcs/steer-pos-deg'] = 5.0
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 5.0)
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 0.0)
        fdm['fcs/steer-cmd-norm'] = 1.0
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 10.0)

    def test_steer_with_fcs(self):
        fdm = self.create_fdm()
        fdm.load_model('L410')
        fdm.load_ic('reset00', True)
        fdm.run_ic()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 0.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 0.0)
        fdm['fcs/steer-cmd-norm'] = 1.0
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 5.0)
        fdm['/controls/switches/full-steering-sw'] = 1.0
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 0.0)
        fdm['/controls/switches/full-steering-sw'] = 2.0
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], 1.0)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 45.0)
        fdm['fcs/steer-cmd-norm'] = -0.5
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-cmd-norm'], -0.5)
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], -22.5)

    def steerType(self, hasSteerPosDeg, hasSteeringAngle, hasCastered):
        self.tree.write(
            self.sandbox('aircraft', self.aircraft_name,
                         self.aircraft_name + '.xml'))

        fdm = self.create_fdm()
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(self.script_path)
        fdm.run_ic()
        pm = fdm.get_property_manager()
        self.assertTrue(pm.hasNode('fcs/steer-pos-deg') == hasSteerPosDeg)
        self.assertTrue(
            pm.hasNode('gear/unit/steering-angle-deg') == hasSteeringAngle)
        self.assertTrue(pm.hasNode('gear/unit/castered') == hasCastered)

        return fdm

    def isCastered(self):
        fdm = self.steerType(True, True, True)
        self.assertTrue(fdm['gear/unit/castered'])
        fdm['fcs/steer-cmd-norm'] = 0.5
        fdm.run()
        self.assertEqual(fdm['gear/unit/steering-angle-deg'], 0.0)
        # self.assertEqual(fdm['fcs/steer-pos-deg'],
        #                  fdm['gear/unit/steering-angle-deg'])

        fdm['fcs/steer-pos-deg'] = 20.0
        self.assertEqual(fdm['gear/unit/steering-angle-deg'], 0.0)
        # self.assertEqual(fdm['fcs/steer-pos-deg'],
        #                  fdm['gear/unit/steering-angle-deg'])

        fdm['gear/unit/castered'] = 0.0
        fdm['fcs/steer-cmd-norm'] = 1.0
        fdm.run()
        self.assertEqual(fdm['gear/unit/steering-angle-deg'],
                         float(self.max_steer_tag.text))
        # self.assertEqual(fdm['fcs/steer-pos-deg'],
        #                  fdm['gear/unit/steering-angle-deg'])

    def isSteered(self):
        fdm = self.steerType(True, False, False)
        fdm['fcs/steer-cmd-norm'] = 0.5
        fdm.run()
        self.assertEqual(fdm['fcs/steer-pos-deg'],
                         0.5 * float(self.max_steer_tag.text))

    def test_steer_type(self):
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'c1721.xml')
        self.tree, self.aircraft_name, b = CopyAircraftDef(
            self.script_path, self.sandbox)
        root = self.tree.getroot()
        self.max_steer_tag = root.find('ground_reactions/contact/max_steer')

        # Check the fixed type
        self.max_steer_tag.text = '0.0'
        fdm = self.steerType(False, False, False)

        # Check the castered type
        self.max_steer_tag.text = '360.0'
        self.isCastered()

        # Check the steered type
        self.max_steer_tag.text = '10.0'
        fdm = self.steerType(True, False, False)
        fdm['fcs/steer-cmd-norm'] = 0.5
        fdm.run()
        self.assertAlmostEqual(fdm['fcs/steer-pos-deg'], 5.0)

        bogey_tag = root.find('ground_reactions/contact//max_steer/..')
        castered_tag = et.SubElement(bogey_tag, 'castered')
        castered_tag.text = '1.0'

        # Check that the bogey is castered no matter what is the value
        # of <max_steer>
        self.max_steer_tag.text = '10.0'
        self.isCastered()

        self.max_steer_tag.text = '0.0'
        self.isCastered()

        self.max_steer_tag.text = '360.0'
        self.isCastered()

        # Check the fixed type
        castered_tag.text = '0.0'
        self.max_steer_tag.text = '0.0'
        fdm = self.steerType(False, False, False)

        # Check the steered type
        self.max_steer_tag.text = '10.0'
        self.isSteered()

        # Check the steered type with 360.0
        self.max_steer_tag.text = '360.0'
        self.isSteered()
Esempio n. 40
0
class CheckFGBug1503(JSBSimTestCase):
    def setUp(self):
        JSBSimTestCase.setUp(self)
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'c1724.xml')

        # Since we will alter the aircraft definition file, we need make a copy
        # of it and of all the files it is refering to.
        self.tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(
            self.script_path, self.sandbox)

    def ScriptExecution(self, fdm, time_limit=1E+9):
        fdm.load_script(self.script_path)
        fdm.run_ic()

        while fdm.run() and fdm.get_sim_time() < time_limit:
            aileron_pos = fdm['fcs/left-aileron-pos-rad']
            self.assertEqual(
                aileron_pos,
                0.0,
                msg=
                "Failed running the script %s at time step %f\nProperty fcs/left-aileron-pos-rad is non-zero (%f)"
                % (self.script_path, fdm.get_sim_time(), aileron_pos))

    def CheckRateValue(self, fdm, output_prop, rate_value):
        aileron_course = []

        t0 = fdm.get_sim_time()
        while fdm.run() and fdm.get_sim_time() <= t0 + 1.0:
            aileron_course += [(fdm.get_sim_time(), fdm[output_prop])]

        # Thanks to a linear regression on the values, we can check that the
        # value is following a slope equal to the rate limit. The correlation
        # coefficient r_value is also checked to verify that the output is
        # evolving linearly.
        slope, intercept, r_value, p_value, std_err = stats.linregress(
            aileron_course)
        self.assertTrue(abs(slope - rate_value) < 1E-9
                        and abs(1.0 - abs(r_value)) < 1E-9,
                        msg="The actuator rate is not linear")

    def CheckRateLimit(self, input_prop, output_prop, incr_limit, decr_limit):
        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')

        self.ScriptExecution(fdm, 1.0)

        fdm[input_prop] = 1.0

        self.CheckRateValue(fdm, output_prop, incr_limit)

        fdm[input_prop] = 0.0
        self.CheckRateValue(fdm, output_prop, decr_limit)

        # Because JSBSim internals use static pointers, we cannot rely on
        # Python garbage collector to decide when the FDM is destroyed
        # otherwise we can get dangling pointers.
        del fdm

    def test_regression_bug_1503(self):
        # First, the execution time of the script c1724.xml is measured. It
        # will be used as a reference to check if JSBSim hangs or not.
        fdm = CreateFDM(self.sandbox)
        start_time = time.time()
        self.ScriptExecution(fdm)
        exec_time = time.time() - start_time
        del fdm

        # Now the copy of the aircraft definition file will be altered: the
        # <rate_limit> element is split in two: one with the 'decr' sense, the
        # other with 'incr' sense.
        actuator_element = self.tree.getroot().find(
            'flight_control/channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        rate_element.attrib['sense'] = 'decr'
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = str(float(rate_element.text) * 0.5)

        self.tree.write(
            self.sandbox('aircraft', self.aircraft_name,
                         self.aircraft_name + '.xml'))

        # Run the script with the modified aircraft
        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')

        # A new process is created that launches the script. We wait for 10
        # times the reference execution time for the script completion. Beyond
        # that time, if the process is not completed, it is terminated and the
        # test is failed.
        p = Process(target=self.ScriptExecution, args=(fdm, ))
        p.start()
        p.join(exec_time * 10.0)  # Wait 10 times the reference time
        alive = p.is_alive()
        if alive:
            p.terminate()
        self.assertFalse(alive, msg="The script has hanged")

    def test_actuator_rate_from_property(self):
        # Second part of the test.
        # #######################
        #
        # The test is run again but this time, <rate_limit> will be read from a
        # property instead of being read from a value hard coded in the
        # aircraft definition file. It has been reported in the bug 1503 of
        # FlightGear that for such a configuration the <actuator> output is
        # constantly increasing even if the input is null. For this script the
        # <actuator> output is stored in the property
        # fcs/left-aileron-pos-rad. The function ScriptExecution will monitor
        # that property and if it changes then the test is failed.

        tree = et.parse(
            os.path.join(self.path_to_jsbsim_aircrafts,
                         self.aircraft_name + '.xml'))
        actuator_element = tree.getroot().find(
            'flight_control/channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        flight_control_element = tree.getroot().find('flight_control')
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value'
        property.attrib['value'] = rate_element.text
        actuator_element = flight_control_element.find(
            'channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        rate_element.attrib['sense'] = 'decr'
        rate_element.text = property.text
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = rate_element.text

        tree.write(
            self.sandbox('aircraft', self.aircraft_name,
                         self.aircraft_name + '.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        self.ScriptExecution(fdm)
        del fdm

    def test_actuator_rate_is_linear(self):
        # Third part of the test.
        ########################
        #
        # The test is run again but this time we are checking that rate_limit
        # drives the actuator output value as expected. The idea is to store
        # the output value of the actuator output vs the time and check with a
        # linear regression that
        # 1. The actuator output value is evolving linearly
        # 2. The slope of the actuator output is equal to the rate_limit value
        # The test is run with the rate_limit given by a value, a property,
        # different values of the ascending and descending rates and a number
        # of combinations thereof.

        # The aircraft file definition is modified such that the actuator
        # element input is driven by a unique property. The name of this unique
        # property is built in the variable 'input_prop' below. When setting
        # that property to 1.0 (resp. -1.0) the ascending (resp. descending)
        # rate is triggered.
        tree = et.parse(
            os.path.join(self.path_to_jsbsim_aircrafts,
                         self.aircraft_name + '.xml'))
        flight_control_element = tree.getroot().find('flight_control')
        actuator_element = flight_control_element.find(
            'channel/actuator//rate_limit/..')

        # Remove the hysteresis. We want to make sure we are measuring the
        # rate_limit and just that.
        hysteresis_element = actuator_element.find('hysteresis')
        actuator_element.remove(hysteresis_element)
        input_element = actuator_element.find('input')
        input_prop = string.split(actuator_element.attrib['name'], '-')
        input_prop[-1] = 'input'
        input_prop = string.join(input_prop, '-')
        input_element.text = input_prop
        output_element = actuator_element.find('output')
        output_prop = string.strip(output_element.text)

        # Add the new properties to <flight_control> so that we can make
        # reference to them without JSBSim complaining
        property = et.SubElement(flight_control_element, 'property')
        property.text = input_prop
        property.attrib['value'] = '0.0'
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value'
        property.attrib['value'] = '0.15'
        property = et.SubElement(flight_control_element, 'property')
        property.text = 'fcs/rate-limit-value2'
        property.attrib['value'] = '0.05'

        # First check with rate_limit set to 0.1

        rate_element = actuator_element.find('rate_limit')
        rate_element.text = '0.1'

        output_file = os.path.join('aircraft', self.aircraft_name,
                                   self.aircraft_name + '.xml')
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.1, -0.1)

        # Check when rate_limit is set by the property 'fcs/rate-limit-value'

        tree = et.parse(output_file)
        flight_control_element = tree.getroot().find('flight_control')
        actuator_element = flight_control_element.find(
            'channel/actuator//rate_limit/..')
        rate_element = actuator_element.find('rate_limit')
        rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.15, -0.15)

        # Checking when the ascending and descending rates are different.
        # First with the 2 rates set by hard coded values (0.1 and 0.2
        # respectively)

        rate_element.attrib['sense'] = 'decr'
        rate_element.text = '0.1'
        new_rate_element = et.SubElement(actuator_element, 'rate_limit')
        new_rate_element.attrib['sense'] = 'incr'
        new_rate_element.text = '0.2'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.2, -0.1)

        # Check when the descending rate is set by a property and the ascending
        # rate is set by a value.

        rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.2, -0.15)

        # Check when the ascending rate is set by a property and the descending
        # rate is set by a value.

        rate_element.text = '0.1'
        new_rate_element.text = 'fcs/rate-limit-value'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.15, -0.1)

        # Check when the ascending and descending rates are set by properties

        rate_element.text = 'fcs/rate-limit-value2'
        tree.write(output_file)

        self.CheckRateLimit(input_prop, output_prop, 0.15, -0.05)