예제 #1
0
    def Compare(self, section):
        # Rerun the script with the modified aircraft definition
        self.sandbox.delete_csv_files()
        fdm = CreateFDM(self.sandbox)
        # We need to tell JSBSim that the aircraft definition is located in the
        # directory build/.../aircraft
        fdm.set_aircraft_path('aircraft')
        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)

        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(self.ref, mod))

        # Whether the data is read from the aircraft definition file or from an
        # external file, the results shall be exactly identical. Hence the
        # precision set to 0.0.
        diff = FindDifferences(self.ref, mod, 0.0)
        self.assertEqual(len(diff),
                         0,
                         msg='\nTesting section "' + section + '"\n' +
                         diff.to_string())
예제 #2
0
    def Compare(self, section):
        # Rerun the script with the modified aircraft definition
        self.sandbox.delete_csv_files()
        fdm = CreateFDM(self.sandbox)
        # We need to tell JSBSim that the aircraft definition is located in the
        # directory build/.../aircraft
        fdm.set_aircraft_path('aircraft')
        fdm.set_output_directive(
            self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))
        fdm.load_script(self.script)
        fdm.set_property_value('simulation/randomseed', 0.0)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

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

        # Whether the data is read from the aircraft definition file or from an
        # external file, the results shall be exactly identical. Hence the
        # precision set to 0.0.
        diff = self.ref.compare(mod, 0.0)
        self.assertTrue(diff.empty(),
                        msg='\nTesting section "' + section + '"\n' +
                        repr(diff))
예제 #3
0
    def testOrbit(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        # The time step is too small in ball_orbit so let's increase it to 0.1s
        # for a quicker run
        tree = et.parse(script_path)
        run_tag = tree.getroot().find('./run')
        run_tag.attrib['dt'] = '0.1'
        tree.write(script_name)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_name)
        # Switch the accel on
        fdm['fcs/accelerometer/on'] = 1.0
        fdm.run_ic()

        while fdm.run():
            self.assertAlmostEqual(fdm['fcs/accelerometer/X'], 0.0, delta=1E-8)
            self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], 0.0, delta=1E-8)
            self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], 0.0, delta=1E-8)
            self.assertAlmostEqual(fdm['accelerations/a-pilot-x-ft_sec2'],
                                   0.0,
                                   delta=1E-8)
            self.assertAlmostEqual(fdm['accelerations/a-pilot-y-ft_sec2'],
                                   0.0,
                                   delta=1E-8)
            self.assertAlmostEqual(fdm['accelerations/a-pilot-z-ft_sec2'],
                                   0.0,
                                   delta=1E-8)

        del fdm
예제 #4
0
    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
예제 #5
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)
예제 #6
0
 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)
예제 #7
0
    def Compare(self, section):
        # Rerun the script with the modified aircraft definition
        self.sandbox.delete_csv_files()
        fdm = CreateFDM(self.sandbox)
        # We need to tell JSBSim that the aircraft definition is located in the
        # directory build/.../aircraft
        fdm.set_aircraft_path('aircraft')
        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)

        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(self.ref, mod))

        # Whether the data is read from the aircraft definition file or from an
        # external file, the results shall be exactly identical. Hence the
        # precision set to 0.0.
        diff = FindDifferences(self.ref, mod, 0.0)
        self.assertEqual(len(diff), 0,
                         msg='\nTesting section "'+section+'"\n'+diff.to_string())
예제 #8
0
    def testOrbit(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        # The time step is too small in ball_orbit so let's increase it to 0.1s
        # for a quicker run
        tree = et.parse(script_path)
        run_tag = tree.getroot().find('./run')
        run_tag.attrib['dt'] = '0.1'
        tree.write(script_name)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_name)
        # Switch the accel on
        fdm['fcs/accelerometer/on'] = 1.0
        fdm.run_ic()

        while fdm.run():
            self.assertAlmostEqual(fdm['fcs/accelerometer/X'], 0.0, delta=1E-8)
            self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], 0.0, delta=1E-8)
            self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], 0.0, delta=1E-8)
            self.assertAlmostEqual(fdm['accelerations/a-pilot-x-ft_sec2'], 0.0,
                                   delta=1E-8)
            self.assertAlmostEqual(fdm['accelerations/a-pilot-y-ft_sec2'], 0.0,
                                   delta=1E-8)
            self.assertAlmostEqual(fdm['accelerations/a-pilot-z-ft_sec2'], 0.0,
                                   delta=1E-8)

        del fdm
