def test_fuel_tanks_content(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml') fdm = CreateFDM(self.sandbox) fdm.load_script(script_path) fdm.run_ic() tree = et.parse(script_path) use_tag = tree.getroot().find('use') aircraft_name = use_tag.attrib['aircraft'] aircraft_path = self.sandbox.path_to_jsbsim_file('aircraft', aircraft_name) aircraft_tree = et.parse(os.path.join(aircraft_path, aircraft_name+'.xml')) total_fuel_quantity = 0.0 total_oxidizer_quantity = 0.0 for tank in aircraft_tree.findall('propulsion/tank'): contents = float(tank.find('contents').text) if tank.attrib['type'] == "FUEL": total_fuel_quantity += contents elif tank.attrib['type'] == 'OXIDIZER': total_oxidizer_quantity += contents self.assertAlmostEqual(fdm['propulsion/total-fuel-lbs'], total_fuel_quantity) self.assertAlmostEqual(fdm['propulsion/total-oxidizer-lbs'], total_oxidizer_quantity)
def test_wind_frame(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'ball_chute.xml') fdm = CreateFDM(self.sandbox) fdm.load_script(script_path) fdm.run_ic() self.assertAlmostEqual( fdm['external_reactions/parachute/location-x-in'], 12.0) self.assertAlmostEqual( fdm['external_reactions/parachute/location-y-in'], 0.0) self.assertAlmostEqual( fdm['external_reactions/parachute/location-z-in'], 0.0) self.assertAlmostEqual(fdm['external_reactions/parachute/x'], -1.0) self.assertAlmostEqual(fdm['external_reactions/parachute/y'], 0.0) self.assertAlmostEqual(fdm['external_reactions/parachute/z'], 0.0) while fdm.run(): Tw2b = fdm.get_auxiliary().get_Tw2b() mag = fdm['aero/qbar-psf'] * fdm[ 'fcs/parachute_reef_pos_norm'] * 20.0 f = Tw2b * np.mat([-1.0, 0.0, 0.0]).T * mag self.assertAlmostEqual(fdm['forces/fbx-external-lbs'], f[0, 0]) self.assertAlmostEqual(fdm['forces/fby-external-lbs'], f[1, 0]) self.assertAlmostEqual(fdm['forces/fbz-external-lbs'], f[2, 0]) m = np.cross(self.getLeverArm(fdm, 'parachute'), np.array([f[0, 0], f[1, 0], f[2, 0]])) self.assertAlmostEqual(fdm['moments/l-external-lbsft'], m[0]) self.assertAlmostEqual(fdm['moments/m-external-lbsft'], m[1]) self.assertAlmostEqual(fdm['moments/n-external-lbsft'], m[2])
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))
def test_CAS_ic(self): script_name = 'Short_S23_3.xml' script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name) # Add a Pitot angle to the Short S23 tree, aircraft_name, path_to_jsbsim_aircrafts = CopyAircraftDef(script_path, self.sandbox) self.addPitotTube(tree.getroot(), 5.0) tree.write(self.sandbox('aircraft', aircraft_name, aircraft_name+'.xml')) # Read the CAS specified in the IC file tree = et.parse(script_path) use_element = tree.getroot().find('use') IC_file = use_element.attrib['initialize'] tree = et.parse(os.path.join(path_to_jsbsim_aircrafts, append_xml(IC_file))) vc_tag = tree.getroot().find('./vc') VCAS = float(vc_tag.text) if 'unit' in vc_tag.attrib and vc_tag.attrib['unit'] == 'FT/SEC': VCAS /= 1.68781 # Converts in kts # Run the IC and check that the model is initialized correctly fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) fdm.run_ic() self.assertAlmostEqual(fdm['ic/vc-kts'], VCAS, delta=1E-7) self.assertAlmostEqual(fdm['velocities/vc-kts'], VCAS, delta=1E-7)
def testOrbit(self): script_name = 'ball_orbit.xml' script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name) self.AddAccelerometersToAircraft(script_path) # The time step is too small in ball_orbit so let's increase it to 0.1s # for a quicker run tree = et.parse(script_path) run_tag = tree.getroot().find('./run') run_tag.attrib['dt'] = '0.1' tree.write(script_name) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_name) # Switch the accel on fdm['fcs/accelerometer/on'] = 1.0 fdm.run_ic() while fdm.run(): self.assertAlmostEqual(fdm['fcs/accelerometer/X'], 0.0, delta=1E-8) self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], 0.0, delta=1E-8) self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], 0.0, delta=1E-8) self.assertAlmostEqual(fdm['accelerations/a-pilot-x-ft_sec2'], 0.0, delta=1E-8) self.assertAlmostEqual(fdm['accelerations/a-pilot-y-ft_sec2'], 0.0, delta=1E-8) self.assertAlmostEqual(fdm['accelerations/a-pilot-z-ft_sec2'], 0.0, delta=1E-8) del fdm
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 = pd.read_csv('BallOut.csv', index_col=0) 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 = pd.read_csv('BallOut.csv', index_col=0) # Check the data are matching i.e. the time steps are the same between # the two data sets and that the output data are also the same. self.assertTrue(isDataMatching(ref, current)) # Find all the data that are differing by more than 1E-8 between the # two data sets. diff = FindDifferences(ref, current, 1E-8) self.longMessage = True self.assertEqual(len(diff), 0, msg='\n' + diff.to_string())
def test_hold_down_with_gnd_reactions(self): fdm = CreateFDM(self.sandbox) fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'c1721.xml')) fdm.run_ic() ExecuteUntil(fdm, 0.25) fdm['forces/hold-down'] = 1.0 h0 = fdm['position/h-sl-ft'] pitch = fdm['attitude/pitch-rad'] roll = fdm['attitude/roll-rad'] heading = fdm['attitude/heading-true-rad'] while fdm['simulation/sim-time-sec'] < 2.0: fdm.run() self.assertAlmostEqual(fdm['accelerations/pdot-rad_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/qdot-rad_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/rdot-rad_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/udot-ft_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/vdot-ft_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/wdot-ft_sec2'], 0.0) self.assertAlmostEqual(fdm['position/h-sl-ft'], h0, delta=1E-6) self.assertAlmostEqual(fdm['attitude/pitch-rad'], pitch) self.assertAlmostEqual(fdm['attitude/roll-rad'], roll) self.assertAlmostEqual(fdm['attitude/heading-true-rad'], heading)
def test_output(self): tree = et.parse(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('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('JSBout172B.csv', index_col=0) test = pd.read_csv('test.csv', index_col=0) pname = '/fdm/jsbsim/' + property_tag.text ref = orig[pname] mod = test[pname] # Check the data are matching i.e. the time steps are the same between # the two data sets. self.assertTrue(isDataMatching(ref, mod)) # Find all the data that are differing by more than 1E-8 between the # two data sets. delta = pd.concat([np.abs(ref - mod), ref, mod], axis=1) delta.columns = ['delta', 'ref value', 'value'] diff = delta[delta['delta'] > 1E-8] self.longMessage = True self.assertEqual(len(diff), 0, msg='\n'+diff.to_string())
def SubProcessScriptExecution(sandbox, script_path): fdm = CreateFDM(sandbox) fdm.load_script(script_path) fdm.run_ic() while fdm.run(): pass
def test_hold_down_with_gnd_reactions(self): fdm = CreateFDM(self.sandbox) fdm.load_script( self.sandbox.path_to_jsbsim_file('scripts', 'c1721.xml')) fdm.run_ic() ExecuteUntil(fdm, 0.25) fdm['forces/hold-down'] = 1.0 h0 = fdm['position/h-sl-ft'] pitch = fdm['attitude/pitch-rad'] roll = fdm['attitude/roll-rad'] heading = fdm['attitude/heading-true-rad'] while fdm['simulation/sim-time-sec'] < 2.0: fdm.run() self.assertAlmostEqual(fdm['accelerations/pdot-rad_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/qdot-rad_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/rdot-rad_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/udot-ft_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/vdot-ft_sec2'], 0.0) self.assertAlmostEqual(fdm['accelerations/wdot-ft_sec2'], 0.0) self.assertAlmostEqual(fdm['position/h-sl-ft'], h0, delta=1E-6) self.assertAlmostEqual(fdm['attitude/pitch-rad'], pitch) self.assertAlmostEqual(fdm['attitude/roll-rad'], roll) self.assertAlmostEqual(fdm['attitude/heading-true-rad'], heading)
def Compare(self, section): # Rerun the script with the modified aircraft definition self.sandbox.delete_csv_files() fdm = CreateFDM(self.sandbox) # We need to tell JSBSim that the aircraft definition is located in the # directory build/.../aircraft fdm.set_aircraft_path('aircraft') fdm.set_output_directive( self.sandbox.path_to_jsbsim_file('tests', 'output.xml')) fdm.load_script(self.script) fdm['simulation/randomseed'] = 0.0 fdm.run_ic() ExecuteUntil(fdm, 50.0) mod = pd.read_csv('output.csv', index_col=0) # Check the data are matching i.e. the time steps are the same between # the two data sets and that the output data are also the same. self.assertTrue(isDataMatching(self.ref, mod)) # Whether the data is read from the aircraft definition file or from an # external file, the results shall be exactly identical. Hence the # precision set to 0.0. diff = FindDifferences(self.ref, mod, 0.0) self.assertEqual(len(diff), 0, msg='\nTesting section "' + section + '"\n' + diff.to_string())
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 testFunctionWithIndexedProps(self): tree = et.parse(self.sandbox.path_to_jsbsim_file('engine', 'eng_PegasusXc.xml')) # Define the function starter-max-power-W as a 'post' function root = tree.getroot() startPowFunc_tag = root.find("function/[@name='propulsion/engine[#]/starter-max-power-W']") startPowFunc_tag.attrib['type']='post' tree.write('eng_PegasusXc.xml') # Copy the propeller file. shutil.copy(self.sandbox.path_to_jsbsim_file('engine', 'prop_deHavilland5000.xml'), '.') fdm = CreateFDM(self.sandbox) fdm.set_engine_path('.') fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'Short_S23_1.xml')) fdm.run_ic() pm = fdm.get_property_manager() self.assertTrue(pm.hasNode('propulsion/engine[0]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[1]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[2]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[3]/starter-max-power-W')) while fdm.run(): rpm = [fdm['propulsion/engine[0]/engine-rpm'], fdm['propulsion/engine[1]/engine-rpm'], fdm['propulsion/engine[2]/engine-rpm'], fdm['propulsion/engine[3]/engine-rpm']] for i in range(4): maxPower = max(0.0, 1.0-rpm[i]/400)*498.941*0.10471976*rpm[i] self.assertAlmostEqual(fdm['propulsion/engine[%d]/starter-max-power-W' % (i,)], maxPower)
def test_output(self): tree = et.parse(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('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('JSBout172B.csv', index_col=0) test = pd.read_csv('test.csv', index_col=0) pname = '/fdm/jsbsim/' + property_tag.text ref = orig[pname] mod = test[pname] # Check the data are matching i.e. the time steps are the same between # the two data sets. self.assertTrue(isDataMatching(ref, mod)) # Find all the data that are differing by more than 1E-8 between the # two data sets. delta = pd.concat([np.abs(ref - mod), ref, mod], axis=1) delta.columns = ['delta', 'ref value', 'value'] diff = delta[delta['delta'] > 1E-8] self.longMessage = True self.assertEqual(len(diff), 0, msg='\n' + diff.to_string())
def test_fuel_tanks_content(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml') fdm = CreateFDM(self.sandbox) fdm.load_script(script_path) fdm.run_ic() tree = et.parse(script_path) use_tag = tree.getroot().find('use') aircraft_name = use_tag.attrib['aircraft'] aircraft_path = self.sandbox.path_to_jsbsim_file( 'aircraft', aircraft_name) aircraft_tree = et.parse( os.path.join(aircraft_path, aircraft_name + '.xml')) total_fuel_quantity = 0.0 total_oxidizer_quantity = 0.0 for tank in aircraft_tree.findall('propulsion/tank'): contents = float(tank.find('contents').text) if tank.attrib['type'] == "FUEL": total_fuel_quantity += contents elif tank.attrib['type'] == 'OXIDIZER': total_oxidizer_quantity += contents self.assertAlmostEqual(fdm['propulsion/total-fuel-lbs'], total_fuel_quantity) self.assertAlmostEqual(fdm['propulsion/total-oxidizer-lbs'], total_oxidizer_quantity)
def test_gust_reset(self): fdm = CreateFDM(self.sandbox) fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'c172_cruise_8K.xml')) fdm['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 = pd.read_csv('output.csv', index_col=0) fdm['simulation/randomseed'] = 0.0 fdm.reset_to_initial_conditions(1) ExecuteUntil(fdm, 15.5) current = pd.read_csv('output_0.csv', index_col=0) # Check the data are matching i.e. the time steps are the same between # the two data sets and that the output data are also the same. self.assertTrue(isDataMatching(ref, current)) # Find all the data that are differing by more than 1E-8 between the # two data sets. diff = FindDifferences(ref, current, 1E-8) self.longMessage = True self.assertEqual(len(diff), 0, msg='\n'+diff.to_string())
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 = pd.read_csv('BallOut.csv', index_col=0) 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 = pd.read_csv('BallOut.csv', index_col=0) # Check the data are matching i.e. the time steps are the same between # the two data sets and that the output data are also the same. self.assertTrue(isDataMatching(ref, current)) # Find all the data that are differing by more than 1E-8 between the # two data sets. diff = FindDifferences(ref, current, 1E-8) self.longMessage = True self.assertEqual(len(diff), 0, msg='\n'+diff.to_string())
def Compare(self, section): # Rerun the script with the modified aircraft definition self.sandbox.delete_csv_files() fdm = CreateFDM(self.sandbox) # We need to tell JSBSim that the aircraft definition is located in the # directory build/.../aircraft fdm.set_aircraft_path('aircraft') fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests', 'output.xml')) fdm.load_script(self.script) fdm['simulation/randomseed'] = 0.0 fdm.run_ic() ExecuteUntil(fdm, 50.0) mod = pd.read_csv('output.csv', index_col=0) # Check the data are matching i.e. the time steps are the same between # the two data sets and that the output data are also the same. self.assertTrue(isDataMatching(self.ref, mod)) # Whether the data is read from the aircraft definition file or from an # external file, the results shall be exactly identical. Hence the # precision set to 0.0. diff = FindDifferences(self.ref, mod, 0.0) self.assertEqual(len(diff), 0, msg='\nTesting section "'+section+'"\n'+diff.to_string())
def test_wind_frame(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'ball_chute.xml') fdm = CreateFDM(self.sandbox) fdm.load_script(script_path) fdm.run_ic() self.assertAlmostEqual(fdm['external_reactions/parachute/location-x-in'], 12.0) self.assertAlmostEqual(fdm['external_reactions/parachute/location-y-in'], 0.0) self.assertAlmostEqual(fdm['external_reactions/parachute/location-z-in'], 0.0) self.assertAlmostEqual(fdm['external_reactions/parachute/x'], -1.0) self.assertAlmostEqual(fdm['external_reactions/parachute/y'], 0.0) self.assertAlmostEqual(fdm['external_reactions/parachute/z'], 0.0) while fdm.run(): Tw2b = fdm.get_auxiliary().get_Tw2b() mag = fdm['aero/qbar-psf'] * fdm['fcs/parachute_reef_pos_norm']*20.0 f = Tw2b * np.mat([-1.0, 0.0, 0.0]).T * mag self.assertAlmostEqual(fdm['forces/fbx-external-lbs'], f[0, 0]) self.assertAlmostEqual(fdm['forces/fby-external-lbs'], f[1, 0]) self.assertAlmostEqual(fdm['forces/fbz-external-lbs'], f[2, 0]) m = np.cross(self.getLeverArm(fdm,'parachute'), np.array([f[0,0], f[1,0], f[2, 0]])) self.assertAlmostEqual(fdm['moments/l-external-lbsft'], m[0]) self.assertAlmostEqual(fdm['moments/m-external-lbsft'], m[1]) self.assertAlmostEqual(fdm['moments/n-external-lbsft'], m[2])
def test_fuel_tanks_inertia(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'c1722.xml') # The aircraft c172x does not contain an <inertia_factor> tag so we # need to add one. tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox) tank_tag = tree.getroot().find('propulsion/tank') inertia_factor = et.SubElement(tank_tag, 'inertia_factor') inertia_factor.text = '1.0' tree.write(self.sandbox('aircraft', aircraft_name, aircraft_name+'.xml')) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) fdm.run_ic() contents0 = fdm['propulsion/tank/contents-lbs'] ixx0 = fdm['propulsion/tank/local-ixx-slug_ft2'] iyy0 = fdm['propulsion/tank/local-iyy-slug_ft2'] izz0 = fdm['propulsion/tank/local-izz-slug_ft2'] # Remove half of the tank contents and check that the inertias are # updated accordingly fdm['propulsion/tank/contents-lbs'] = 0.5*contents0 contents = fdm['propulsion/tank/contents-lbs'] ixx = fdm['propulsion/tank/local-ixx-slug_ft2'] iyy = fdm['propulsion/tank/local-iyy-slug_ft2'] izz = fdm['propulsion/tank/local-izz-slug_ft2'] self.assertAlmostEqual(contents, 0.5*contents0, delta=1E-7, msg="The tank content (%f lbs) should be %f lbs" % (contents, 0.5*contents0)) self.assertAlmostEqual(ixx, 0.5*ixx0, delta=1E-7, msg="The tank inertia Ixx (%f slug*ft^2) should be %f slug*ft^2" % (ixx, 0.5*ixx0)) self.assertAlmostEqual(iyy, 0.5*iyy0, delta=1E-7, msg="The tank inertia Iyy (%f slug*ft^2) should be %f slug*ft^2" % (iyy, 0.5*iyy0)) self.assertAlmostEqual(izz, 0.5*izz0, delta=1E-7, msg="The tank inertia Izz (%f slug*ft^2) should be %f slug*ft^2" % (izz, 0.5*izz0)) # Execute the script and check that the fuel inertias have been updated # along with the consumption. ExecuteUntil(fdm, 200.0) contents = fdm['propulsion/tank/contents-lbs'] ixx = fdm['propulsion/tank/local-ixx-slug_ft2'] iyy = fdm['propulsion/tank/local-iyy-slug_ft2'] izz = fdm['propulsion/tank/local-izz-slug_ft2'] contents_ratio = contents / contents0 ixx_ratio = ixx / ixx0 iyy_ratio = iyy / iyy0 izz_ratio = izz / izz0 self.assertAlmostEqual(contents_ratio, ixx_ratio, delta=1E-7, msg="Ixx does not vary as the tank content does\nIxx ratio=%f\nContents ratio=%f" % (ixx_ratio, contents_ratio)) self.assertAlmostEqual(contents_ratio, iyy_ratio, delta=1E-7, msg="Iyy does not vary as the tank content does\nIyy ratio=%f\nContents ratio=%f" % (iyy_ratio, contents_ratio)) self.assertAlmostEqual(contents_ratio, izz_ratio, delta=1E-7, msg="Izz does not vary as the tank content does\nIzz ratio=%f\nContents ratio=%f" % (izz_ratio, contents_ratio))
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_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_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))
def testChannelRate(self): os.environ['JSBSIM_DEBUG'] = str(0) fdm = CreateFDM(self.sandbox) fdm.load_script( self.sandbox.path_to_jsbsim_file('scripts', 'systems-rate-test-0.xml')) fdm.run_ic() while fdm['simulation/sim-time-sec'] < 30: fdm.run() self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int(fdm['simulation/frame'] / 4), fdm['tests/rate-4']) self.assertEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum']) self.assertAlmostEqual( fdm['simulation/dt'] * fdm['tests/rate-4'] * 4, fdm['tests/rate-4-dt-sum']) self.assertEqual(fdm['simulation/dt'], fdm['tests/rate-1-dt']) self.assertEqual(fdm['simulation/dt'] * 4, fdm['tests/rate-4-dt']) 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 while fdm['simulation/sim-time-sec'] < 40: self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int(fdm['simulation/frame'] / 4), fdm['tests/rate-4']) self.assertEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum']) self.assertAlmostEqual( fdm['simulation/dt'] * fdm['tests/rate-4'] * 4, fdm['tests/rate-4-dt-sum']) fdm.run() fdm.reset_to_initial_conditions(1) tf = fdm['tests/rate-1-dt-sum'] xtraFrames = fdm['simulation/frame'] % 4 while fdm['simulation/sim-time-sec'] < 30: fdm.run() self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int((fdm['simulation/frame'] - xtraFrames) / 4), fdm['tests/rate-4']) self.assertAlmostEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum'] - tf) self.assertAlmostEqual( fdm['simulation/dt'] * fdm['tests/rate-4'] * 4, fdm['tests/rate-4-dt-sum'])
def testSteadyFlight(self): script_name = 'c1722.xml' script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name) self.AddAccelerometersToAircraft(script_path) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) # Switch the accel on fdm['fcs/accelerometer/on'] = 1.0 # Use the standard gravity (i.e. GM/r^2) fdm['simulation/gravity-model'] = 0 # Select an orientation such that frame transformations simplify fdm['ic/psi-true-rad'] = 0.0 fdm.run_ic() ExecuteUntil(fdm, 0.1) fdm['simulation/do_simple_trim'] = 1 r = fdm['position/radius-to-vehicle-ft'] pitch = fdm['attitude/theta-rad'] roll = fdm['attitude/phi-rad'] latitude = fdm['position/lat-gc-rad'] g = fdm['accelerations/gravity-ft_sec2'] omega = 0.00007292115 # Earth rotation rate in rad/sec fc = r * math.cos(latitude) * omega * omega # Centrifugal force uvw = np.array(fdm.get_propagate().get_uvw().T)[0] Omega = omega * np.array([ math.cos(pitch - latitude), math.sin(pitch - latitude) * math.sin(roll), math.sin(pitch - latitude) * math.cos(roll) ]) # Compute the acceleration measured by the accelerometer as the sum of # the gravity and the centrifugal and Coriolis forces. fa_yz = (fc * math.cos(latitude - pitch) - g * math.cos(pitch)) fa = np.array([(fc * math.sin(latitude - pitch) + g * math.sin(pitch)), fa_yz * math.sin(roll), fa_yz * math.cos(roll) ]) + np.cross(2.0 * Omega, uvw) # After the trim we are close to the equilibrium but there remains a # small residual that we have to take the bias into account fax = fa[0] + fdm['accelerations/udot-ft_sec2'] fay = fa[1] + fdm['accelerations/vdot-ft_sec2'] faz = fa[2] + fdm['accelerations/wdot-ft_sec2'] # Deltas are relaxed because the tolerances of the trimming algorithm # are quite relaxed themselves. self.assertAlmostEqual(fdm['fcs/accelerometer/X'], fax, delta=1E-6) self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], fay, delta=1E-4) self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], faz, delta=1E-5) del fdm
def test_grain_tanks_content(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml') tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox) id = 0 for tank in tree.getroot().findall('propulsion/tank'): grain_config = tank.find('grain_config') if grain_config and grain_config.attrib['type'] == 'CYLINDRICAL': break ++id capacity = float(tank.find('capacity').text) tank.find('contents').text = str(0.5 * capacity) tree.write( self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml')) radius_tag = tank.find('radius') radius = float(radius_tag.text) if 'unit' in radius_tag.attrib and radius_tag.attrib['unit'] == 'IN': radius /= 12.0 bore_diameter_tag = tank.find('grain_config/bore_diameter') bore_radius = 0.5 * float(bore_diameter_tag.text) if 'unit' in bore_diameter_tag.attrib and bore_diameter_tag.attrib[ 'unit'] == 'IN': bore_radius /= 12.0 fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) fdm.run_ic() tank_name = 'propulsion/tank[%g]' % (id, ) self.assertAlmostEqual(fdm[tank_name + '/contents-lbs'], 0.5 * capacity) fdm['propulsion/tank/contents-lbs'] = capacity mass = capacity / 32.174049 # Converting lbs to slugs ixx = 0.5 * mass * (radius * radius + bore_radius * bore_radius) self.assertAlmostEqual(fdm[tank_name + 'local-ixx-slug_ft2'], ixx) del fdm tank.find('contents').text = '0.0' tree.write( self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml')) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) fdm.run_ic() self.assertAlmostEqual(fdm[tank_name + '/contents-lbs'], 0.0) fdm['propulsion/tank/contents-lbs'] = capacity
def testEnginePowerVC(self): fdm = CreateFDM(self.sandbox) fdm.load_script( self.sandbox.path_to_jsbsim_file('scripts', 'L4102.xml')) fdm.run_ic() pm = fdm.get_property_manager() self.assertTrue(pm.hasNode('propulsion/engine[0]/EnginePowerVC')) self.assertTrue(pm.hasNode('propulsion/engine[1]/EnginePowerVC')) while fdm.run(): self.assertAlmostEqual(fdm['propulsion/engine[0]/EnginePowerVC'], fdm['propulsion/engine[1]/EnginePowerVC'])
def testSteadyFlight(self): script_name = 'c1722.xml' script_path = self.sandbox.path_to_jsbsim_file('scripts', script_name) self.AddAccelerometersToAircraft(script_path) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) # Switch the accel on fdm['fcs/accelerometer/on'] = 1.0 # Use the standard gravity (i.e. GM/r^2) fdm['simulation/gravity-model'] = 0 # Select an orientation such that frame transformations simplify fdm['ic/psi-true-rad'] = 0.0 fdm.run_ic() ExecuteUntil(fdm, 0.1) fdm['simulation/do_simple_trim'] = 1 r = fdm['position/radius-to-vehicle-ft'] pitch = fdm['attitude/theta-rad'] roll = fdm['attitude/phi-rad'] latitude = fdm['position/lat-gc-rad'] g = fdm['accelerations/gravity-ft_sec2'] omega = 0.00007292115 # Earth rotation rate in rad/sec fc = r * math.cos(latitude) * omega * omega # Centrifugal force uvw = np.array(fdm.get_propagate().get_uvw().T)[0] Omega = omega * np.array([math.cos(pitch - latitude), math.sin(pitch - latitude) * math.sin(roll), math.sin(pitch - latitude) * math.cos(roll)]) # Compute the acceleration measured by the accelerometer as the sum of # the gravity and the centrifugal and Coriolis forces. fa_yz = (fc * math.cos(latitude - pitch) - g * math.cos(pitch)) fa = np.array([(fc * math.sin(latitude - pitch) + g * math.sin(pitch)), fa_yz * math.sin(roll), fa_yz * math.cos(roll)]) + np.cross(2.0*Omega, uvw) # After the trim we are close to the equilibrium but there remains a # small residual that we have to take the bias into account fax = fa[0] + fdm['accelerations/udot-ft_sec2'] fay = fa[1] + fdm['accelerations/vdot-ft_sec2'] faz = fa[2] + fdm['accelerations/wdot-ft_sec2'] # Deltas are relaxed because the tolerances of the trimming algorithm # are quite relaxed themselves. self.assertAlmostEqual(fdm['fcs/accelerometer/X'], fax, delta=1E-6) self.assertAlmostEqual(fdm['fcs/accelerometer/Y'], fay, delta=1E-4) self.assertAlmostEqual(fdm['fcs/accelerometer/Z'], faz, delta=1E-5) del fdm
def testEnginePowerVC(self): fdm = CreateFDM(self.sandbox) fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'L4102.xml')) fdm.run_ic() pm = fdm.get_property_manager() self.assertTrue(pm.hasNode('propulsion/engine[0]/EnginePowerVC')) self.assertTrue(pm.hasNode('propulsion/engine[1]/EnginePowerVC')) while fdm.run(): self.assertAlmostEqual(fdm['propulsion/engine[0]/EnginePowerVC'], fdm['propulsion/engine[1]/EnginePowerVC'])
def initFDM(self): fdm = CreateFDM(self.sandbox) script_path = self.sandbox.path_to_jsbsim_file('scripts', 'cannonball.xml') fdm.load_script(script_path) fdm['simulation/integrator/rate/rotational'] = 5 fdm['simulation/integrator/rate/translational'] = 5 fdm['simulation/integrator/position/rotational'] = 5 fdm['simulation/integrator/position/translational'] = 5 fdm.run_ic() fdm.set_dt(0.05) return fdm
def testEnginePowerVC(self): # Check that the same results are obtained whether the engine power # velocity correction is given in a <table> or <function> fdm = CreateFDM(self.sandbox) fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'L4102.xml')) fdm.run_ic() while fdm.run(): pass del fdm ref = pd.read_csv('L410.csv', index_col=0) tree = et.parse(self.sandbox.path_to_jsbsim_file('engine', 'engtm601.xml')) # Modify the engine definition to use a <function> rather than a # <table> component. root = tree.getroot() engPowVC_tag = root.find("table/[@name='EnginePowerVC']") root.remove(engPowVC_tag) del engPowVC_tag.attrib['name'] func_engPowVC = et.SubElement(root, 'function') func_engPowVC.attrib['name'] = 'EnginePowerVC' func_engPowVC.append(engPowVC_tag) tree.write('engtm601.xml') # Copy the propeller file. shutil.copy(self.sandbox.path_to_jsbsim_file('engine', 'vrtule2.xml'), '.') self.sandbox.delete_csv_files() fdm = CreateFDM(self.sandbox) fdm.set_engine_path('.') fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'L4102.xml')) fdm.run_ic() while fdm.run(): pass current = pd.read_csv('L410.csv', index_col=0) # Check the data are matching i.e. the time steps are the same between # the two data sets and that the output data are also the same. self.assertTrue(isDataMatching(ref, current)) # Find all the data that are differing by more than 1E-5 between the # two data sets. diff = FindDifferences(ref, current, 0.0) self.longMessage = True self.assertEqual(len(diff), 0, msg='\n'+diff.to_string())
def testChannelRate(self): os.environ['JSBSIM_DEBUG'] = str(0) fdm = CreateFDM(self.sandbox) fdm.load_script( self.sandbox.path_to_jsbsim_file('scripts', 'systems-rate-test-0.xml')) fdm.run_ic() while fdm['simulation/sim-time-sec'] < 30: fdm.run() self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int(fdm['simulation/frame'] / 4), fdm['tests/rate-4']) self.assertEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum']) self.assertAlmostEqual( fdm['simulation/dt'] * fdm['tests/rate-4'] * 4, fdm['tests/rate-4-dt-sum']) self.assertEqual(fdm['simulation/dt'], fdm['tests/rate-1-dt']) self.assertEqual(fdm['simulation/dt'] * 4, fdm['tests/rate-4-dt']) # Trigger the trimming and check that it fails (i.e. it raises an # exception TrimFailureError) with self.assertRaises(TrimFailureError): fdm['simulation/do_simple_trim'] = 1 while fdm['simulation/sim-time-sec'] < 40: self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int(fdm['simulation/frame'] / 4), fdm['tests/rate-4']) self.assertEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum']) self.assertAlmostEqual( fdm['simulation/dt'] * fdm['tests/rate-4'] * 4, fdm['tests/rate-4-dt-sum']) fdm.run() fdm.reset_to_initial_conditions(1) tf = fdm['tests/rate-1-dt-sum'] xtraFrames = fdm['simulation/frame'] % 4 while fdm['simulation/sim-time-sec'] < 30: fdm.run() self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int((fdm['simulation/frame'] - xtraFrames) / 4), fdm['tests/rate-4']) self.assertAlmostEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum'] - tf) self.assertAlmostEqual( fdm['simulation/dt'] * fdm['tests/rate-4'] * 4, fdm['tests/rate-4-dt-sum'])
def test_grain_tanks_content(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'J2460.xml') tree, aircraft_name, b = CopyAircraftDef(script_path, self.sandbox) id = 0 for tank in tree.getroot().findall('propulsion/tank'): grain_config = tank.find('grain_config') if grain_config and grain_config.attrib['type'] == 'CYLINDRICAL': break ++id capacity = float(tank.find('capacity').text) tank.find('contents').text = str(0.5*capacity) tree.write(self.sandbox('aircraft', aircraft_name, aircraft_name+'.xml')) radius_tag = tank.find('radius') radius = float(radius_tag.text) if 'unit' in radius_tag.attrib and radius_tag.attrib['unit'] == 'IN': radius /= 12.0 bore_diameter_tag = tank.find('grain_config/bore_diameter') bore_radius = 0.5*float(bore_diameter_tag.text) if 'unit' in bore_diameter_tag.attrib and bore_diameter_tag.attrib['unit'] == 'IN': bore_radius /= 12.0 fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) fdm.run_ic() tank_name = 'propulsion/tank[%g]' % (id,) self.assertAlmostEqual(fdm[tank_name+'/contents-lbs'], 0.5*capacity) fdm['propulsion/tank/contents-lbs'] = capacity mass = capacity / 32.174049 # Converting lbs to slugs ixx = 0.5 * mass * (radius * radius + bore_radius*bore_radius) self.assertAlmostEqual(fdm[tank_name+'local-ixx-slug_ft2'], ixx) del fdm tank.find('contents').text = '0.0' tree.write(self.sandbox('aircraft', aircraft_name, aircraft_name+'.xml')) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) fdm.run_ic() self.assertAlmostEqual(fdm[tank_name+'/contents-lbs'], 0.0) fdm['propulsion/tank/contents-lbs'] = capacity
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)
def test_script_input(self): tree = et.parse(self.script_path) input_tag = et.SubElement(tree.getroot(), 'input') input_tag.attrib['port'] = '1138' tree.write('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)
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_moment(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'ball_chute.xml') tree, aircraft_name, aircraft_path = CopyAircraftDef( script_path, self.sandbox) extReact_element = tree.getroot().find('external_reactions') moment_element = et.SubElement(extReact_element, 'moment') moment_element.attrib['name'] = 'parachute' moment_element.attrib['frame'] = 'WIND' direction_element = et.SubElement(moment_element, 'direction') x_element = et.SubElement(direction_element, 'x') x_element.text = '0.2' y_element = et.SubElement(direction_element, 'y') y_element.text = '0.0' z_element = et.SubElement(direction_element, 'z') z_element.text = '-1.5' tree.write( self.sandbox('aircraft', aircraft_name, aircraft_name + '.xml')) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) fdm.run_ic() mDir = np.array([0.2, 0.0, -1.5]) mDir /= np.linalg.norm(mDir) self.assertAlmostEqual(fdm['external_reactions/parachute/l'], mDir[0]) self.assertAlmostEqual(fdm['external_reactions/parachute/m'], mDir[1]) self.assertAlmostEqual(fdm['external_reactions/parachute/n'], mDir[2]) fdm['external_reactions/parachute/magnitude-lbsft'] = -3.5 while fdm.run(): Tw2b = fdm.get_auxiliary().get_Tw2b() mag = fdm['aero/qbar-psf'] * fdm[ 'fcs/parachute_reef_pos_norm'] * 20.0 f = Tw2b * np.mat([-1.0, 0.0, 0.0]).T * mag self.assertAlmostEqual(fdm['forces/fbx-external-lbs'], f[0, 0]) self.assertAlmostEqual(fdm['forces/fby-external-lbs'], f[1, 0]) self.assertAlmostEqual(fdm['forces/fbz-external-lbs'], f[2, 0]) m = -3.5 * Tw2b * np.mat(mDir).T fm = np.cross(self.getLeverArm(fdm, 'parachute'), np.array([f[0, 0], f[1, 0], f[2, 0]])) self.assertAlmostEqual(fdm['moments/l-external-lbsft'], m[0, 0] + fm[0]) self.assertAlmostEqual(fdm['moments/m-external-lbsft'], m[1, 0] + fm[1]) self.assertAlmostEqual(fdm['moments/n-external-lbsft'], m[2, 0] + fm[2])
def testChannelRate(self): os.environ['JSBSIM_DEBUG'] = str(0) fdm = CreateFDM(self.sandbox) fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'systems-rate-test-0.xml')) fdm.run_ic() while fdm['simulation/sim-time-sec'] < 30: fdm.run() self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int(fdm['simulation/frame']/4), fdm['tests/rate-4']) self.assertEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum']) self.assertAlmostEqual(fdm['simulation/dt']*fdm['tests/rate-4']*4, fdm['tests/rate-4-dt-sum']) self.assertEqual(fdm['simulation/dt'], fdm['tests/rate-1-dt']) self.assertEqual(fdm['simulation/dt']*4, fdm['tests/rate-4-dt']) 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 while fdm['simulation/sim-time-sec'] < 40: self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int(fdm['simulation/frame']/4), fdm['tests/rate-4']) self.assertEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum']) self.assertAlmostEqual(fdm['simulation/dt']*fdm['tests/rate-4']*4, fdm['tests/rate-4-dt-sum']) fdm.run() fdm.reset_to_initial_conditions(1) tf = fdm['tests/rate-1-dt-sum'] xtraFrames = fdm['simulation/frame'] % 4 while fdm['simulation/sim-time-sec'] < 30: fdm.run() self.assertEqual(fdm['simulation/frame'], fdm['tests/rate-1']) self.assertEqual(int((fdm['simulation/frame']-xtraFrames)/4), fdm['tests/rate-4']) self.assertAlmostEqual(fdm['simulation/sim-time-sec'], fdm['tests/rate-1-dt-sum']-tf) self.assertAlmostEqual(fdm['simulation/dt']*fdm['tests/rate-4']*4, fdm['tests/rate-4-dt-sum'])
def testTableWithIndexedVars(self): tree = et.parse( self.sandbox.path_to_jsbsim_file('engine', 'eng_PegasusXc.xml')) # Define the function starter-max-power-W as a 'post' function root = tree.getroot() startPowFunc_tag = root.find( "function/[@name='propulsion/engine[#]/starter-max-power-W']") startPowFunc_tag.attrib['type'] = 'post' max_tag = startPowFunc_tag.find('product/max') diff_tag = max_tag.find('difference') max_tag.remove(diff_tag) table_tag = et.SubElement(max_tag, 'table') table_tag.attrib['name'] = 'propulsion/engine[#]/starter-tabular-data' indepVar_tag = et.SubElement(table_tag, 'independentVar') indepVar_tag.attrib['lookup'] = 'row' indepVar_tag.text = 'propulsion/engine[#]/engine-rpm' tData_tag = et.SubElement(table_tag, 'tableData') tData_tag.text = '0.0 1.0\n400.0 0.0' tree.write('eng_PegasusXc.xml') # Copy the propeller file. shutil.copy( self.sandbox.path_to_jsbsim_file('engine', 'prop_deHavilland5000.xml'), '.') fdm = CreateFDM(self.sandbox) fdm.set_engine_path('.') fdm.load_script( self.sandbox.path_to_jsbsim_file('scripts', 'Short_S23_1.xml')) fdm.run_ic() pm = fdm.get_property_manager() self.assertTrue(pm.hasNode('propulsion/engine[0]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[1]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[2]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[3]/starter-max-power-W')) while fdm.run(): rpm = [ fdm['propulsion/engine[0]/engine-rpm'], fdm['propulsion/engine[1]/engine-rpm'], fdm['propulsion/engine[2]/engine-rpm'], fdm['propulsion/engine[3]/engine-rpm'] ] for i in xrange(4): tabularData = max(0.0, 1.0 - rpm[i] / 400) maxPower = tabularData * 498.941 * 0.10471976 * rpm[i] self.assertAlmostEqual( fdm['propulsion/engine[%d]/starter-max-power-W' % (i, )], maxPower) self.assertAlmostEqual( fdm['propulsion/engine[%d]/starter-tabular-data' % (i, )], tabularData)
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['simulation/sim-time-sec'], 0.0) ExecuteUntil(fdm, 5.0) fdm.reset_to_initial_conditions(1) self.assertEqual(fdm['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 steerType(self, hasSteerPosDeg, hasSteeringAngle, hasCastered): self.tree.write(self.sandbox('aircraft', self.aircraft_name, self.aircraft_name+'.xml')) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(self.script_path) fdm.run_ic() pm = fdm.get_property_manager() self.assertTrue(pm.hasNode('fcs/steer-pos-deg') == hasSteerPosDeg) self.assertTrue(pm.hasNode('gear/unit/steering-angle-deg') == hasSteeringAngle) self.assertTrue(pm.hasNode('gear/unit/castered') == hasCastered) return fdm
def 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 test_output_from_file(self): tree = et.parse(self.script_path) output_tag = et.SubElement(tree.getroot(), 'output') # Relative path from the aircraft directory to the output directive # file output_tag.attrib['file'] = os.path.join('..', '..', 'tests', 'output.xml') tree.write('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 LoadScript(self, tree, script_path, prop_output_to_CSV=[]): # Make a local copy of files referenced by the script. for element in list(tree.getroot()): if 'file' in element.keys(): name = append_xml(element.attrib['file']) name_with_path = os.path.join(os.path.dirname(script_path), name) if os.path.exists(name_with_path): shutil.copy(name_with_path, name) # Generate a CSV file to check that it is correctly initialized # with the initial values output_tag = et.SubElement(tree.getroot(), '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 f = os.path.split(script_path)[-1] # Script name tree.write(f) # Initialize the script fdm = CreateFDM(self.sandbox) self.assertTrue(fdm.load_script(f), msg="Failed to load script %s" % (f,)) fdm.run_ic() return (f, fdm)
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))
def test_moment(self): script_path = self.sandbox.path_to_jsbsim_file('scripts', 'ball_chute.xml') tree, aircraft_name, aircraft_path = CopyAircraftDef(script_path, self.sandbox) extReact_element = tree.getroot().find('external_reactions') moment_element = et.SubElement(extReact_element, 'moment') moment_element.attrib['name'] = 'parachute' moment_element.attrib['frame'] = 'WIND' direction_element = et.SubElement(moment_element, 'direction') x_element = et.SubElement(direction_element, 'x') x_element.text = '0.2' y_element = et.SubElement(direction_element, 'y') y_element.text = '0.0' z_element = et.SubElement(direction_element, 'z') z_element.text = '-1.5' tree.write(self.sandbox('aircraft', aircraft_name, aircraft_name+'.xml')) fdm = CreateFDM(self.sandbox) fdm.set_aircraft_path('aircraft') fdm.load_script(script_path) fdm.run_ic() mDir = np.array([0.2, 0.0, -1.5]) mDir /= np.linalg.norm(mDir) self.assertAlmostEqual(fdm['external_reactions/parachute/l'], mDir[0]) self.assertAlmostEqual(fdm['external_reactions/parachute/m'], mDir[1]) self.assertAlmostEqual(fdm['external_reactions/parachute/n'], mDir[2]) fdm['external_reactions/parachute/magnitude-lbsft'] = -3.5 while fdm.run(): Tw2b = fdm.get_auxiliary().get_Tw2b() mag = fdm['aero/qbar-psf'] * fdm['fcs/parachute_reef_pos_norm']*20.0 f = Tw2b * np.mat([-1.0, 0.0, 0.0]).T * mag self.assertAlmostEqual(fdm['forces/fbx-external-lbs'], f[0, 0]) self.assertAlmostEqual(fdm['forces/fby-external-lbs'], f[1, 0]) self.assertAlmostEqual(fdm['forces/fbz-external-lbs'], f[2, 0]) m = -3.5 * Tw2b * np.mat(mDir).T fm = np.cross(self.getLeverArm(fdm,'parachute'), np.array([f[0,0], f[1,0], f[2, 0]])) self.assertAlmostEqual(fdm['moments/l-external-lbsft'], m[0, 0] + fm[0]) self.assertAlmostEqual(fdm['moments/m-external-lbsft'], m[1, 0] + fm[1]) self.assertAlmostEqual(fdm['moments/n-external-lbsft'], m[2, 0] + fm[2])
def testDragFunctions(self): fdm = CreateFDM(self.sandbox) self.script_path = self.sandbox.path_to_jsbsim_file('scripts', 'x153.xml') fdm.load_script(self.script_path) fdm.set_output_directive(self.sandbox.path_to_jsbsim_file('tests', 'output.xml')) fdm.run_ic() while fdm.run(): pass results = pd.read_csv('output.csv', index_col=0) Fdrag = results['F_{Drag} (lbs)'] CDmin = results['aero/coefficient/CDmin'] CDi = results['aero/coefficient/CDi'] self.assertAlmostEqual(abs(Fdrag/(CDmin+CDi)).max(), 1.0, delta=1E-5)
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))
def testTableWithIndexedVars(self): tree = et.parse(self.sandbox.path_to_jsbsim_file('engine', 'eng_PegasusXc.xml')) # Define the function starter-max-power-W as a 'post' function root = tree.getroot() startPowFunc_tag = root.find("function/[@name='propulsion/engine[#]/starter-max-power-W']") startPowFunc_tag.attrib['type']='post' max_tag = startPowFunc_tag.find('product/max') diff_tag = max_tag.find('difference') max_tag.remove(diff_tag) table_tag = et.SubElement(max_tag,'table') table_tag.attrib['name']='propulsion/engine[#]/starter-tabular-data' indepVar_tag = et.SubElement(table_tag, 'independentVar') indepVar_tag.attrib['lookup']='row' indepVar_tag.text = 'propulsion/engine[#]/engine-rpm' tData_tag = et.SubElement(table_tag, 'tableData') tData_tag.text ='0.0 1.0\n400.0 0.0' tree.write('eng_PegasusXc.xml') # Copy the propeller file. shutil.copy(self.sandbox.path_to_jsbsim_file('engine', 'prop_deHavilland5000.xml'), '.') fdm = CreateFDM(self.sandbox) fdm.set_engine_path('.') fdm.load_script(self.sandbox.path_to_jsbsim_file('scripts', 'Short_S23_1.xml')) fdm.run_ic() pm = fdm.get_property_manager() self.assertTrue(pm.hasNode('propulsion/engine[0]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[1]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[2]/starter-max-power-W')) self.assertTrue(pm.hasNode('propulsion/engine[3]/starter-max-power-W')) while fdm.run(): rpm = [fdm['propulsion/engine[0]/engine-rpm'], fdm['propulsion/engine[1]/engine-rpm'], fdm['propulsion/engine[2]/engine-rpm'], fdm['propulsion/engine[3]/engine-rpm']] for i in range(4): tabularData = max(0.0, 1.0-rpm[i]/400) maxPower = tabularData*498.941*0.10471976*rpm[i] self.assertAlmostEqual(fdm['propulsion/engine[%d]/starter-max-power-W' % (i,)], maxPower) self.assertAlmostEqual(fdm['propulsion/engine[%d]/starter-tabular-data' % (i,)], tabularData)