Пример #1
0
class TestGustReset(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_gust_reset(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(
            self.sandbox.path_to_jsbsim_file('scripts', 'c172_cruise_8K.xml'))
        fdm.set_property_value('simulation/randomseed', 0.0)
        fdm.set_output_directive(
            self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))

        fdm.run_ic()
        ExecuteUntil(fdm, 15.5)

        ref, current = Table(), Table()
        ref.ReadCSV(self.sandbox('output.csv'))

        fdm.set_property_value('simulation/randomseed', 0.0)
        fdm.reset_to_initial_conditions(1)
        ExecuteUntil(fdm, 15.5)

        current.ReadCSV(self.sandbox('output_0.csv'))

        diff = ref.compare(current)
        self.longMessage = True
        self.assertTrue(diff.empty(), msg='\n' + repr(diff))
Пример #2
0
class CheckScripts(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()
        self.scripts = 0

    def tearDown(self):
        print "Tested %g scripts" % (self.scripts,)
        self.sandbox.erase()

    def testScripts(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts')
        for f in os.listdir(self.sandbox.elude(script_path)):
            fullpath = os.path.join(self.sandbox.elude(script_path), f)

            # Does f contains a JSBSim script ?
            if not CheckXMLFile(fullpath, 'runscript'):
                continue

            fdm = CreateFDM(self.sandbox)
            self.assertTrue(fdm.load_script(os.path.join(script_path, f)),
                            msg="Failed to load script %s" % (fullpath,))
            fdm.run_ic()

            self.scripts += 1
            del fdm
Пример #3
0
    def setUp(self):
        self.sandbox = SandBox()
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml')

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

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

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

        # Wait for the thread to be started before connecting a telnet session
        self.cond.acquire()
        self.cond.wait()
        self.tn = telnetlib.Telnet("localhost", 1137)
        self.cond.release()
Пример #4
0
class TestDebugLvl(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox('check_cases', 'orbit')

    def tearDown(self):
        self.sandbox.erase()

    def testDebugLvl(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'ball_orbit.xml'))
        fdm.run_ic()

        ExecuteUntil(fdm, 1000.)

        ref, current = Table(), Table()
        ref.ReadCSV(self.sandbox('BallOut.csv'))
        del fdm

        os.environ["JSBSIM_DEBUG"]=str(0)
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'ball_orbit.xml'))
        fdm.run_ic()

        ExecuteUntil(fdm, 1000.)

        current.ReadCSV(self.sandbox('BallOut.csv'))

        diff = ref.compare(current)
        self.longMessage = True
        self.assertTrue(diff.empty(), msg='\n'+repr(diff))
Пример #5
0
class CheckScripts(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()
        self.scripts = 0

    def tearDown(self):
        print "Tested %g scripts" % (self.scripts, )
        self.sandbox.erase()

    def testScripts(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts')
        for f in os.listdir(self.sandbox.elude(script_path)):
            fullpath = os.path.join(self.sandbox.elude(script_path), f)

            # Does f contains a JSBSim script ?
            if not CheckXMLFile(fullpath, 'runscript'):
                continue

            fdm = CreateFDM(self.sandbox)
            self.assertTrue(fdm.load_script(os.path.join(script_path, f)),
                            msg="Failed to load script %s" % (fullpath, ))
            fdm.run_ic()

            self.scripts += 1
            del fdm
Пример #6
0
class TestGustReset(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_gust_reset(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'c172_cruise_8K.xml'))
        fdm.set_property_value('simulation/randomseed', 0.0)
        fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))

        fdm.run_ic()
        ExecuteUntil(fdm, 15.5)

        ref, current = Table(), Table()
        ref.ReadCSV(self.sandbox('output.csv'))

        fdm.set_property_value('simulation/randomseed', 0.0)
        fdm.reset_to_initial_conditions(1)
        ExecuteUntil(fdm, 15.5)

        current.ReadCSV(self.sandbox('output_0.csv'))

        diff = ref.compare(current)
        self.longMessage = True
        self.assertTrue(diff.empty(), msg='\n'+repr(diff))
Пример #7
0
class TestDebugLvl(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox('check_cases', 'orbit')

    def tearDown(self):
        self.sandbox.erase()

    def testDebugLvl(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(
            self.sandbox.path_to_jsbsim_file('scripts', 'ball_orbit.xml'))
        fdm.run_ic()

        ExecuteUntil(fdm, 1000.)

        ref, current = Table(), Table()
        ref.ReadCSV(self.sandbox('BallOut.csv'))
        del fdm

        os.environ["JSBSIM_DEBUG"] = str(0)
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(
            self.sandbox.path_to_jsbsim_file('scripts', 'ball_orbit.xml'))
        fdm.run_ic()

        ExecuteUntil(fdm, 1000.)

        current.ReadCSV(self.sandbox('BallOut.csv'))

        diff = ref.compare(current)
        self.longMessage = True
        self.assertTrue(diff.empty(), msg='\n' + repr(diff))
Пример #8
0
class TestOrbitCheckCase(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox('check_cases', 'orbit')

    def tearDown(self):
        self.sandbox.erase()

    def testOrbitCheckCase(self):
        os.environ['JSBSIM_DEBUG'] = str(0)
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(
            self.sandbox.path_to_jsbsim_file('scripts', 'ball_orbit.xml'))
        fdm.run_ic()

        while fdm.run():
            pass

        ref, current = Table(), Table()
        ref.ReadCSV(
            self.sandbox.elude(
                self.sandbox.path_to_jsbsim_file('logged_data',
                                                 'BallOut.csv')))
        current.ReadCSV(self.sandbox('BallOut.csv'))

        diff = ref.compare(current)
        self.longMessage = True
        self.assertTrue(diff.empty(), msg='\n' + repr(diff))
Пример #9
0
    def setUp(self):
        self.sandbox = SandBox()
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'c1724.xml')

        # Since we will alter the aircraft definition file, we need make a copy
        # of it and of all the files it is refering to.
        self.tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(
            self.script_path, self.sandbox)
Пример #10
0
class TestScriptOutput(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'c1722.xml')

    def tearDown(self):
        self.sandbox.erase()

    def test_no_output(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(self.script_path)
        fdm.run_ic()
        ExecuteUntil(fdm, 10.)

        self.assertFalse(self.sandbox.exists('output.csv'),
                         msg="Results have unexpectedly been written to 'output.csv'")

    def test_output_from_file(self):
        tree = et.parse(self.sandbox.elude(self.script_path))
        output_tag = et.SubElement(tree.getroot(), 'output')
        output_tag.attrib['file'] = self.sandbox.elude(self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))
        tree.write(self.sandbox('c1722_0.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.load_script('c1722_0.xml')
        fdm.run_ic()
        ExecuteUntil(fdm, 10.)

        self.assertTrue(self.sandbox.exists('output.csv'),
                        msg="The file 'output.csv' has not been created")

    def test_output(self):
        tree = et.parse(self.sandbox.elude(self.script_path))
        output_tag = et.SubElement(tree.getroot(), 'output')
        output_tag.attrib['name'] = 'test.csv'
        output_tag.attrib['type'] = 'CSV'
        output_tag.attrib['rate'] = '10'
        property_tag = et.SubElement(output_tag, 'property')
        property_tag.text = 'position/vrp-radius-ft'
        tree.write(self.sandbox('c1722_0.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.load_script('c1722_0.xml')
        fdm.run_ic()
        ExecuteUntil(fdm, 10.)

        self.assertTrue(self.sandbox.exists(output_tag.attrib['name']),
                        msg="The file 'output.csv' has not been created")
        orig = pd.read_csv(self.sandbox('JSBout172B.csv'))
        test = pd.read_csv(self.sandbox('test.csv'))
        self.assertEqual(np.max(orig['Time']-test['Time']), 0.0)
        pname = '/fdm/jsbsim/' + property_tag.text
        self.assertEqual(np.max(orig[pname]-test[pname]), 0.0)
Пример #11
0
    def setUp(self):
        self.sandbox = SandBox()

        self.fdm = CreateFDM(self.sandbox)
        self.script_path = self.sandbox.path_to_jsbsim_file("scripts", "c1722.xml")

        # Read the time step 'dt' from the script file
        self.tree = et.parse(self.sandbox.elude(self.script_path))
        root = self.tree.getroot()
        use_tag = root.find("./use")
        aircraft_name = use_tag.attrib["aircraft"]
        self.run_tag = root.find("./run")
        self.dt = float(self.run_tag.attrib["dt"])

        # Read the date at which the trim will be run
        event_tags = root.findall("./run/event")
        for event in event_tags:
            if event.attrib["name"] == "Trim":
                cond_tag = event.find("./condition")
                self.trim_date = float(string.split(cond_tag.text)[-1])
                break

        # Read the output rate and the output file from the aircraft file
        aircraft_path = self.sandbox.path_to_jsbsim_file("aircraft", aircraft_name, append_xml(aircraft_name))
        tree = et.parse(self.sandbox.elude(aircraft_path))
        output_tag = tree.getroot().find("./output")
        self.output_file = self.sandbox(output_tag.attrib["name"])
        self.rateHz = float(output_tag.attrib["rate"])
        self.rate = int(1.0 / (self.rateHz * self.dt))
Пример #12
0
    def setUp(self):
        self.sandbox = SandBox()
        self.script_path = self.sandbox.path_to_jsbsim_file("scripts", "c1724.xml")

        # Since we will alter the aircraft definition file, we need make a copy
        # of it and of all the files it is refering to.
        self.tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(self.script_path, self.sandbox)
Пример #13
0
class TestCosineGust(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def testMagnitude(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts',
                                                         'c172_cruise_8K.xml'))

        fdm.run_ic()
        t = 0.0

        startup_duration = 5.0
        steady_duration = 1.0
        end_duration = 5.0
        start_time = 10.0
        magnitude = 30.0

        end_time = start_time + startup_duration + steady_duration + end_duration

        while fdm.get_property_value('simulation/run_id') == 0:
            fdm.run()
            wn = fdm.get_property_value('atmosphere/total-wind-north-fps')
            we = fdm.get_property_value('atmosphere/total-wind-east-fps')
            wd = fdm.get_property_value('atmosphere/total-wind-down-fps')

            if t >= start_time and t <= end_time:
                wmag = math.sqrt(wn*wn + we*we + wd*wd)
                t -= start_time
                if t <= startup_duration:
                    self.assertAlmostEqual(0.5 * magnitude * (1.0 - math.cos(math.pi*t/startup_duration)),
                                           wmag, delta=1E-3)
                else:
                    t -= startup_duration
                    if t <= steady_duration:
                        self.assertAlmostEqual(magnitude, wmag, delta=1E-8)
                    else:
                        t -= steady_duration
                        if t <= end_duration:
                            self.assertAlmostEqual(0.5 * magnitude * (1.0 + math.cos(math.pi*t/end_duration)),
                                                   wmag, delta=1E-3)

            t = fdm.get_property_value('simulation/sim-time-sec')
Пример #14
0
class CheckTrim(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_trim_doesnt_ignite_rockets(self):
        # Run a longitudinal trim with a rocket equipped with solid propellant
        # boosters (aka SRBs). The trim algorithm will try to reach a vertical
        # equilibrium by tweaking the throttle but since the rocket is nose up,
        # the trim cannot converge. As a result the algorithm will set full
        # throttle which will result in the SRBs ignition if the integration is
        # not suspended. This bug has been reported in FlightGear and this test
        # is checking that there is no regression.

        fdm = CreateFDM(self.sandbox)
        fdm.load_model('J246')
        aircraft_path = self.sandbox.elude(self.sandbox.path_to_jsbsim_file('aircraft'))
        fdm.load_ic(os.path.join(aircraft_path, 'J246', 'LC39'), False)
        fdm.run_ic()

        # Check that the SRBs are not ignited
        self.assertEqual(fdm['propulsion/engine[0]/thrust-lbs'], 0.0)
        self.assertEqual(fdm['propulsion/engine[1]/thrust-lbs'], 0.0)

        try:
            fdm['simulation/do_simple_trim'] = 1
        except RuntimeError as e:
            # The trim cannot succeed. Just make sure that the raised exception
            # is due to the trim failure otherwise rethrow.
            if e.args[0] != 'Trim Failed':
                raise

        # Check that the trim did not ignite the SRBs
        self.assertEqual(fdm['propulsion/engine[0]/thrust-lbs'], 0.0)
        self.assertEqual(fdm['propulsion/engine[1]/thrust-lbs'], 0.0)

    def test_trim_on_ground(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_model('c172x')
        fdm['ic/theta-deg'] = 10.0
        fdm.run_ic()
        fdm['ic/theta-deg'] = 0.0
        fdm['simulation/do_simple_trim'] = 2
Пример #15
0
class CheckAircrafts(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def testAircrafts(self):
        aircraft_path = self.sandbox.elude(
            self.sandbox.path_to_jsbsim_file('aircraft'))
        for d in os.listdir(aircraft_path):
            fullpath = os.path.join(aircraft_path, d)

            # Is d a directory ?
            if not os.path.isdir(fullpath):
                continue

            f = os.path.join(aircraft_path, d, append_xml(d))

            # Is f an aircraft definition file ?
            if not CheckXMLFile(f, 'fdm_config'):
                continue

            if d in ('blank'):
                continue

            fdm = CreateFDM(self.sandbox)
            self.assertTrue(fdm.load_model(d),
                            msg='Failed to load aircraft %s' % (d, ))

            for f in os.listdir(fullpath):
                f = os.path.join(aircraft_path, d, f)
                if CheckXMLFile(f, 'initialize'):
                    self.assertTrue(
                        fdm.load_ic(f, False),
                        msg='Failed to load IC %s for aircraft %s' % (f, d))
                    try:
                        fdm.run_ic()
                    except RuntimeError:
                        self.fail('Failed to run IC %s for aircraft %s' %
                                  (f, d))

                    break

            del fdm
Пример #16
0
class CheckAircrafts(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def testAircrafts(self):
        aircraft_path = self.sandbox.elude(self.sandbox.path_to_jsbsim_file('aircraft'))
        for d in os.listdir(aircraft_path):
            fullpath = os.path.join(aircraft_path, d)

            # Is d a directory ?
            if not os.path.isdir(fullpath):
                continue

            f = os.path.join(aircraft_path, d, append_xml(d))

            # Is f an aircraft definition file ?
            if not CheckXMLFile(f, 'fdm_config'):
                continue

            if d in ('blank'):
                continue

            fdm = CreateFDM(self.sandbox)
            self.assertTrue(fdm.load_model(d),
                            msg='Failed to load aircraft %s' % (d,))

            for f in os.listdir(fullpath):
                f = os.path.join(aircraft_path, d, f)
                if CheckXMLFile(f, 'initialize'):
                    self.assertTrue(fdm.load_ic(f, False),
                                    msg='Failed to load IC %s for aircraft %s' %(f,d))
                    try:
                        fdm.run_ic()
                    except RuntimeError:
                        self.fail('Failed to run IC %s for aircraft %s' %(f,d))

                    break

            del fdm
Пример #17
0
class TestHoldDown(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_static_hold_down(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_model('J246')
        aircraft_path = self.sandbox.elude(self.sandbox.path_to_jsbsim_file('aircraft'))
        fdm.load_ic(os.path.join(aircraft_path, 'J246', 'LC39'), False)
        fdm.set_property_value('forces/hold-down', 1.0)
        fdm.run_ic()
        h0 = fdm.get_property_value('position/h-sl-ft')
        t = 0.0

        while t < 420.0:
            fdm.run()
            t = fdm.get_property_value('simulation/sim-time-sec')
            self.assertAlmostEqual(fdm.get_property_value('position/h-sl-ft'),
                                   h0, delta=1E-5)
Пример #18
0
class TestOrbitCheckCase(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox('check_cases', 'orbit')

    def tearDown(self):
        self.sandbox.erase()

    def testOrbitCheckCase(self):
        os.environ['JSBSIM_DEBUG'] = str(0)
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'ball_orbit.xml'))
        fdm.run_ic()

        while fdm.run():
            pass

        ref, current = Table(), Table()
        ref.ReadCSV(self.sandbox.elude(self.sandbox.path_to_jsbsim_file('logged_data', 'BallOut.csv')))
        current.ReadCSV(self.sandbox('BallOut.csv'))

        diff = ref.compare(current)
        self.longMessage = True
        self.assertTrue(diff.empty(), msg='\n'+repr(diff))
Пример #19
0
class TestHoldDown(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_static_hold_down(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_model('J246')
        aircraft_path = self.sandbox.elude(
            self.sandbox.path_to_jsbsim_file('aircraft'))
        fdm.load_ic(os.path.join(aircraft_path, 'J246', 'LC39'), False)
        fdm.set_property_value('forces/hold-down', 1.0)
        fdm.run_ic()
        h0 = fdm.get_property_value('position/h-sl-ft')
        t = 0.0

        while t < 420.0:
            fdm.run()
            t = fdm.get_property_value('simulation/sim-time-sec')
            self.assertAlmostEqual(fdm.get_property_value('position/h-sl-ft'),
                                   h0,
                                   delta=1E-5)
Пример #20
0
class CheckMomentsUpdate(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_moments_update(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'weather-balloon.xml')
        fdm = CreateFDM(self.sandbox)

        fdm.load_script(script_path)
        fdm.run_ic()

        # Moves the radio sonde to modify the CG location
        fdm.set_property_value('inertia/pointmass-location-X-inches', 5.0)

        # Check that the moment is immediately updated accordingly
        fdm.run()
        Fbz = fdm.get_property_value('forces/fbz-buoyancy-lbs')
        CGx = fdm.get_property_value('inertia/cg-x-in') / 12.0 # Converts from in to ft
        Mby = fdm.get_property_value('moments/m-buoyancy-lbsft')
        self.assertTrue(abs(Fbz * CGx + Mby) < 1E-7,
                        msg="Fbz*CGx = %f and Mby = %f do not match" % (-Fbz*CGx, Mby))
Пример #21
0
class TestSimTimeReset(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    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

    def test_script_start_time_0(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(script_path)
        fdm.run_ic()

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

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

        del fdm

    def test_script_start_time(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        tree = et.parse(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find('./run')
        run_tag.attrib['start'] = '1.2'
        tree.write(self.sandbox(script_name))
        fdm = CreateFDM(self.sandbox)

        fdm.load_script(script_name)
        fdm.run_ic()

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

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

        del fdm

    def test_script_no_start_time(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        tree = et.parse(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find('./run')
        # Remove the parameter 'start' from the tag <run>
        del run_tag.attrib['start']
        tree.write(self.sandbox(script_name))
        fdm = CreateFDM(self.sandbox)

        fdm.load_script(script_name)
        fdm.run_ic()

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

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

        del fdm
Пример #22
0
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>
#

import sys
from JSBSim_utils import CreateFDM, Table, SandBox

sandbox = SandBox("check_cases", "orbit")

fdm = CreateFDM(sandbox)
fdm.load_script(sandbox.path_to_jsbsim_file("scripts", "ball_orbit.xml"))
fdm.run_ic()

while fdm.run():
    pass

ref, current = Table(), Table()
ref.ReadCSV(sandbox.elude(sandbox.path_to_jsbsim_file("logged_data", "BallOut.csv")))
current.ReadCSV(sandbox("BallOut.csv"))

diff = ref.compare(current)
if not diff.empty():
    print diff
Пример #23
0
class TestPitotAngle(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    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)
        metrics_tag = tree.getroot().find('./metrics')
        pitot_tag = et.SubElement(metrics_tag, 'pitot_angle')
        pitot_tag.attrib['unit'] = 'DEG'
        pitot_tag.text = '5.0'
        tree.write(self.sandbox('aircraft', aircraft_name,
                                aircraft_name+'.xml'))

        # Read the CAS specified in the IC file
        tree = et.parse(self.sandbox.elude(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

        # 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.get_property_value('ic/vc-kts'),
                               VCAS, delta=1E-7)
        self.assertAlmostEqual(fdm.get_property_value('velocities/vc-kts'),
                               VCAS, delta=1E-7)

    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()
        metrics_tag = root.find('./metrics')
        pitot_tag = et.SubElement(metrics_tag, 'pitot_angle')
        pitot_tag.attrib['unit'] = 'DEG'
        pitot_tag.text = '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 = float(pitot_tag.text) * math.pi / 180.
        weight = fdm.get_property_value('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.set_property_value('ic/h-sl-ft', weight / spring_coeff)
        fdm.set_property_value('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.set_property_value('atmosphere/wind-north-fps',
                                       10. * math.cos(angle) * ca2)
                fdm.set_property_value('atmosphere/wind-east-fps',
                                       10. * math.sin(angle) * ca2)
                fdm.set_property_value('atmosphere/wind-down-fps',
                                       10. * math.sin(angle2))
                fdm.run()

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

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

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

                self.assertAlmostEqual(fdm.get_property_value('velocities/vc-kts'),
                                       max(0.0, vc) / 1.68781, delta=1E-7)
Пример #24
0
class CheckMomentsUpdate(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def CheckCGPosition(self):
        weight = self.fdm.get_property_value('inertia/weight-lbs')
        empty_weight = self.fdm.get_property_value('inertia/empty-weight-lbs')
        contents = self.fdm.get_property_value(
            'buoyant_forces/gas-cell/contents-mol')
        radiosonde_weight = weight - empty_weight - contents * mol2lbs

        CGx = self.fdm.get_property_value('inertia/cg-x-in')
        CGy = self.fdm.get_property_value('inertia/cg-y-in')
        CGz = self.fdm.get_property_value('inertia/cg-z-in')
        X = self.fdm.get_property_value('inertia/pointmass-location-X-inches')
        Y = self.fdm.get_property_value('inertia/pointmass-location-Y-inches')
        Z = self.fdm.get_property_value('inertia/pointmass-location-Z-inches')

        self.assertAlmostEqual(CGx, X * radiosonde_weight / weight, delta=1E-7)
        self.assertAlmostEqual(CGy, Y * radiosonde_weight / weight, delta=1E-7)
        self.assertAlmostEqual(CGz, Z * radiosonde_weight / weight, delta=1E-7)

    def test_moments_update(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                       'weather-balloon.xml')
        self.fdm = CreateFDM(self.sandbox)

        self.fdm.load_script(script_path)
        self.fdm.set_output_directive(
            self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))
        self.fdm.run_ic()

        self.CheckCGPosition()

        dt = self.fdm.get_property_value('simulation/dt')
        ExecuteUntil(self.fdm, 1.0 - 2.0 * dt)

        self.CheckCGPosition()

        # Moves the radio sonde to modify the CG location
        self.fdm.set_property_value('inertia/pointmass-location-X-inches', 5.0)

        # Check that the moment is immediately updated accordingly
        self.fdm.run()
        self.CheckCGPosition()

        Fbx = self.fdm.get_property_value('forces/fbx-buoyancy-lbs')
        Fbz = self.fdm.get_property_value('forces/fbz-buoyancy-lbs')
        CGx = self.fdm.get_property_value(
            'inertia/cg-x-in') / 12.0  # Converts from in to ft
        CGz = self.fdm.get_property_value('inertia/cg-z-in') / 12.0
        Mby = self.fdm.get_property_value('moments/m-buoyancy-lbsft')

        self.assertAlmostEqual(
            Fbx * CGz - Fbz * CGx,
            Mby,
            delta=1E-7,
            msg="Fbx*CGz-Fbz*CGx = %f and Mby = %f do not match" %
            (Fbx * CGz - Fbz * CGx, Mby))

        # One further step to log the same results in the output file
        self.fdm.run()
        self.CheckCGPosition()

        csv = Table()
        csv.ReadCSV(self.sandbox('output.csv'))
        Mby = csv.get_column('M_{Buoyant} (ft-lbs)')[-1]
        Fbx = csv.get_column('F_{Buoyant x} (lbs)')[-1]
        Fbz = csv.get_column('F_{Buoyant z} (lbs)')[-1]

        self.assertAlmostEqual(
            Fbx * CGz - Fbz * CGx,
            Mby,
            delta=1E-7,
            msg="Fbx*CGz-Fbz*CGx = %f and Mby = %f do not match" %
            (Fbx * CGz - Fbz * CGx, Mby))
Пример #25
0
class TestICOverride(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_IC_override(self):
        # Run the script c1724.xml
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1724.xml')

        fdm = CreateFDM(self.sandbox)
        fdm.load_script(script_path)

        vt0 = fdm.get_property_value('ic/vt-kts')

        fdm.run_ic()
        ExecuteUntil(fdm, 1.0)

        # Check that the total velocity exported in the output file matches the IC
        # defined in the initialization file
        ref = Table()
        ref.ReadCSV(self.sandbox('JSBout172B.csv'))

        for col, title in enumerate(ref._lines[0]):
            if title == 'V_{Total} (ft/s)':
                self.assertTrue(
                    abs(ref._lines[1][col] - (vt0 / fpstokts)) < 1E-5,
                    msg=
                    "Original script %s\nThe total velocity is %f. The value %f was expected"
                    % (script_path, ref._lines[1][col], vt0 / fpstokts))
                break
        else:
            self.fail("The total velocity is not exported in %s" %
                      (script_path, ))

        # Now, we will re-run the same test but the IC will be overridden in the scripts
        # The initial total velocity is increased by 1 ft/s
        vt0 += 1.0

        # The script c1724.xml is loaded and the following line is added in it:
        #    <property value="..."> ic/vt-kts </property>
        # The modified script is then saved with the named 'c1724_0.xml'
        tree = et.parse(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find("./run")
        property = et.SubElement(run_tag, 'property')
        property.text = 'ic/vt-kts'
        property.attrib['value'] = str(vt0)
        tree.write(self.sandbox('c1724_0.xml'))

        # Re-run the same check than above. This time we are making sure than the total
        # initial velocity is increased by 1 ft/s
        self.sandbox.delete_csv_files()

        # 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.load_script('c1724_0.xml')

        self.assertTrue(
            abs(fdm.get_property_value('ic/vt-kts') - vt0) < 1E-5,
            msg=
            "Modified script %s\nThe total velocity in the IC (%f) is different from %f"
            % (self.sandbox('JSBout172B.csv'),
               fdm.get_property_value('ic/vt-kts'), vt0))

        fdm.run_ic()
        ExecuteUntil(fdm, 1.0)

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

        for col, title in enumerate(mod._lines[0]):
            if title == 'V_{Total} (ft/s)':
                self.assertTrue(
                    abs(mod._lines[1][col] - (vt0 / fpstokts)) < 1E-5,
                    msg=
                    "Modified script %s\nThe total velocity is %f. The value %f was expected"
                    % (self.sandbox('JSBout172B.csv'), mod._lines[1][col],
                       vt0 / fpstokts))
                break
        else:
            self.fail("The total velocity is not exported in %s" %
                      (sandbox('JSBout172B.csv'), ))
Пример #26
0
class TestSimTimeReset(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    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

    def test_script_start_time_0(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(script_path)
        fdm.run_ic()

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

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

        del fdm

    def test_script_start_time(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        tree = et.parse(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find('./run')
        run_tag.attrib['start'] = '1.2'
        tree.write(self.sandbox(script_name))
        fdm = CreateFDM(self.sandbox)

        fdm.load_script(script_name)
        fdm.run_ic()

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

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

        del fdm

    def test_script_no_start_time(self):
        script_name = 'ball_orbit.xml'
        script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name)
        tree = et.parse(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find('./run')
        # Remove the parameter 'start' from the tag <run>
        del run_tag.attrib['start']
        tree.write(self.sandbox(script_name))
        fdm = CreateFDM(self.sandbox)

        fdm.load_script(script_name)
        fdm.run_ic()

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

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

        del fdm
Пример #27
0
class TestICOverride(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_IC_override(self):
        # Run the script c1724.xml
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1724.xml')

        fdm = CreateFDM(self.sandbox)
        fdm.load_script(script_path)

        vt0 = fdm.get_property_value('ic/vt-kts')

        fdm.run_ic()
        self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'), 0.0)
        self.assertAlmostEqual(fdm.get_property_value('velocities/vt-fps'),
                               vt0 / fpstokts, delta=1E-7)

        ExecuteUntil(fdm, 1.0)

        # Check that the total velocity exported in the output file matches the
        # IC defined in the initialization file
        ref = Table()
        ref.ReadCSV(self.sandbox('JSBout172B.csv'))
        self.assertEqual(ref.get_column('Time')[1], 0.0)
        self.assertAlmostEqual(ref.get_column('V_{Total} (ft/s)')[1],
                               vt0 / fpstokts, delta=1E-7)

        # Now, we will re-run the same test but the IC will be overridden in the
        # script. The initial total velocity is increased by 1 ft/s
        vt0 += 1.0

        # The script c1724.xml is loaded and the following line is added in it:
        #    <property value="..."> ic/vt-kts </property>
        # The modified script is then saved with the named 'c1724_0.xml'
        tree = et.parse(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find("./run")
        property = et.SubElement(run_tag, 'property')
        property.text = 'ic/vt-kts'
        property.attrib['value'] = str(vt0)
        tree.write(self.sandbox('c1724_0.xml'))

        # Re-run the same check than above. This time we are making sure than
        # the total initial velocity is increased by 1 ft/s
        self.sandbox.delete_csv_files()

        # 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.load_script('c1724_0.xml')

        self.assertAlmostEqual(fdm.get_property_value('ic/vt-kts'), vt0,
                               delta=1E-6)

        fdm.run_ic()
        self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'), 0.0)
        self.assertAlmostEqual(fdm.get_property_value('velocities/vt-fps'),
                               vt0 / fpstokts, delta=1E-6)

        ExecuteUntil(fdm, 1.0)

        mod = Table()
        mod.ReadCSV(self.sandbox('JSBout172B.csv'))
        self.assertAlmostEqual(mod.get_column('V_{Total} (ft/s)')[1],
                               vt0 / fpstokts, delta=1E-6)
Пример #28
0
 def setUp(self):
     self.sandbox = SandBox()
Пример #29
0
class TestInputSocket(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                            'c1722.xml')

    def tearDown(self):
        self.sandbox.erase()

    def sanityCheck(self, _tn):
        # Check that the connection has been established
        out = _tn.getOutput()
        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(_tn.sendCommand("help"), '\n')[2:-2])),
                         ['get', 'help', 'hold', 'info', 'iterate', 'quit', 'resume', 'set'])

    def test_no_input(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(self.script_path)
        fdm.run_ic()
        fdm.hold()

        with self.assertRaises(socket.error):
            TelnetInterface(fdm, 5., 1137)

    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)

    def test_script_input(self):
        tree = et.parse(self.sandbox.elude(self.script_path))
        input_tag = et.SubElement(tree.getroot(), 'input')
        input_tag.attrib['port'] = '1138'
        tree.write(self.sandbox('c1722_1.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.load_script('c1722_1.xml')
        fdm.run_ic()
        fdm.hold()

        tn = TelnetInterface(fdm, 5., 1138)
        self.sanityCheck(tn)
Пример #30
0
import os, time, sys, string
import xml.etree.ElementTree as et
from multiprocessing import Process
from scipy import stats
from JSBSim_utils import SandBox, CreateFDM, append_xml, CopyAircraftDef

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

    while fdm.run() and fdm.get_sim_time() < time_limit:
        if fdm.get_property_value('fcs/left-aileron-pos-rad') != 0.0:
            sys.exit(-1)

sandbox = SandBox()

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

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

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

# Now the copy of the aircraft definition file will be altered: the <rate_limit>
Пример #31
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)
Пример #32
0
class TestModelLoading(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def BuildReference(self, script_name):
        # Run the script
        self.script = self.sandbox.path_to_jsbsim_file(os.path.join('scripts',
                                                               script_name))
        self.sandbox.delete_csv_files()
        fdm = CreateFDM(self.sandbox)
        fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests',
                                                                  'output.xml'))
        fdm.load_script(self.script)
        fdm.set_property_value('simulation/randomseed', 0.0)

        fdm.run_ic()
        ExecuteUntil(fdm, 50.0)

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

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

        tree, self.aircraft_name, self.path_to_jsbsim_aircrafts = CopyAircraftDef(self.script, self.sandbox)
        self.aircraft_path = self.sandbox('aircraft', self.aircraft_name)

    def ProcessAndCompare(self, section):
        # Here we determine if the original aircraft definition <section> is
        # inline or read from an external file.
        tree = et.parse(os.path.join(self.path_to_jsbsim_aircrafts,
                                     self.aircraft_name + '.xml'))
        root = tree.getroot()

        # Iterate over all the tags named <section>
        for section_element in root.findall(section):
            if 'file' in section_element.keys():
                self.InsertAndCompare(section_element, tree)
            else:
                self.DetachAndCompare(section_element, tree)

    def DetachAndCompare(self, section_element, tree):
        # Extract <section> from the original aircraft definition file and copy
        # it in a separate XML file 'section.xml'
        section_tree = et.ElementTree(element=section_element)
        if 'name' in section_element.keys():
            section = section_element.attrib['name']
        else:
            section = section_element.tag

        section_tree.write(os.path.join(self.aircraft_path, section+'.xml'),
                           xml_declaration=True)

        # Now, we need to clean up the aircraft definition file from all
        # references to <section>. We just need a single <section> tag that
        # points to the file 'section.xml'
        for element in list(section_element):
            section_element.remove(element)

        section_element.attrib = {'file': section+'.xml'}
        tree.write(os.path.join(self.aircraft_path, self.aircraft_name+'.xml'),
                   xml_declaration=True)

        self.Compare(section)

    def InsertAndCompare(self, section_element, tree):
        file_name = append_xml(section_element.attrib['file'])
        section_file = os.path.join(self.path_to_jsbsim_aircrafts, file_name)

        # If <section> is actually <system>, we need to iterate over all the
        # directories in which the file is allowed to be stored until the file
        # is located.
        if not os.path.exists(section_file) and section_element.tag == 'system':
            section_file = os.path.join(self.path_to_jsbsim_aircrafts, "systems", file_name)
            if not os.path.exists(section_file):
                section_file = self.sandbox.elude(self.sandbox.path_to_jsbsim_file("systems", file_name))

        # The original <section> tag is dropped and replaced by the content of
        # the file.
        section_root = et.parse(section_file).getroot()

        del section_element.attrib['file']
        section_element.attrib.update(section_root.attrib)
        section_element.extend(section_root)

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

        self.Compare(section_element.tag+" file:"+section_file)

    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))

    def test_model_loading(self):
        self.longMessage = True

        self.BuildReference('c1724.xml')
        output_ref = Table()
        output_ref.ReadCSV(self.sandbox('JSBout172B.csv'))

        self.ProcessAndCompare('aerodynamics')
        self.ProcessAndCompare('autopilot')
        self.ProcessAndCompare('flight_control')
        self.ProcessAndCompare('ground_reactions')
        self.ProcessAndCompare('mass_balance')
        self.ProcessAndCompare('metrics')
        self.ProcessAndCompare('propulsion')
        self.ProcessAndCompare('system')

        # The <output> section needs special handling. In addition to the check
        # conducted by ProcessAndCompare with a directive file, we need to
        # verify that the <output> tag has been correctly executed by JSBSim.
        # In the case of the script c1724.xml, this means that the data output
        # in JSBout172B.csv is the same between the reference 'output_ref' and
        # the result 'mod' below where the <output> tag was moved in a separate
        # file.
        self.ProcessAndCompare('output')
        mod = Table()
        mod.ReadCSV(self.sandbox('JSBout172B.csv'))
        diff = output_ref.compare(mod, 0.0)
        self.assertTrue(diff.empty(),
                        msg='\nTesting section "output"\n'+repr(diff))

        self.BuildReference('weather-balloon.xml')
        self.ProcessAndCompare('buoyant_forces')

        self.BuildReference('Concorde_runway_test.xml')
        self.ProcessAndCompare('external_reactions')
Пример #33
0
class TestInputSocket(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'c1722.xml')

    def tearDown(self):
        self.sandbox.erase()

    def sanityCheck(self, _tn):
        # Check that the connection has been established
        out = _tn.getOutput()
        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(_tn.sendCommand("help"), '\n')[2:-2])), [
                        'get', 'help', 'hold', 'info', 'iterate', 'quit',
                        'resume', 'set'
                    ])

    def test_no_input(self):
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(self.script_path)
        fdm.run_ic()
        fdm.hold()

        with self.assertRaises(socket.error):
            TelnetInterface(fdm, 5., 1137)

    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)

    def test_script_input(self):
        tree = et.parse(self.sandbox.elude(self.script_path))
        input_tag = et.SubElement(tree.getroot(), 'input')
        input_tag.attrib['port'] = '1138'
        tree.write(self.sandbox('c1722_1.xml'))

        fdm = CreateFDM(self.sandbox)
        fdm.load_script('c1722_1.xml')
        fdm.run_ic()
        fdm.hold()

        tn = TelnetInterface(fdm, 5., 1138)
        self.sanityCheck(tn)
Пример #34
0
class ResetOutputFiles(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_reset_output_files(self):
      #
      # Regular run that checks the correct CSV file is created
      # We are just checking its existence, not its content. To accelerate the
      # test execution, the simulation is interrupted after 1.0sec of simulated
      # time.
      #
      fdm = CreateFDM(self.sandbox)
      fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml'))

      fdm.run_ic()
      ExecuteUntil(fdm, 1.0)

      self.assertTrue(self.sandbox.exists('JSBout172B.csv'),
                      msg="Standard run: the file 'JSBout172B.csv' should exist.")

      #
      # Reset the simulation and check that iteration number is correctly
      # appended to the filename.
      #
      fdm.reset_to_initial_conditions(1)
      ExecuteUntil(fdm, 1.0)

      self.assertTrue(self.sandbox.exists('JSBout172B_0.csv'),
                      msg="Reset: the file 'JSBout172B_0.csv' should exist.")

      #
      # Change the output filename and check that the naming logic is reset
      # (e.g. that no iteration number is appended to the filename)
      #
      fdm.set_output_filename(0, 'dummy.csv')
      fdm.reset_to_initial_conditions(1)
      ExecuteUntil(fdm, 1.0)

      self.assertTrue(self.sandbox.exists('dummy.csv'),
                      msg="Output name renaming: the file 'dummy.csv' should exist.")

      #
      # Call FGFDMExec::SetOutputFileName() after the simulation is reset. And
      # verify that the new output file name is ignored until the next call to
      # FGOutput::SetStartNewOutput(). This should be so according to the
      # documentation of FGOutput::SetOutputName().
      #
      fdm.reset_to_initial_conditions(1)
      fdm.set_output_filename(0, 'dummyx.csv')
      ExecuteUntil(fdm, 1.0)

      self.assertTrue(not self.sandbox.exists('dummyx.csv'),
                      msg="Late renaming: 'dummyx.csv' should not exist.")
      self.assertTrue(self.sandbox.exists('dummy_0.csv'),
                      msg="Late renaming: 'dummy_0.csv' should exist.")

      #
      # Check that the new filename is taken into account when the simulation is
      # reset.
      #
      fdm.reset_to_initial_conditions(1)
      ExecuteUntil(fdm, 1.0)

      self.assertTrue(self.sandbox.exists('dummyx.csv'),
                      msg="Reset after late renaming: 'dummyx.csv' should exist.")

      #
      # Check against multiple calls to FGFDMExec::SetOutputFileName()
      #
      fdm.set_output_filename(0, 'this_one.csv')
      fdm.set_output_filename(0, 'that_one.csv')
      fdm.reset_to_initial_conditions(1)
      ExecuteUntil(fdm, 1.0)

      self.assertTrue(not self.sandbox.exists('this_one.csv'),
                      msg="Output name overwritten: 'this_one.csv' should not exist.")
      self.assertTrue(self.sandbox.exists('that_one.csv'),
                      msg="Output name overwritten: 'that_one.csv' should exist.")

      #
      # Check again on a brand new FDM
      #
      self.sandbox.delete_csv_files()

      # 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.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml'))

      fdm.run_ic()
      fdm.set_output_filename(0,'oops.csv') # Oops!! Changed my mind
      ExecuteUntil(fdm, 1.0)

      self.assertTrue(not self.sandbox.exists('oops.csv'),
                      msg="New FDM: 'oops.csv' should not exist.")
      self.assertTrue(self.sandbox.exists('JSBout172B.csv'),
                      msg="New FDM: 'JSBout172B.csv' should exist.")

      #
      # The new file name 'oops.csv' has been ignored.
      # Check if it is now taken into account.
      #
      fdm.reset_to_initial_conditions(1)
      ExecuteUntil(fdm, 1.0)

      self.assertTrue(self.sandbox.exists('oops.csv'),
                      msg="Reset new FDM: 'oops.csv' should exist.")
Пример #35
0
 def setUp(self):
     self.sandbox = SandBox()
     self.script_path = self.sandbox.path_to_jsbsim_file('scripts',
                                                         'c1722.xml')
Пример #36
0
class CheckMomentsUpdate(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def CheckCGPosition(self):
        weight = self.fdm.get_property_value('inertia/weight-lbs')
        empty_weight = self.fdm.get_property_value('inertia/empty-weight-lbs')
        contents = self.fdm.get_property_value('buoyant_forces/gas-cell/contents-mol')
        radiosonde_weight = weight - empty_weight - contents * mol2lbs

        CGx = self.fdm.get_property_value('inertia/cg-x-in')
        CGy = self.fdm.get_property_value('inertia/cg-y-in')
        CGz = self.fdm.get_property_value('inertia/cg-z-in')
        X = self.fdm.get_property_value('inertia/pointmass-location-X-inches')
        Y = self.fdm.get_property_value('inertia/pointmass-location-Y-inches')
        Z = self.fdm.get_property_value('inertia/pointmass-location-Z-inches')

        self.assertAlmostEqual(CGx, X * radiosonde_weight / weight, delta = 1E-7)
        self.assertAlmostEqual(CGy, Y * radiosonde_weight / weight, delta = 1E-7)
        self.assertAlmostEqual(CGz, Z * radiosonde_weight / weight, delta = 1E-7)

    def test_moments_update(self):
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'weather-balloon.xml')
        self.fdm = CreateFDM(self.sandbox)

        self.fdm.load_script(script_path)
        self.fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests', 'output.xml'))
        self.fdm.run_ic()

        self.CheckCGPosition()

        dt = self.fdm.get_property_value('simulation/dt')
        ExecuteUntil(self.fdm, 1.0-2.0*dt)

        self.CheckCGPosition()

        # Moves the radio sonde to modify the CG location
        self.fdm.set_property_value('inertia/pointmass-location-X-inches', 5.0)

        # Check that the moment is immediately updated accordingly
        self.fdm.run()
        self.CheckCGPosition()

        Fbx = self.fdm.get_property_value('forces/fbx-buoyancy-lbs')
        Fbz = self.fdm.get_property_value('forces/fbz-buoyancy-lbs')
        CGx = self.fdm.get_property_value('inertia/cg-x-in') / 12.0 # Converts from in to ft
        CGz = self.fdm.get_property_value('inertia/cg-z-in') / 12.0
        Mby = self.fdm.get_property_value('moments/m-buoyancy-lbsft')

        self.assertAlmostEqual(Fbx * CGz - Fbz * CGx, Mby, delta=1E-7,
                               msg="Fbx*CGz-Fbz*CGx = %f and Mby = %f do not match" % (Fbx*CGz-Fbz*CGx, Mby))

        # One further step to log the same results in the output file
        self.fdm.run()
        self.CheckCGPosition()

        csv = Table()
        csv.ReadCSV(self.sandbox('output.csv'))
        Mby = csv.get_column('M_{Buoyant} (ft-lbs)')[-1]
        Fbx = csv.get_column('F_{Buoyant x} (lbs)')[-1]
        Fbz = csv.get_column('F_{Buoyant z} (lbs)')[-1]

        self.assertAlmostEqual(Fbx * CGz - Fbz * CGx, Mby, delta=1E-7,
                               msg="Fbx*CGz-Fbz*CGx = %f and Mby = %f do not match" % (Fbx*CGz-Fbz*CGx, Mby))
Пример #37
0
class ResetOutputFiles(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_reset_output_files(self):
        #
        # Regular run that checks the correct CSV file is created
        # We are just checking its existence, not its content. To accelerate the
        # test execution, the simulation is interrupted after 1.0sec of simulated
        # time.
        #
        fdm = CreateFDM(self.sandbox)
        fdm.load_script(
            self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml'))

        fdm.run_ic()
        ExecuteUntil(fdm, 1.0)

        self.assertTrue(
            self.sandbox.exists('JSBout172B.csv'),
            msg="Standard run: the file 'JSBout172B.csv' should exist.")

        #
        # Reset the simulation and check that iteration number is correctly
        # appended to the filename.
        #
        fdm.reset_to_initial_conditions(1)
        ExecuteUntil(fdm, 1.0)

        self.assertTrue(self.sandbox.exists('JSBout172B_0.csv'),
                        msg="Reset: the file 'JSBout172B_0.csv' should exist.")

        #
        # Change the output filename and check that the naming logic is reset
        # (e.g. that no iteration number is appended to the filename)
        #
        fdm.set_output_filename(0, 'dummy.csv')
        fdm.reset_to_initial_conditions(1)
        ExecuteUntil(fdm, 1.0)

        self.assertTrue(
            self.sandbox.exists('dummy.csv'),
            msg="Output name renaming: the file 'dummy.csv' should exist.")

        #
        # Call FGFDMExec::SetOutputFileName() after the simulation is reset. And
        # verify that the new output file name is ignored until the next call to
        # FGOutput::SetStartNewOutput(). This should be so according to the
        # documentation of FGOutput::SetOutputName().
        #
        fdm.reset_to_initial_conditions(1)
        fdm.set_output_filename(0, 'dummyx.csv')
        ExecuteUntil(fdm, 1.0)

        self.assertTrue(not self.sandbox.exists('dummyx.csv'),
                        msg="Late renaming: 'dummyx.csv' should not exist.")
        self.assertTrue(self.sandbox.exists('dummy_0.csv'),
                        msg="Late renaming: 'dummy_0.csv' should exist.")

        #
        # Check that the new filename is taken into account when the simulation is
        # reset.
        #
        fdm.reset_to_initial_conditions(1)
        ExecuteUntil(fdm, 1.0)

        self.assertTrue(
            self.sandbox.exists('dummyx.csv'),
            msg="Reset after late renaming: 'dummyx.csv' should exist.")

        #
        # Check against multiple calls to FGFDMExec::SetOutputFileName()
        #
        fdm.set_output_filename(0, 'this_one.csv')
        fdm.set_output_filename(0, 'that_one.csv')
        fdm.reset_to_initial_conditions(1)
        ExecuteUntil(fdm, 1.0)

        self.assertTrue(
            not self.sandbox.exists('this_one.csv'),
            msg="Output name overwritten: 'this_one.csv' should not exist.")
        self.assertTrue(
            self.sandbox.exists('that_one.csv'),
            msg="Output name overwritten: 'that_one.csv' should exist.")

        #
        # Check again on a brand new FDM
        #
        self.sandbox.delete_csv_files()

        # 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.load_script(
            self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml'))

        fdm.run_ic()
        fdm.set_output_filename(0, 'oops.csv')  # Oops!! Changed my mind
        ExecuteUntil(fdm, 1.0)

        self.assertTrue(not self.sandbox.exists('oops.csv'),
                        msg="New FDM: 'oops.csv' should not exist.")
        self.assertTrue(self.sandbox.exists('JSBout172B.csv'),
                        msg="New FDM: 'JSBout172B.csv' should exist.")

        #
        # The new file name 'oops.csv' has been ignored.
        # Check if it is now taken into account.
        #
        fdm.reset_to_initial_conditions(1)
        ExecuteUntil(fdm, 1.0)

        self.assertTrue(self.sandbox.exists('oops.csv'),
                        msg="Reset new FDM: 'oops.csv' should exist.")
Пример #38
0
 def setUp(self):
     self.sandbox = SandBox()
Пример #39
0
 def setUp(self):
     self.sandbox = SandBox('check_cases', 'orbit')
Пример #40
0
class TestAccelerometer(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def AddAccelerometersToAircraft(self, script_path):
        tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox)
        system_tag = et.SubElement(tree.getroot(), 'system')
        system_tag.attrib['file'] = 'accelerometers'
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

    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(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find('./run')
        run_tag.attrib['dt'] = '0.1'
        tree.write(self.sandbox(script_name))

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

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

        del fdm

    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

    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

    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)
Пример #41
0
class TestInitialConditions(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_initial_conditions(self):
        # A dictionary that contains the XML tags to extract from the IC file
        # along with the name of the properties that contain the values
        # extracted from the IC file.
        vars = [{'tag': 'vt', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/vt-fps', 'prop': 'velocities/vt-fps',
                 'CSV_header': 'V_{Total} (ft/s)'},
                {'tag': 'ubody', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/u-fps', 'prop': 'velocities/u-fps',
                 'CSV_header': 'UBody'},
                {'tag': 'vbody', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/v-fps', 'prop': 'velocities/v-fps',
                 'CSV_header': 'VBody'},
                {'tag': 'wbody', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/w-fps', 'prop': 'velocities/w-fps',
                 'CSV_header': 'WBody'},
                {'tag': 'vnorth', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/vn-fps', 'prop': 'velocities/v-north-fps',
                 'CSV_header': 'V_{North} (ft/s)'},
                {'tag': 'veast', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/ve-fps', 'prop': 'velocities/v-east-fps',
                 'CSV_header': 'V_{East} (ft/s)'},
                {'tag': 'vdown', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/vd-fps', 'prop': 'velocities/v-down-fps',
                 'CSV_header': 'V_{Down} (ft/s)'},
                {'tag': 'latitude', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/lat-gc-deg', 'prop': 'position/lat-gc-deg',
                 'CSV_header': 'Latitude (deg)'},
                {'tag': 'longitude', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/long-gc-deg', 'prop': 'position/long-gc-deg',
                 'CSV_header': 'Longitude (deg)'},
                {'tag': 'altitude', 'unit': convtoft, 'default_unit': 'FT',
                 'ic_prop': 'ic/h-agl-ft', 'prop': 'position/h-agl-ft',
                 'CSV_header': 'Altitude AGL (ft)'},
                {'tag': 'altitudeAGL', 'unit': convtoft, 'default_unit': 'FT',
                 'ic_prop': 'ic/h-agl-ft', 'prop': 'position/h-agl-ft',
                 'CSV_header': 'Altitude AGL (ft)'},
                {'tag': 'altitudeMSL', 'unit': convtoft, 'default_unit': 'FT',
                 'ic_prop': 'ic/h-sl-ft', 'prop': 'position/h-sl-ft',
                 'CSV_header': 'Altitude ASL (ft)'},
                {'tag': 'phi', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/phi-deg', 'prop': 'attitude/phi-deg',
                 'CSV_header': 'Phi (deg)'},
                {'tag': 'theta', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/theta-deg', 'prop': 'attitude/theta-deg',
                 'CSV_header': 'Theta (deg)'},
                {'tag': 'psi', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/psi-true-deg', 'prop': 'attitude/psi-deg',
                 'CSV_header': 'Psi (deg)'},
                {'tag': 'elevation', 'unit': convtoft, 'default_unit': 'FT',
                 'ic_prop': 'ic/terrain-elevation-ft', 'prop': 'position/terrain-elevation-asl-ft',
                 'CSV_header': 'Terrain Elevation (ft)'}]

        script_path = self.sandbox.path_to_jsbsim_file('scripts')
        for f in os.listdir(self.sandbox.elude(script_path)):
            # TODO These scripts need some further investigation
            if f in ('ZLT-NT-moored-1.xml',):
                continue
            fullpath = os.path.join(self.sandbox.elude(script_path), f)

            # Does f contains a JSBSim script ?
            if not CheckXMLFile(fullpath, 'runscript'):
                continue

            # Read the IC file name from the script
            tree = et.parse(fullpath)
            root = tree.getroot()
            use_tag = root.find('use')

            aircraft_name = use_tag.attrib['aircraft']
            aircraft_path = os.path.join('aircraft', aircraft_name)
            path_to_jsbsim_aircrafts = self.sandbox.elude(self.sandbox.path_to_jsbsim_file(aircraft_path))

            IC_file = append_xml(use_tag.attrib['initialize'])
            IC_tree = et.parse(os.path.join(path_to_jsbsim_aircrafts, IC_file))
            IC_root = IC_tree.getroot()

            # Only testing version 1.0 of init files
            if 'version' in IC_root.attrib:
                if float(IC_root.attrib['version']) == 2.0:
                    continue

            # Extract the IC values from XML
            for var in vars:
                var_tag = IC_root.find('./'+var['tag'])
                var['specified'] = var_tag is not None
                if not var['specified']:
                    var['value'] = 0.0
                    continue

                var['value'] = float(var_tag.text)
                if 'unit' in var_tag.attrib:
                    conv = var['unit'][var_tag.attrib['unit']]
                else:
                    conv = var['unit'][var['default_unit']]
                var['value'] *= conv

            # Generate a CSV file to check that it is correctly initialized with
            # the initial values
            output_tag = et.SubElement(root, 'output')
            output_tag.attrib['name'] = 'check_csv_values.csv'
            output_tag.attrib['type'] = 'CSV'
            output_tag.attrib['rate'] = '10'
            position_tag = et.SubElement(output_tag, 'position')
            position_tag.text = 'ON'
            velocities_tag = et.SubElement(output_tag, 'velocities')
            velocities_tag.text = 'ON'
            tree.write(self.sandbox(f))

            # Initialize the script
            fdm = CreateFDM(self.sandbox)
            fdm.load_script(f)
            fdm.run_ic()

            # Sanity check, we just initialized JSBSim with the ICs, the time
            # must be set to 0.0
            self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'),
                             0.0)

            # Check that the properties (including in 'ic/') have been correctly
            # initialized (i.e. that they contain the value read from the XML
            # file).
            for var in vars:
                if not var['specified']:
                    continue

                value = var['value']
                prop = fdm.get_property_value(var['ic_prop'])
                if var['tag'] == 'psi':
                    if abs(prop - 360.0) <= 1E-8:
                        prop = 0.0
                self.assertAlmostEqual(value, prop, delta=1E-7,
                                       msg="In script %s: %s should be %f but found %f" % (f, var['tag'], value, prop))
                prop = fdm.get_property_value(var['prop'])
                if var['tag'] == 'psi':
                    if abs(prop - 360.0) <= 1E-8:
                        prop = 0.0
                self.assertAlmostEqual(value, prop, delta=1E-7,
                                       msg="In script %s: %s should be %f but found %f" % (f, var['tag'], value, prop))

            # Execute the first second of the script. This is to make sure that
            # the CSV file is open and the ICs have been written in it.
            ExecuteUntil(fdm, 1.0)

            # Copies the CSV file content in a table
            ref = pd.read_csv(self.sandbox('check_csv_values.csv'))

            # Sanity check: make sure that the time step 0.0 has been copied in
            # the CSV file.
            self.assertEqual(ref['Time'][0], 0.0)

            # Check that the value in the CSV file equals the value read from
            # the IC file.
            for var in vars:
                if not var['specified']:
                    continue

                value = var['value']
                csv_value = ref[var['CSV_header']][0]
                if var['tag'] == 'psi':
                    if abs(csv_value - 360.0) <= 1E-8:
                        csv_value = 0.0
                self.assertAlmostEqual(value, csv_value, delta=1E-7,
                                       msg="In script %s: %s should be %f but found %f" % (f, var['tag'], value, csv_value))

            del fdm
Пример #42
0
class TestFuelTanksInertia(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    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))
Пример #43
0
 def setUp(self):
     self.sandbox = SandBox()
     self.scripts = 0
Пример #44
0
class TestPitotAngle(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    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)
        metrics_tag = tree.getroot().find('./metrics')
        pitot_tag = et.SubElement(metrics_tag, 'pitot_angle')
        pitot_tag.attrib['unit'] = 'DEG'
        pitot_tag.text = '5.0'
        tree.write(
            self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml'))

        # Read the CAS specified in the IC file
        tree = et.parse(self.sandbox.elude(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

        # 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.get_property_value('ic/vc-kts'),
                               VCAS,
                               delta=1E-7)
        self.assertAlmostEqual(fdm.get_property_value('velocities/vc-kts'),
                               VCAS,
                               delta=1E-7)

    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()
        metrics_tag = root.find('./metrics')
        pitot_tag = et.SubElement(metrics_tag, 'pitot_angle')
        pitot_tag.attrib['unit'] = 'DEG'
        pitot_tag.text = '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 = float(pitot_tag.text) * math.pi / 180.
        weight = fdm.get_property_value('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.set_property_value('ic/h-sl-ft', weight / spring_coeff)
        fdm.set_property_value('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.set_property_value('atmosphere/wind-north-fps',
                                       10. * math.cos(angle) * ca2)
                fdm.set_property_value('atmosphere/wind-east-fps',
                                       10. * math.sin(angle) * ca2)
                fdm.set_property_value('atmosphere/wind-down-fps',
                                       10. * math.sin(angle2))
                fdm.run()

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

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

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

                self.assertAlmostEqual(
                    fdm.get_property_value('velocities/vc-kts'),
                    max(0.0, vc) / 1.68781,
                    delta=1E-7)
Пример #45
0
# Regression test that checks that output file names modifications made through
# FGFMExec::SetOutputFileName() are properly handled.
#
# Rules that are checked :
#  1. FGFDMExec::SetOutputFileName() change the name to what it has been
#     instructed to use (that's a minimum !)
#  2. Multiple calls to FGFDMExec::SetOutputFileName() are properly handled e.g.
#     the name used is the last one sent via the method.
#  3. If a call to FGFDMExec::SetOutputFileName() is made *after* the simulation
#     has been initialized (i.e. after FGModel::InitModel() is called) then it
#     is ignored until the next call to FGMFDMExec::InitModel().

import sys
from JSBSim_utils import CreateFDM, ExecuteUntil, SandBox

sandbox = SandBox()

#
# Regular run that checks the correct CSV file is created
# We are just checking its existence, not its content. To accelerate the test
# execution, the simulation is interrupted after 1.0sec of simulated time.
#
fdm = CreateFDM(sandbox)
fdm.load_script(sandbox.path_to_jsbsim_file('scripts', 'c1722.xml'))

fdm.run_ic()
ExecuteUntil(fdm, 1.0)

if not sandbox.exists('JSBout172B.csv'):
  print "Standard run: the file 'JSBout172B.csv' should exist."
  sys.exit(-1) # 'make test' will report the test failed.
Пример #46
0
class CheckFGBug1503(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()
        self.script_path = self.sandbox.path_to_jsbsim_file("scripts", "c1724.xml")

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

    def tearDown(self):
        self.sandbox.erase()

    def ScriptExecution(self, fdm, time_limit=1e9):
        fdm.load_script(self.script_path)
        fdm.run_ic()

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

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

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

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

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

        self.ScriptExecution(fdm, 1.0)

        fdm.set_property_value(input_prop, 1.0)

        self.CheckRateValue(fdm, output_prop, incr_limit)

        fdm.set_property_value(input_prop, 0.0)
        self.CheckRateValue(fdm, output_prop, decr_limit)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # First check with rate_limit set to 0.1

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

        output_file = self.sandbox("aircraft", self.aircraft_name, self.aircraft_name + ".xml")
        tree.write(output_file)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.CheckRateLimit(input_prop, output_prop, 0.15, -0.05)
Пример #47
0
class TestICOverride(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_IC_override(self):
        # Run the script c1724.xml
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1724.xml')

        fdm = CreateFDM(self.sandbox)
        fdm.load_script(script_path)

        vt0 = fdm.get_property_value('ic/vt-kts')

        fdm.run_ic()
        self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'),
                         0.0)
        self.assertAlmostEqual(fdm.get_property_value('velocities/vt-fps'),
                               vt0 / fpstokts,
                               delta=1E-7)

        ExecuteUntil(fdm, 1.0)

        # Check that the total velocity exported in the output file matches the
        # IC defined in the initialization file
        ref = Table()
        ref.ReadCSV(self.sandbox('JSBout172B.csv'))
        self.assertEqual(ref.get_column('Time')[1], 0.0)
        self.assertAlmostEqual(ref.get_column('V_{Total} (ft/s)')[1],
                               vt0 / fpstokts,
                               delta=1E-7)

        # Now, we will re-run the same test but the IC will be overridden in the
        # script. The initial total velocity is increased by 1 ft/s
        vt0 += 1.0

        # The script c1724.xml is loaded and the following line is added in it:
        #    <property value="..."> ic/vt-kts </property>
        # The modified script is then saved with the named 'c1724_0.xml'
        tree = et.parse(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find("./run")
        property = et.SubElement(run_tag, 'property')
        property.text = 'ic/vt-kts'
        property.attrib['value'] = str(vt0)
        tree.write(self.sandbox('c1724_0.xml'))

        # Re-run the same check than above. This time we are making sure than
        # the total initial velocity is increased by 1 ft/s
        self.sandbox.delete_csv_files()

        # 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.load_script('c1724_0.xml')

        self.assertAlmostEqual(fdm.get_property_value('ic/vt-kts'),
                               vt0,
                               delta=1E-6)

        fdm.run_ic()
        self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'),
                         0.0)
        self.assertAlmostEqual(fdm.get_property_value('velocities/vt-fps'),
                               vt0 / fpstokts,
                               delta=1E-6)

        ExecuteUntil(fdm, 1.0)

        mod = Table()
        mod.ReadCSV(self.sandbox('JSBout172B.csv'))
        self.assertAlmostEqual(mod.get_column('V_{Total} (ft/s)')[1],
                               vt0 / fpstokts,
                               delta=1E-6)
Пример #48
0
class CheckFGBug1503(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()
        self.script_path = self.sandbox.path_to_jsbsim_file(
            'scripts', 'c1724.xml')

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

    def tearDown(self):
        self.sandbox.erase()

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

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

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

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

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

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

        self.ScriptExecution(fdm, 1.0)

        fdm.set_property_value(input_prop, 1.0)

        self.CheckRateValue(fdm, output_prop, incr_limit)

        fdm.set_property_value(input_prop, 0.0)
        self.CheckRateValue(fdm, output_prop, decr_limit)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # First check with rate_limit set to 0.1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.CheckRateLimit(input_prop, output_prop, 0.15, -0.05)
Пример #49
0
class TestICOverride(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_IC_override(self):
        # Run the script c1724.xml
        script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1724.xml')

        fdm = CreateFDM(self.sandbox)
        fdm.load_script(script_path)

        vt0 = fdm.get_property_value('ic/vt-kts')

        fdm.run_ic()
        ExecuteUntil(fdm, 1.0)

        # Check that the total velocity exported in the output file matches the IC
        # defined in the initialization file
        ref = Table()
        ref.ReadCSV(self.sandbox('JSBout172B.csv'))

        for col, title in enumerate(ref._lines[0]):
            if title == 'V_{Total} (ft/s)':
                self.assertTrue(abs(ref._lines[1][col] - (vt0 / fpstokts)) < 1E-5,
                                msg="Original script %s\nThe total velocity is %f. The value %f was expected" % (script_path, ref._lines[1][col], vt0 / fpstokts))
                break
        else:
            self.fail("The total velocity is not exported in %s" % (script_path,))

        # Now, we will re-run the same test but the IC will be overridden in the scripts
        # The initial total velocity is increased by 1 ft/s
        vt0 += 1.0

        # The script c1724.xml is loaded and the following line is added in it:
        #    <property value="..."> ic/vt-kts </property>
        # The modified script is then saved with the named 'c1724_0.xml'
        tree = et.parse(self.sandbox.elude(script_path))
        run_tag = tree.getroot().find("./run")
        property = et.SubElement(run_tag, 'property')
        property.text = 'ic/vt-kts'
        property.attrib['value'] = str(vt0)
        tree.write(self.sandbox('c1724_0.xml'))

        # Re-run the same check than above. This time we are making sure than the total
        # initial velocity is increased by 1 ft/s
        self.sandbox.delete_csv_files()

        # 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.load_script('c1724_0.xml')

        self.assertTrue(abs(fdm.get_property_value('ic/vt-kts') - vt0) < 1E-5,
                        msg="Modified script %s\nThe total velocity in the IC (%f) is different from %f" % (self.sandbox('JSBout172B.csv'), fdm.get_property_value('ic/vt-kts'), vt0))

        fdm.run_ic()
        ExecuteUntil(fdm, 1.0)

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

        for col, title in enumerate(mod._lines[0]):
            if title == 'V_{Total} (ft/s)':
                self.assertTrue(abs(mod._lines[1][col] - (vt0 / fpstokts)) < 1E-5,
                                msg="Modified script %s\nThe total velocity is %f. The value %f was expected" % (self.sandbox('JSBout172B.csv'), mod._lines[1][col], vt0 / fpstokts))
                break
        else:
            self.fail("The total velocity is not exported in %s" % (sandbox('JSBout172B.csv'),))
Пример #50
0
class TestInitialConditions(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

    def tearDown(self):
        self.sandbox.erase()

    def test_initial_conditions(self):
        prop_output_to_CSV = ['velocities/vc-kts']
        # A dictionary that contains the XML tags to extract from the IC file
        # along with the name of the properties that contain the values
        # extracted from the IC file.
        vars = [{'tag': 'vt', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/vt-fps', 'prop': 'velocities/vt-fps',
                 'CSV_header': 'V_{Total} (ft/s)'},
                {'tag': 'vc', 'unit': convtokts, 'default_unit': 'KTS',
                 'ic_prop': 'ic/vc-kts', 'prop': 'velocities/vc-kts',
                 'CSV_header': '/fdm/jsbsim/velocities/vc-kts'},
                {'tag': 'ubody', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/u-fps', 'prop': 'velocities/u-fps',
                 'CSV_header': 'UBody'},
                {'tag': 'vbody', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/v-fps', 'prop': 'velocities/v-fps',
                 'CSV_header': 'VBody'},
                {'tag': 'wbody', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/w-fps', 'prop': 'velocities/w-fps',
                 'CSV_header': 'WBody'},
                {'tag': 'vnorth', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/vn-fps', 'prop': 'velocities/v-north-fps',
                 'CSV_header': 'V_{North} (ft/s)'},
                {'tag': 'veast', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/ve-fps', 'prop': 'velocities/v-east-fps',
                 'CSV_header': 'V_{East} (ft/s)'},
                {'tag': 'vdown', 'unit': convtofps, 'default_unit': 'FT/SEC',
                 'ic_prop': 'ic/vd-fps', 'prop': 'velocities/v-down-fps',
                 'CSV_header': 'V_{Down} (ft/s)'},
                {'tag': 'latitude', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/lat-gc-deg', 'prop': 'position/lat-gc-deg',
                 'CSV_header': 'Latitude (deg)'},
                {'tag': 'longitude', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/long-gc-deg', 'prop': 'position/long-gc-deg',
                 'CSV_header': 'Longitude (deg)'},
                {'tag': 'altitude', 'unit': convtoft, 'default_unit': 'FT',
                 'ic_prop': 'ic/h-agl-ft', 'prop': 'position/h-agl-ft',
                 'CSV_header': 'Altitude AGL (ft)'},
                {'tag': 'altitudeAGL', 'unit': convtoft, 'default_unit': 'FT',
                 'ic_prop': 'ic/h-agl-ft', 'prop': 'position/h-agl-ft',
                 'CSV_header': 'Altitude AGL (ft)'},
                {'tag': 'altitudeMSL', 'unit': convtoft, 'default_unit': 'FT',
                 'ic_prop': 'ic/h-sl-ft', 'prop': 'position/h-sl-ft',
                 'CSV_header': 'Altitude ASL (ft)'},
                {'tag': 'phi', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/phi-deg', 'prop': 'attitude/phi-deg',
                 'CSV_header': 'Phi (deg)'},
                {'tag': 'theta', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/theta-deg', 'prop': 'attitude/theta-deg',
                 'CSV_header': 'Theta (deg)'},
                {'tag': 'psi', 'unit': convtodeg, 'default_unit': 'RAD',
                 'ic_prop': 'ic/psi-true-deg', 'prop': 'attitude/psi-deg',
                 'CSV_header': 'Psi (deg)'},
                {'tag': 'elevation', 'unit': convtoft, 'default_unit': 'FT',
                 'ic_prop': 'ic/terrain-elevation-ft',
                 'prop': 'position/terrain-elevation-asl-ft',
                 'CSV_header': 'Terrain Elevation (ft)'}]

        script_path = self.sandbox.path_to_jsbsim_file('scripts')
        for f in os.listdir(self.sandbox.elude(script_path)):
            # TODO These scripts need some further investigation
            if f in ('ZLT-NT-moored-1.xml',
                     '737_cruise_steady_turn_simplex.xml'):
                continue
            fullpath = os.path.join(self.sandbox.elude(script_path), f)

            # Does f contains a JSBSim script ?
            if not CheckXMLFile(fullpath, 'runscript'):
                continue

            # Read the IC file name from the script
            tree = et.parse(fullpath)
            root = tree.getroot()
            use_tag = root.find('use')

            aircraft_name = use_tag.attrib['aircraft']
            aircraft_path = os.path.join('aircraft', aircraft_name)
            path_to_jsbsim_aircrafts = self.sandbox.elude(self.sandbox.path_to_jsbsim_file(aircraft_path))

            IC_file = append_xml(use_tag.attrib['initialize'])
            IC_tree = et.parse(os.path.join(path_to_jsbsim_aircrafts, IC_file))
            IC_root = IC_tree.getroot()

            # Only testing version 1.0 of init files
            if 'version' in IC_root.attrib:
                if float(IC_root.attrib['version']) == 2.0:
                    continue

            # Extract the IC values from XML
            for var in vars:
                var_tag = IC_root.find('./'+var['tag'])
                var['specified'] = var_tag is not None
                if not var['specified']:
                    var['value'] = 0.0
                    continue

                var['value'] = float(var_tag.text)
                if 'unit' in var_tag.attrib:
                    conv = var['unit'][var_tag.attrib['unit']]
                else:
                    conv = var['unit'][var['default_unit']]
                var['value'] *= conv

            # Generate a CSV file to check that it is correctly initialized
            # with the initial values
            output_tag = et.SubElement(root, 'output')
            output_tag.attrib['name'] = 'check_csv_values.csv'
            output_tag.attrib['type'] = 'CSV'
            output_tag.attrib['rate'] = '10'
            position_tag = et.SubElement(output_tag, 'position')
            position_tag.text = 'ON'
            velocities_tag = et.SubElement(output_tag, 'velocities')
            velocities_tag.text = 'ON'
            for props in prop_output_to_CSV:
                property_tag = et.SubElement(output_tag, 'property')
                property_tag.text = props
            tree.write(self.sandbox(f))

            # Initialize the script
            fdm = CreateFDM(self.sandbox)
            fdm.load_script(f)
            fdm.run_ic()

            # Sanity check, we just initialized JSBSim with the ICs, the time
            # must be set to 0.0
            self.assertEqual(fdm.get_property_value('simulation/sim-time-sec'),
                             0.0)

            # Check that the properties (including in 'ic/') have been
            # correctly initialized (i.e. that they contain the value read from
            # the XML file).
            for var in vars:
                if not var['specified']:
                    continue

                value = var['value']
                prop = fdm.get_property_value(var['ic_prop'])
                if var['tag'] == 'psi':
                    if abs(prop - 360.0) <= 1E-8:
                        prop = 0.0
                self.assertAlmostEqual(value, prop, delta=1E-7,
                                       msg="In script %s: %s should be %f but found %f" % (f, var['tag'], value, prop))
                prop = fdm.get_property_value(var['prop'])
                if var['tag'] == 'psi':
                    if abs(prop - 360.0) <= 1E-8:
                        prop = 0.0
                self.assertAlmostEqual(value, prop, delta=1E-7,
                                       msg="In script %s: %s should be %f but found %f" % (f, var['tag'], value, prop))

            # Execute the first second of the script. This is to make sure that
            # the CSV file is open and the ICs have been written in it.
            try:
                ExecuteUntil(fdm, 1.0)
            except RuntimeError as e:
                if e.args[0] == 'Trim Failed':
                    self.fail("Trim failed in script %s" % (f,))
                else:
                    raise

            # Copies the CSV file content in a table
            ref = pd.read_csv(self.sandbox('check_csv_values.csv'))

            # Sanity check: make sure that the time step 0.0 has been copied in
            # the CSV file.
            self.assertEqual(ref['Time'][0], 0.0)

            # Check that the value in the CSV file equals the value read from
            # the IC file.
            for var in vars:
                if not var['specified']:
                    continue

                value = var['value']
                csv_value = ref[var['CSV_header']][0]
                if var['tag'] == 'psi':
                    if abs(csv_value - 360.0) <= 1E-8:
                        csv_value = 0.0
                self.assertAlmostEqual(value, csv_value, delta=1E-7,
                                       msg="In script %s: %s should be %f but found %f" % (f, var['tag'], value, csv_value))

            del fdm
Пример #51
0
class CheckOutputRate(unittest.TestCase):
    def setUp(self):
        self.sandbox = SandBox()

        self.fdm = CreateFDM(self.sandbox)
        self.script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml')

        # Read the time step 'dt' from the script file
        self.tree = et.parse(self.sandbox.elude(self.script_path))
        root = self.tree.getroot()
        use_tag = root.find("./use")
        aircraft_name = use_tag.attrib['aircraft']
        self.run_tag = root.find("./run")
        self.dt = float(self.run_tag.attrib['dt'])

        # Read the date at which the trim will be run
        event_tags = root.findall('./run/event')
        for event in event_tags:
            if event.attrib['name'] == 'Trim':
                cond_tag = event.find('./condition')
                self.trim_date = float(string.split(cond_tag.text)[-1])
                break

        # Read the output rate and the output file from the aircraft file
        aircraft_path = self.sandbox.path_to_jsbsim_file('aircraft', aircraft_name,
                                                         append_xml(aircraft_name))
        tree = et.parse(self.sandbox.elude(aircraft_path))
        output_tag = tree.getroot().find("./output")
        self.output_file = self.sandbox(output_tag.attrib['name'])
        self.rateHz = float(output_tag.attrib['rate'])
        self.rate = int(1.0 / (self.rateHz * self.dt))

    def tearDown(self):
        del self.fdm
        self.sandbox.erase()

    def testOutputRate(self):
        self.fdm.load_script(self.script_path)

        # Check that the output is enabled by default
        self.assertEqual(self.fdm.get_property_value("simulation/output/enabled"),
                         1.0)

        # Check that the rate is consistent with the values extracted from the
        # script and the aircraft definition
        self.assertAlmostEqual(self.fdm.get_property_value("simulation/output/log_rate_hz"),
                               self.rateHz, delta=1E-5)

        self.fdm.run_ic()

        for i in xrange(self.rate):
            self.fdm.run()

        output = Table()
        output.ReadCSV(self.output_file)

        # According to the settings, the output file must contain 2 lines in
        # addition to the headers :
        # 1. The initial conditions
        # 2. The output after 'rate' iterations
        self.assertEqual(output.get_column(0)[1], 0.0)
        self.assertEqual(output.get_column(0)[2], self.rate * self.dt)
        self.assertEqual(output.get_column(0)[2],
                         self.fdm.get_property_value("simulation/sim-time-sec"))

    def testDisablingOutput(self):
        self.fdm.load_script(self.script_path)

        # Disables the output during the initialization
        self.fdm.set_property_value("simulation/output/enabled", 0.0)
        self.fdm.run_ic()
        self.fdm.set_property_value("simulation/output/enabled", 1.0)

        for i in xrange(self.rate):
            self.fdm.run()

        output = Table()
        output.ReadCSV(self.output_file)

        # According to the settings, the output file must contain 1 line in
        # addition to the headers :
        # 1. The output after 'rate' iterations
        self.assertEqual(output.get_column(0)[1],
                         self.fdm.get_property_value("simulation/sim-time-sec"))

    def testTrimRestoresOutputSettings(self):
        self.fdm.load_script(self.script_path)

        # Disables the output during the initialization
        self.fdm.set_property_value("simulation/output/enabled", 0.0)
        self.fdm.run_ic()

        # Check that the output remains disabled even after the trim is
        # executed
        while self.fdm.get_property_value("simulation/sim-time-sec") < self.trim_date + 2.0*self.dt:
            self.fdm.run()
            self.assertEqual(self.fdm.get_property_value("simulation/output/enabled"),
                             0.0)

        # Re-enable the output and check that the output rate is unaffected by
        # the previous operations
        self.fdm.set_property_value("simulation/output/enabled", 1.0)
        frame = int(self.fdm.get_property_value("simulation/frame"))

        for i in xrange(self.rate):
            self.fdm.run()

        output = Table()
        output.ReadCSV(self.output_file)

        # The frame at which the data is logged must be the next multiple of
        # the output rate
        self.assertEqual(int(output.get_column(0)[1]/self.dt),
                         (1 + frame/self.rate)*self.rate)

    def testDisablingOutputInScript(self):
        property = et.SubElement(self.run_tag, 'property')
        property.text = 'simulation/output/enabled'
        property.attrib['value'] = "0.0"
        self.tree.write(self.sandbox('c1722_0.xml'))

        self.fdm.load_script('c1722_0.xml')

        # Check that the output is disabled
        self.assertEqual(self.fdm.get_property_value("simulation/output/enabled"),
                         0.0)

        self.fdm.run_ic()
        self.fdm.set_property_value("simulation/output/enabled", 1.0)

        for i in xrange(self.rate):
            self.fdm.run()

        output = Table()
        output.ReadCSV(self.output_file)

        # According to the settings, the output file must contain 1 line in
        # addition to the headers :
        # 1. The output after 'rate' iterations
        self.assertEqual(output.get_column(0)[1],
                         self.fdm.get_property_value("simulation/sim-time-sec"))
Пример #52
0
 def setUp(self):
     self.sandbox = SandBox('check_cases', 'orbit')