예제 #9
0
    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
예제 #10
0
    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
예제 #11
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)
예제 #12
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))
예제 #13
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))
예제 #14
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)
예제 #15
0
    def testSteadyFlight(self):
        script_name = 'c1722.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        # Switch the accel on
        fdm['fcs/accelerometer/on'] = 1.0
        # Use the standard gravity (i.e. GM/r^2)
        fdm['simulation/gravity-model'] = 0
        # Select an orientation such that frame transformations simplify
        fdm['ic/psi-true-rad'] = 0.0
        fdm.run_ic()

        ExecuteUntil(fdm, 0.1)

        fdm['simulation/do_simple_trim'] = 1

        r = fdm['position/radius-to-vehicle-ft']
        pitch = fdm['attitude/theta-rad']
        roll = fdm['attitude/phi-rad']
        latitude = fdm['position/lat-gc-rad']
        g = fdm['accelerations/gravity-ft_sec2']
        omega = 0.00007292115  # Earth rotation rate in rad/sec
        fc = r * math.cos(latitude) * omega * omega  # Centrifugal force

        uvw = np.array(fdm.get_propagate().get_uvw().T)[0]
        Omega = omega * np.array([
            math.cos(pitch - latitude),
            math.sin(pitch - latitude) * math.sin(roll),
            math.sin(pitch - latitude) * math.cos(roll)
        ])

        # Compute the acceleration measured by the accelerometer as the sum of
        # the gravity and the centrifugal and Coriolis forces.
        fa_yz = (fc * math.cos(latitude - pitch) - g * math.cos(pitch))
        fa = np.array([(fc * math.sin(latitude - pitch) + g * math.sin(pitch)),
                       fa_yz * math.sin(roll), fa_yz * math.cos(roll)
                       ]) + np.cross(2.0 * Omega, uvw)

        # After the trim we are close to the equilibrium but there remains a
        # small residual that we have to take the bias into account
        fax = fa[0] + fdm['accelerations/udot-ft_sec2']
        fay = fa[1] + fdm['accelerations/vdot-ft_sec2']
        faz = fa[2] + fdm['accelerations/wdot-ft_sec2']

        # Deltas are relaxed because the tolerances of the trimming algorithm
        # are quite relaxed themselves.
        self.assertAlmostEqual(fdm['fcs/accelerometer/X'], fax, delta=1E-6)
        self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], fay, delta=1E-4)
        self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], faz, delta=1E-5)

        del fdm
예제 #16
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
예제 #17
0
    def testSteadyFlight(self):
        script_name = 'c1722.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        # Switch the accel on
        fdm['fcs/accelerometer/on'] = 1.0
        # Use the standard gravity (i.e. GM/r^2)
        fdm['simulation/gravity-model'] = 0
        # Select an orientation such that frame transformations simplify
        fdm['ic/psi-true-rad'] = 0.0
        fdm.run_ic()

        ExecuteUntil(fdm, 0.1)

        fdm['simulation/do_simple_trim'] = 1

        r = fdm['position/radius-to-vehicle-ft']
        pitch = fdm['attitude/theta-rad']
        roll = fdm['attitude/phi-rad']
        latitude = fdm['position/lat-gc-rad']
        g = fdm['accelerations/gravity-ft_sec2']
        omega = 0.00007292115  # Earth rotation rate in rad/sec
        fc = r * math.cos(latitude) * omega * omega  # Centrifugal force

        uvw = np.array(fdm.get_propagate().get_uvw().T)[0]
        Omega = omega * np.array([math.cos(pitch - latitude),
                                  math.sin(pitch - latitude) * math.sin(roll),
                                  math.sin(pitch - latitude) * math.cos(roll)])

        # Compute the acceleration measured by the accelerometer as the sum of
        # the gravity and the centrifugal and Coriolis forces.
        fa_yz = (fc * math.cos(latitude - pitch) - g * math.cos(pitch))
        fa = np.array([(fc * math.sin(latitude - pitch) + g * math.sin(pitch)),
                       fa_yz * math.sin(roll),
                       fa_yz * math.cos(roll)]) + np.cross(2.0*Omega, uvw)

        # After the trim we are close to the equilibrium but there remains a
        # small residual that we have to take the bias into account
        fax = fa[0] + fdm['accelerations/udot-ft_sec2']
        fay = fa[1] + fdm['accelerations/vdot-ft_sec2']
        faz = fa[2] + fdm['accelerations/wdot-ft_sec2']

        # Deltas are relaxed because the tolerances of the trimming algorithm
        # are quite relaxed themselves.
        self.assertAlmostEqual(fdm['fcs/accelerometer/X'], fax, delta=1E-6)
        self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], fay, delta=1E-4)
        self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], faz, delta=1E-5)

        del fdm
