Replies: 7 comments
-
Yep there is, take a look at this discussion - #530 You can do the same thing, i.e. lookup the relevant property node once and then call it's Lines 129 to 211 in ae4652a |
Beta Was this translation helpful? Give feedback.
-
I would like to express my sincere gratitude for your prompt response to my inquiry. I am eager to implement the method you suggested, but I encountered an issue when attempting to create an FGPropertyManager and use the get_node function within the class. It seems that the attribute is not available. I initially installed jsbsim using the command "pip install jsbsim==1.1.13." However, it appears that the provided pyx.in file in this release version may be outdated. To proceed with the method you outlined, it seems I will need to download the source code and build it. Could you kindly guide me on how to proceed with this process? Thank you once again for your assistance, and I look forward to your guidance on this matter. |
Beta Was this translation helpful? Give feedback.
-
Yep, the latest version is 1.1.13 which was released early Dec 2022, and the updated code for We're planning on doing another release quite soon, so you could wait for that if you're not in an immediate rush. Otherwise as you say build it yourself. |
Beta Was this translation helpful? Give feedback.
-
@dw95kim version JSBSim 1.1.14 has just been released. |
Beta Was this translation helpful? Give feedback.
-
@dw95kim okay so I jumped the gun a bit implying that the required Python However version 1.2.0 has now been released and this branch does include the required Python methods. I just tested it out. To allow you to use the same syntax as before in terms of getting property data from the FDM I created this simple class which wraps the class FDMProperties:
def __init__(self, fdm):
self.property_manager = fdm.get_property_manager()
self.properties = { }
def __getitem__(self, property):
try:
property_node = self.properties[property]
return property_node.get_double_value()
except KeyError:
property_node = self.property_manager.get_node(property)
if property_node is not None:
self.properties[property] = property_node
return property_node.get_double_value()
else:
raise KeyError(f'Property {property} not found.') So quick test. fdm = jsbsim.FGFDMExec('..\\') # Path for the location of the folders "aircraft", "engines" and "systems"
fdm.load_model('737') # Load the aircraft 737
props = FDMProperties(fdm)
alpha = props['aero/alpha-deg']
alpha = props['aero/alpha-deg']
alpha = props['aero/alpha-xxx'] When I get a chance I'll do some benchmarking to see how much of a difference this makes. @dw95kim it will be useful to get a performance update from your setup as well. Also going to take a look to see if it possibly makes sense to implement the same caching logic in |
Beta Was this translation helpful? Give feedback.
-
@dw95kim so I wrote up a quick benchmark test to see what sort of performance improvement you can expect to see. With 3 test cases. In all test cases the code loads the 737 model and trims it for level flight at 30,000ft and then runs the simulation for 5,000 seconds. In test case 1, no properties are queried for during the execution run, setting a baseline in terms of performance. In test case 2 and 3 a set of 13 properties, is queried for each simulation timestep. Given the default simulation timestep of 1/120 we're talking about a total of 600,000 timesteps. Test case 2 makes use of the regular I'm guessing 13 properties is in the ball park in terms of the typical size of the state vector you might use during RL? import jsbsim
import timeit
class FDMProperties:
def __init__(self, fdm):
self.property_manager = fdm.get_property_manager()
self.properties = { }
def __getitem__(self, property):
try:
property_node = self.properties[property]
return property_node.get_double_value()
except KeyError:
property_node = self.property_manager.get_node(property)
if property_node is not None:
self.properties[property] = property_node
return property_node.get_double_value()
else:
raise KeyError(f'Property {property} not found.')
def test1():
fdm = jsbsim.FGFDMExec('..\\')
fdm.load_model('737')
# Set engines running
fdm['propulsion/engine[0]/set-running'] = 1
fdm['propulsion/engine[1]/set-running'] = 1
fdm['ic/h-sl-ft'] = 30000
fdm['ic/vc-kts'] = 300
fdm['ic/gamma-deg'] = 0
fdm.run_ic()
fdm['simulation/do_simple_trim'] = 1
while fdm.get_sim_time() < 5000:
fdm.run()
def test2():
fdm = jsbsim.FGFDMExec('..\\')
fdm.load_model('737')
# Set engines running
fdm['propulsion/engine[0]/set-running'] = 1
fdm['propulsion/engine[1]/set-running'] = 1
fdm['ic/h-sl-ft'] = 30000
fdm['ic/vc-kts'] = 300
fdm['ic/gamma-deg'] = 0
fdm.run_ic()
fdm['simulation/do_simple_trim'] = 1
while fdm.get_sim_time() < 5000:
fdm.run()
alpha = fdm['aero/alpha-deg']
theta = fdm['attitude/theta-deg']
gamma = fdm['flight-path/gamma-deg']
altitude = fdm['position/h-sl-ft']
kia = fdm['velocities/vc-kts']
Nz = fdm['accelerations/Nz']
u = fdm['velocities/u-fps']
v = fdm['velocities/v-fps']
w = fdm['velocities/w-fps']
p = fdm['velocities/p-rad_sec']
q = fdm['velocities/q-rad_sec']
r = fdm['velocities/r-rad_sec']
def test3():
fdm = jsbsim.FGFDMExec('..\\')
fdm.load_model('737')
# Set engines running
fdm['propulsion/engine[0]/set-running'] = 1
fdm['propulsion/engine[1]/set-running'] = 1
fdm['ic/h-sl-ft'] = 30000
fdm['ic/vc-kts'] = 300
fdm['ic/gamma-deg'] = 0
fdm.run_ic()
fdm['simulation/do_simple_trim'] = 1
props = FDMProperties(fdm)
while fdm.get_sim_time() < 5000:
fdm.run()
alpha = props['aero/alpha-deg']
theta = props['attitude/theta-deg']
gamma = props['flight-path/gamma-deg']
altitude = props['position/h-sl-ft']
kia = props['velocities/vc-kts']
Nz = props['accelerations/Nz']
u = props['velocities/u-fps']
v = props['velocities/v-fps']
w = props['velocities/w-fps']
p = props['velocities/p-rad_sec']
q = props['velocities/q-rad_sec']
r = props['velocities/r-rad_sec']
test1time = timeit.Timer(test1).timeit(number=3)
test2time = timeit.Timer(test2).timeit(number=3)
test3time = timeit.Timer(test3).timeit(number=3)
print(test1time, test2time, test3time) So each test case is run 3 times, with the following cumulative run times for each test case on my PC (Intel Core i5-9600KF @ 3.7GHz). 26.8 83.1 29.2 So test case 1 which does no property queries is 3.1 times faster compared to using to the standard property query mechanism, and test case 3 which uses the cached @agodemar I took a quick look at the Matlab S-Function implementation to refresh my memory to see whether this sort of speed-up could be applied there as well. But it already makes use of Lastly in terms of absolute performance @dw95kim has asked:
Let's take test case 1, running my PC, it's executed |
Beta Was this translation helpful? Give feedback.
-
With this commit - 48e2558 the property node caching is now done within |
Beta Was this translation helpful? Give feedback.
-
I'm working on an RL project to develop a multi-agent aerial combat algorithm using the JSBSim physics engine. Can JSBSim accelerate process of taking stick values and returning 6DOF?
Currently, with a single agent, I'm able to achieve a simulation rate of around 300Hz. However, when the number of agents increases, I've observed a linear decrease in the simulation rate. Profiling with line_profiler showed that a significant amount of time is spent in the get_property_value function in Python. I suspect this part to be a bottleneck, and I hope there's a way to improve its speed.
To summarize:
Beta Was this translation helpful? Give feedback.
All reactions