예제 #18
0
def CheckRateLimit(script_path, input_prop, output_prop, incr_limit, decr_limit):
    fdm = CreateFDM(sandbox)
    fdm.set_aircraft_path('aircraft')

    ScriptExecution(fdm, script_path, 1.0)

    fdm.set_property_value(input_prop, 1.0)

    CheckRateValue(fdm, output_prop, incr_limit)

    fdm.set_property_value(input_prop, 0.0)
    CheckRateValue(fdm, output_prop, decr_limit)
예제 #19
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
예제 #20
0
    def testSpinningBodyOnOrbit(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model('ball')
        # Offset the CG along Y (by 30")
        fdm.set_property_value('inertia/pointmass-weight-lbs[1]', 50.0)

        aircraft_path = self.sandbox.elude(
            self.sandbox.path_to_jsbsim_file('aircraft', 'ball'))
        fdm.load_ic(os.path.join(aircraft_path, 'reset00.xml'), False)
        # Switch the accel on
        fdm.set_property_value('fcs/accelerometer/on', 1.0)
        # Set the orientation such that the spinning axis is Z.
        fdm.set_property_value('ic/phi-rad', 0.5 * math.pi)

        # Set the angular velocities to 0.0 in the ECEF frame. The angular
        # velocity R_{inertial} will therefore be equal to the Earth rotation
        # rate 7.292115E-5 rad/sec
        fdm.set_property_value('ic/p-rad_sec', 0.0)
        fdm.set_property_value('ic/q-rad_sec', 0.0)
        fdm.set_property_value('ic/r-rad_sec', 0.0)
        fdm.run_ic()

        fax = fdm.get_property_value('fcs/accelerometer/X')
        fay = fdm.get_property_value('fcs/accelerometer/Y')
        faz = fdm.get_property_value('fcs/accelerometer/Z')
        cgy_ft = fdm.get_property_value('inertia/cg-y-in') / 12.
        omega = 0.00007292115  # Earth rotation rate in rad/sec

        self.assertAlmostEqual(
            fdm.get_property_value('accelerations/a-pilot-x-ft_sec2'),
            fax,
            delta=1E-8)
        self.assertAlmostEqual(
            fdm.get_property_value('accelerations/a-pilot-y-ft_sec2'),
            fay,
            delta=1E-8)
        self.assertAlmostEqual(
            fdm.get_property_value('accelerations/a-pilot-z-ft_sec2'),
            faz,
            delta=1E-8)

        # Acceleration along X should be zero
        self.assertAlmostEqual(fax, 0.0, delta=1E-8)
        # Acceleration along Y should be equal to r*omega^2
        self.assertAlmostEqual(fay / (cgy_ft * omega * omega), 1.0, delta=1E-7)
        # Acceleration along Z should be zero
        self.assertAlmostEqual(faz, 0.0, delta=1E-8)
예제 #21
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])
예제 #22
0
    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
예제 #23
0
    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
예제 #24
0
    def testSteadyFlight(self):
        script_name = 'c1722.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        # Switch the accel on
        fdm.set_property_value('fcs/accelerometer/on', 1.0)
        # Use the standard gravity (i.e. GM/r^2)
        fdm.set_property_value('simulation/gravity-model', 0)
        # Simplifies the transformation to compare the accelerometer with the
        # gravity
        fdm.set_property_value('ic/psi-true-rad', 0.0)
        fdm.run_ic()

        while fdm.get_property_value('simulation/sim-time-sec') <= 0.5:
            fdm.run()

        fdm.set_property_value('simulation/do_simple_trim', 1)
        ax = fdm.get_property_value('accelerations/udot-ft_sec2')
        ay = fdm.get_property_value('accelerations/vdot-ft_sec2')
        az = fdm.get_property_value('accelerations/wdot-ft_sec2')
        g = fdm.get_property_value('accelerations/gravity-ft_sec2')
        theta = fdm.get_property_value('attitude/theta-rad')

        # There is a lag of one time step between the computations of the
        # accelerations and the update of the accelerometer
        fdm.run()
        fax = fdm.get_property_value('fcs/accelerometer/X')
        fay = fdm.get_property_value('fcs/accelerometer/Y')
        faz = fdm.get_property_value('fcs/accelerometer/Z')

        fax -= ax
        fay -= ay
        faz -= az

        # Deltas are relaxed because the tolerances of the trimming algorithm
        # are quite relaxed themselves.
        self.assertAlmostEqual(faz / (g * math.cos(theta)), -1.0, delta=1E-5)
        self.assertAlmostEqual(fax / (g * math.sin(theta)), 1.0, delta=1E-5)
        self.assertAlmostEqual(math.sqrt(fax * fax + fay * fay + faz * faz) /
                               g,
                               1.0,
                               delta=1E-6)

        del fdm
예제 #25
0
    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
예제 #26
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])
예제 #27
0
    def testSpinningBodyOnOrbit(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model('ball')
        # Offset the CG along Y (by 30")
        fdm['inertia/pointmass-weight-lbs[1]'] = 50.0

        aircraft_path = self.sandbox.path_to_jsbsim_file('aircraft', 'ball')
        fdm.load_ic(os.path.join(aircraft_path, 'reset00.xml'), False)
        # Switch the accel on
        fdm['fcs/accelerometer/on'] = 1.0
        # Set the orientation such that the spinning axis is Z.
        fdm['ic/phi-rad'] = 0.5 * math.pi

        # Set the angular velocities so that angular velocity R_{inertial} will
        # be equal to 1.0 rad/sec.
        omega = 0.00007292115  # Earth rotation rate in rad/sec
        fdm['ic/p-rad_sec'] = 0.0
        fdm['ic/q-rad_sec'] = 0.0
        fdm['ic/r-rad_sec'] = 1.0 - omega
        fdm.run_ic()

        fax = fdm['fcs/accelerometer/X']
        fay = fdm['fcs/accelerometer/Y']
        faz = fdm['fcs/accelerometer/Z']
        cgy_ft = fdm['inertia/cg-y-in'] / 12.

        self.assertAlmostEqual(fdm['accelerations/a-pilot-x-ft_sec2'],
                               fax,
                               delta=1E-8)
        self.assertAlmostEqual(fdm['accelerations/a-pilot-y-ft_sec2'],
                               fay,
                               delta=1E-8)
        self.assertAlmostEqual(fdm['accelerations/a-pilot-z-ft_sec2'],
                               faz,
                               delta=1E-8)

        # Acceleration along X should be zero
        self.assertAlmostEqual(fax, 0.0, delta=1E-8)
        # Acceleration along Y should be equal to d*r_dot^2
        self.assertAlmostEqual(fay / cgy_ft, 1.0, delta=1E-7)
        # Acceleration along Z should be zero
        self.assertAlmostEqual(faz, 0.0, delta=1E-8)
예제 #28
0
    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
예제 #29
0
    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)
예제 #30
0
    def testSpinningBodyOnOrbit(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model('ball')
        # Offset the CG along Y (by 30")
        fdm.set_property_value('inertia/pointmass-weight-lbs[1]', 50.0)

        aircraft_path = self.sandbox.elude(self.sandbox.path_to_jsbsim_file('aircraft', 'ball'))
        fdm.load_ic(os.path.join(aircraft_path, 'reset00.xml'), False)
        # Switch the accel on
        fdm.set_property_value('fcs/accelerometer/on', 1.0)
        # Set the orientation such that the spinning axis is Z.
        fdm.set_property_value('ic/phi-rad', 0.5*math.pi)

        # Set the angular velocities to 0.0 in the ECEF frame. The angular
        # velocity R_{inertial} will therefore be equal to the Earth rotation
        # rate 7.292115E-5 rad/sec
        fdm.set_property_value('ic/p-rad_sec', 0.0)
        fdm.set_property_value('ic/q-rad_sec', 0.0)
        fdm.set_property_value('ic/r-rad_sec', 0.0)
        fdm.run_ic()

        fax = fdm.get_property_value('fcs/accelerometer/X')
        fay = fdm.get_property_value('fcs/accelerometer/Y')
        faz = fdm.get_property_value('fcs/accelerometer/Z')
        cgy_ft = fdm.get_property_value('inertia/cg-y-in') / 12.
        omega = 0.00007292115 # Earth rotation rate in rad/sec

        self.assertAlmostEqual(fdm.get_property_value('accelerations/a-pilot-x-ft_sec2'),
                               fax, delta=1E-8)
        self.assertAlmostEqual(fdm.get_property_value('accelerations/a-pilot-y-ft_sec2'),
                               fay, delta=1E-8)
        self.assertAlmostEqual(fdm.get_property_value('accelerations/a-pilot-z-ft_sec2'),
                               faz, delta=1E-8)

        # Acceleration along X should be zero
        self.assertAlmostEqual(fax, 0.0, delta=1E-8)
        # Acceleration along Y should be equal to r*omega^2
        self.assertAlmostEqual(fay / (cgy_ft * omega * omega), 1.0, delta=1E-7)
        # Acceleration along Z should be zero
        self.assertAlmostEqual(faz, 0.0, delta=1E-8)
예제 #31
0
    def testSteadyFlight(self):
        script_name = 'c1722.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_script(script_path)
        # Switch the accel on
        fdm.set_property_value('fcs/accelerometer/on', 1.0)
        # Use the standard gravity (i.e. GM/r^2)
        fdm.set_property_value('simulation/gravity-model', 0)
        # Simplifies the transformation to compare the accelerometer with the
        # gravity
        fdm.set_property_value('ic/psi-true-rad', 0.0)
        fdm.run_ic()

        while fdm.get_property_value('simulation/sim-time-sec') <= 0.5:
            fdm.run()

        fdm.set_property_value('simulation/do_simple_trim', 1)
        ax = fdm.get_property_value('accelerations/udot-ft_sec2')
        ay = fdm.get_property_value('accelerations/vdot-ft_sec2')
        az = fdm.get_property_value('accelerations/wdot-ft_sec2')
        g = fdm.get_property_value('accelerations/gravity-ft_sec2')
        theta = fdm.get_property_value('attitude/theta-rad')

        # There is a lag of one time step between the computations of the
        # accelerations and the update of the accelerometer
        fdm.run()
        fax = fdm.get_property_value('fcs/accelerometer/X')
        fay = fdm.get_property_value('fcs/accelerometer/Y')
        faz = fdm.get_property_value('fcs/accelerometer/Z')

        fax -= ax
        fay -= ay
        faz -= az

        # Deltas are relaxed because the tolerances of the trimming algorithm
        # are quite relaxed themselves.
        self.assertAlmostEqual(faz / (g * math.cos(theta)), -1.0, delta=1E-5)
        self.assertAlmostEqual(fax / (g * math.sin(theta)), 1.0, delta=1E-5)
        self.assertAlmostEqual(math.sqrt(fax*fax+fay*fay+faz*faz)/g, 1.0, delta=1E-6)

        del fdm
예제 #32
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.)
예제 #33
0
    def testSpinningBodyOnOrbit(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

        fdm = CreateFDM(self.sandbox)
        fdm.set_aircraft_path('aircraft')
        fdm.load_model('ball')
        # Offset the CG along Y (by 30")
        fdm['inertia/pointmass-weight-lbs[1]'] = 50.0

        aircraft_path = self.sandbox.path_to_jsbsim_file('aircraft', 'ball')
        fdm.load_ic(os.path.join(aircraft_path, 'reset00.xml'), False)
        # Switch the accel on
        fdm['fcs/accelerometer/on'] = 1.0
        # Set the orientation such that the spinning axis is Z.
        fdm['ic/phi-rad'] = 0.5*math.pi

        # Set the angular velocities so that angular velocity R_{inertial} will
        # be equal to 1.0 rad/sec.
        omega = 0.00007292115  # Earth rotation rate in rad/sec
        fdm['ic/p-rad_sec'] = 0.0
        fdm['ic/q-rad_sec'] = 0.0
        fdm['ic/r-rad_sec'] = 1.0 - omega
        fdm.run_ic()

        fax = fdm['fcs/accelerometer/X']
        fay = fdm['fcs/accelerometer/Y']
        faz = fdm['fcs/accelerometer/Z']
        cgy_ft = fdm['inertia/cg-y-in'] / 12.

        self.assertAlmostEqual(fdm['accelerations/a-pilot-x-ft_sec2'], fax,
                               delta=1E-8)
        self.assertAlmostEqual(fdm['accelerations/a-pilot-y-ft_sec2'], fay,
                               delta=1E-8)
        self.assertAlmostEqual(fdm['accelerations/a-pilot-z-ft_sec2'], faz,
                               delta=1E-8)

        # Acceleration along X should be zero
        self.assertAlmostEqual(fax, 0.0, delta=1E-8)
        # Acceleration along Y should be equal to d*r_dot^2
        self.assertAlmostEqual(fay / cgy_ft, 1.0, delta=1E-7)
        # Acceleration along Z should be zero
        self.assertAlmostEqual(faz, 0.0, delta=1E-8)
예제 #34
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.)
예제 #35
0
    def testOnGround(self):
        script_name = 'c1721.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

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

        # Switch the accel on
        fdm.set_property_value('fcs/accelerometer/on', 1.0)
        # Use the standard gravity (i.e. GM/r^2)
        fdm.set_property_value('simulation/gravity-model', 0)
        # Simplifies the transformation to compare the accelerometer with the
        # gravity
        fdm.set_property_value('ic/psi-true-rad', 0.0)
        fdm.run_ic()

        for i in xrange(500):
            fdm.run()

        ax = fdm.get_property_value('accelerations/udot-ft_sec2')
        ay = fdm.get_property_value('accelerations/vdot-ft_sec2')
        az = fdm.get_property_value('accelerations/wdot-ft_sec2')
        g = fdm.get_property_value('accelerations/gravity-ft_sec2')
        theta = fdm.get_property_value('attitude/theta-rad')

        # There is a lag of one time step between the computations of the
        # accelerations and the update of the accelerometer
        fdm.run()
        fax = fdm.get_property_value('fcs/accelerometer/X')
        fay = fdm.get_property_value('fcs/accelerometer/Y')
        faz = fdm.get_property_value('fcs/accelerometer/Z')

        fax -= ax
        faz -= az

        self.assertAlmostEqual(fay, 0.0, delta=1E-6)
        self.assertAlmostEqual(fax / (g * math.sin(theta)), 1.0, delta=1E-5)
        self.assertAlmostEqual(faz / (g * math.cos(theta)), -1.0, delta=1E-7)

        del fdm
예제 #36
0
    def testOnGround(self):
        script_name = 'c1721.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

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

        # Switch the accel on
        fdm.set_property_value('fcs/accelerometer/on', 1.0)
        # Use the standard gravity (i.e. GM/r^2)
        fdm.set_property_value('simulation/gravity-model', 0)
        # Simplifies the transformation to compare the accelerometer with the
        # gravity
        fdm.set_property_value('ic/psi-true-rad', 0.0)
        fdm.run_ic()

        for i in xrange(500):
            fdm.run()

        ax = fdm.get_property_value('accelerations/udot-ft_sec2')
        ay = fdm.get_property_value('accelerations/vdot-ft_sec2')
        az = fdm.get_property_value('accelerations/wdot-ft_sec2')
        g = fdm.get_property_value('accelerations/gravity-ft_sec2')
        theta = fdm.get_property_value('attitude/theta-rad')

        # There is a lag of one time step between the computations of the
        # accelerations and the update of the accelerometer
        fdm.run()
        fax = fdm.get_property_value('fcs/accelerometer/X')
        fay = fdm.get_property_value('fcs/accelerometer/Y')
        faz = fdm.get_property_value('fcs/accelerometer/Z')

        fax -= ax
        faz -= az

        self.assertAlmostEqual(fay, 0.0, delta=1E-6)
        self.assertAlmostEqual(fax / (g * math.sin(theta)), 1.0, delta=1E-5)
        self.assertAlmostEqual(faz / (g * math.cos(theta)), -1.0, delta=1E-7)

        del fdm
예제 #37
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)
예제 #38
0
    def test_no_script(self):
        fdm = CreateFDM(self.sandbox)
        aircraft_path = self.sandbox.path_to_jsbsim_file('aircraft')
        fdm.set_aircraft_path(aircraft_path)
        fdm.load_model('c172x')

        aircraft_path = os.path.join(self.sandbox.elude(aircraft_path), 'c172x')
        fdm.load_ic(os.path.join(aircraft_path, 'reset01.xml'), False)
        fdm.run_ic()

        self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'), 0.0)
        ExecuteUntil(fdm, 5.0)

        t = fdm.get_property_value('simulation/sim-time-sec')
        fdm.set_property_value('simulation/do_simple_trim', 1)
        self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'), t)

        fdm.reset_to_initial_conditions(1)
        self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'), 0.0)

        del fdm
예제 #39
0
    def test_no_script(self):
        fdm = CreateFDM(self.sandbox)
        aircraft_path = self.sandbox.path_to_jsbsim_file('aircraft')
        fdm.set_aircraft_path(aircraft_path)
        fdm.load_model('c172x')

        aircraft_path = os.path.join(aircraft_path, 'c172x')
        fdm.load_ic(os.path.join(aircraft_path, 'reset01.xml'), False)
        fdm.run_ic()

        self.assertEqual(fdm['simulation/sim-time-sec'], 0.0)
        ExecuteUntil(fdm, 5.0)

        t = fdm['simulation/sim-time-sec']
        fdm['simulation/do_simple_trim'] = 1
        self.assertEqual(fdm['simulation/sim-time-sec'], t)

        fdm.reset_to_initial_conditions(1)
        self.assertEqual(fdm['simulation/sim-time-sec'], 0.0)

        del fdm
예제 #40
0
    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")
예제 #41
0
    def Compare(self, section):
        # Rerun the script with the modified aircraft definition
        self.sandbox.delete_csv_files()
        fdm = CreateFDM(self.sandbox)
        # We need to tell JSBSim that the aircraft definition is located in the
        # directory build/.../aircraft
        fdm.set_aircraft_path('aircraft')
        fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))
        fdm.load_script(self.script)
        fdm.set_property_value('simulation/randomseed', 0.0)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

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

        # Whether the data is read from the aircraft definition file or from an
        # external file, the results shall be exactly identical. Hence the
        # precision set to 0.0.
        diff = self.ref.compare(mod, 0.0)
        self.assertTrue(diff.empty(),
                        msg='\nTesting section "'+section+'"\n'+repr(diff))
예제 #42
0
    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")
예제 #43
0
    def testOnGround(self):
        script_name = 'c1721.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

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

        # Switch the accel on
        fdm['fcs/accelerometer/on'] = 1.0
        # Use the standard gravity (i.e. GM/r^2)
        fdm['simulation/gravity-model'] = 0
        # Simplifies the transformation to compare the accelerometer with the
        # gravity
        fdm['ic/psi-true-rad'] = 0.0
        fdm.run_ic()

        for i in xrange(1000):
            fdm.run()

        r = fdm['position/radius-to-vehicle-ft']
        g = fdm['accelerations/gravity-ft_sec2']
        latitude = fdm['position/lat-gc-rad']
        pitch = fdm['attitude/theta-rad']
        omega = 0.00007292115  # Earth rotation rate in rad/sec
        fc = r * math.cos(latitude) * omega * omega

        fax = fc * math.sin(latitude - pitch) + g * math.sin(pitch)
        faz = fc * math.cos(latitude - pitch) - g * math.cos(pitch)

        self.assertAlmostEqual(fdm['fcs/accelerometer/X'], fax, delta=1E-7)
        self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], 0.0, delta=1E-7)
        self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], faz, delta=1E-6)

        del fdm
예제 #44
0
    def testOnGround(self):
        script_name = 'c1721.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        self.AddAccelerometersToAircraft(script_path)

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

        # Switch the accel on
        fdm['fcs/accelerometer/on'] = 1.0
        # Use the standard gravity (i.e. GM/r^2)
        fdm['simulation/gravity-model'] = 0
        # Simplifies the transformation to compare the accelerometer with the
        # gravity
        fdm['ic/psi-true-rad'] = 0.0
        fdm.run_ic()

        for i in xrange(1000):
            fdm.run()

        r = fdm['position/radius-to-vehicle-ft']
        g = fdm['accelerations/gravity-ft_sec2']
        latitude = fdm['position/lat-gc-rad']
        pitch = fdm['attitude/theta-rad']
        omega = 0.00007292115  # Earth rotation rate in rad/sec
        fc = r * math.cos(latitude) * omega * omega

        fax = fc * math.sin(latitude - pitch) + g * math.sin(pitch)
        faz = fc * math.cos(latitude - pitch) - g * math.cos(pitch)

        self.assertAlmostEqual(fdm['fcs/accelerometer/X'], fax, delta=1E-7)
        self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], 0.0, delta=1E-7)
        self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], faz, delta=1E-6)

        del fdm
예제 #45
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')
예제 #46
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))
예제 #47
0
 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)
예제 #48
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')
예제 #49
0
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')

# 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=ScriptExecution, args=(fdm, script_path))
p.start()
p.join(exec_time * 10.0) # Wait 10 times the reference time
if p.is_alive():
    # The process has not yet completed: it means it probably hanged.
    p.terminate()
    sys.exit(-1)

# Second part of the test.
# #######################
#
예제 #50
0
    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']
예제 #51
0
    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
예제 #52
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())
예제 #53
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)
예제 #54
0
class TestInputSocket(unittest.TestCase):
    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()

    def tearDown(self):
        self.tn.close()
        self.thread.quit = True
        self.thread.join()
        self.sandbox.erase()

    def sendCommand(self, command):
        self.cond.acquire()
        self.tn.write(command+"\n")
        # Wait for a time step to be executed before reading the output from telnet
        self.cond.wait()
        msg = self.tn.read_very_eager()
        self.cond.release()
        self.thread.join(0.1)
        return msg

    def getSimTime(self):
        self.cond.acquire()
        self.cond.wait()
        t = self.fdm.get_sim_time()
        self.cond.release()
        return t

    def getDeltaT(self):
        self.cond.acquire()
        self.cond.wait()
        dt = self.fdm.get_delta_t()
        self.cond.release()
        return dt

    def getPropertyValue(self, property):
        msg = string.split(self.sendCommand("get "+property),'\n')
        return float(string.split(msg[0], '=')[1])

    def test_input_socket(self):
        # Check that the connection has been established
        self.cond.acquire()
        self.cond.wait()
        out = self.tn.read_very_eager()
        self.cond.release()
        self.assertTrue(string.split(out, '\n')[0] == 'Connected to JSBSim server',
                        msg="Not connected to the JSBSim server.\nGot message '%s' instead" % (out,))

        # Check that "help" returns the minimum set of commands that will be
        # tested
        self.assertEqual(sorted(map(lambda x : string.strip(string.split(x, '{')[0]),
                                    string.split(self.sendCommand("help"), '\n')[2:-2])),
                         ['get', 'help', 'hold', 'info', 'iterate', 'quit', 'resume', 'set'])

        # Check the aircraft name and its version
        msg = string.split(self.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(self.getSimTime(), 0.0)
        self.assertEqual(self.getPropertyValue("simulation/sim-time-sec"), 0.0)

        # Check that 'iterate' iterates the correct number of times
        self.sendCommand("iterate 19")
        self.assertEqual(self.getSimTime(), 19. * self.getDeltaT())
        self.assertAlmostEqual(self.getPropertyValue("simulation/sim-time-sec"),
                               self.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.
        self.thread.join(0.1)
        self.assertEqual(self.getSimTime(), 19. * self.getDeltaT())
        self.assertAlmostEqual(self.getPropertyValue("simulation/sim-time-sec"),
                               self.getSimTime(), delta=1E-5)

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

        # Check the resume/hold commands
        self.thread.realTime = True
        t = self.getSimTime()
        self.sendCommand("resume")
        self.thread.join(0.5)
        self.assertNotEqual(self.getSimTime(), t)
        self.thread.join(0.5)
        self.sendCommand("hold")
        self.thread.realTime = False
        t = self.getSimTime()
        self.assertAlmostEqual(self.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.
        self.thread.join(0.1)
        self.assertEqual(self.getSimTime(), t)
        self.assertAlmostEqual(self.getPropertyValue("simulation/sim-time-sec"),
                               t, delta=1E-5)
예제 #55
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)
예제 #56
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())