So over the last few weeks, I have made great strides in scripting my engine. What started with "getting a bit of throttle lag", has become a bit more than that and I wanted to showcase it to some fresher - and perhaps more knowledgeable eyes. I'd like to stress that even though this is my own work, I have had valuable discussions that lead up to this, and couldn't have done this without some valuable discussions. Those in question know who they are. The title did warn you, so let's start with a bit of an introduction. The objective is to get a more prototypical, physics-based behaviour of the actual cylinder bit on a locomotive. Several sources do a really good job of indicating what goes on inside the cylinder as the wheels go round. Personally, I recommend Henderson (1904): Locomotive Operation; a technical and practical analysis. I have some text in italics, those are things I am not quite sure of.
Values are computed based on the current (virtual) control settings and the angular position of the wheels, as well as several other parameters. One thing you will quickly run in to, is the limitation that the framerate imposes on any serious work at higher speeds. To counteract this, in my script, some sensitive physics calculations are done in what I like to call the fast loop. It subdivides the frame into multiple subframes. Sub-iteration points of wheel-rotation are easily obtained by linearly spacing them out. I have noticed no ill effects of having a fast loop containing around 20 - 50 points. The plot below has a lot of data points, but I don't get nearly that FPS .
Fig 1. Blue: Steam Chest Pressure, Pink: Cylinder Pressure (left, front end)
We start of by computing both the cylinder pressures and steam chest pressures. Cylinder pressures are based on an assumed indicator diagram, valve events, admission losses (based on RPM) and steam chest pressure. The steam chest pressure itself is the consequence of keeping track of the mass flow rate out of the steam chest (due to the cylinders filling up) and the regulator setting and pressure differential over the regulator. Notice there is no superheater* to complicate matters!
The steam chest behaves much as you would a reservoir of steam to expect. When standing still and opening the regulator, it quickly fills up. The rate at which it drains is very much dependent on RPM (i.e. speed) and cut-off. There's also a very nice bounce in the needle, but my engine technically has no steam chest gauge . Because the locomotive is not equipped with any drifting valves, the steam chest will drop below atmospheric when having the regulator shut and the motion in full gear.
Having all cylinder pressures, one may use the piston equations to find the torque on exerted on the cranks. In my case, I have also kept track of the accelerations of the pistons and connecting rods, using Newton's second law and substracting these from the piston force. The result is shown:
Fig 2. Torque exerted on cranks. Blue: Left-hand, Pink: Right-hand.
Note that the torque does go negative, which I would attribute to the combined effect of mass inertia and pre-admission. When summated, the torque does stay positive for most cut-offs. At lower cut-offs, I have seen a tendency for the torque to have significant negative areas. Would this be the 'no-true-midgear' that you hear people speak of when discussing Stephensons' motion? Finally, from torque we can go to tractive effort, which is what we are interested in. This is also a good time to check for the adhesion limit. In my script, this is done in the fast loop, integrating rotational acceleration of the wheels.
Let's now exit the fast loop before we ask to much of lua. I've made a couple of observations about how tractive effort is handled in the game engine, depending on throttle setting. I believe it was Chris Barnes who came up with the formula:
TE = MaxForce * TE_vs_Speed.csv * TE_vs_Cutoff * (P_boiler/MaxP_Boiler) * Regulator
My notes:
- Both the TractiveEffortvsSpeed and TractiveEffortvsCutoff are straightforward multipliers. Speed is in MPH; Cutoff seems to be normalised (i.e. don't use a fractional number as the max cut-off!).
- The MaxForce parameter is in kilopounds-force.
- The regulator is a straightforward multiplier.
- There is something with the boiler pressure, but I do not know exactly what. TS's steam chest pressure makes zero sense to me.
For now assume that we've got the boiler pressure at an optimum at all times, until we figure out how that is handled in game. We can set both the CSV's to be a flat 1 for all speed and cutoff, and can then modulate the regulator to set the tractive effort. To account for a negative torque, use a parameter that sets the reverser in the opposite direction.
Fig 3. Tractive effort. Blue: Value reported by using Call("GetTractiveEffort"). Green: As calculated in the fast loop.
The result looks something like the above. There are some differences, but let's agree that the results are correct "within an order of magnitude". A very fun aspect of this script is that, when starting, there exist arrangements of the valve gear for which the locomotive will barely start when not in full gear. Some parameters need sorting out, but I feel that the performance of the locomotive is convincingly prototypical.
Now for a couple of downsides or points I'll need to think about.
- The tractive effort is in principle completely unrelated to the in-game cut-off. The reverser control however is still related to the exhaust effect, and thus to steam production rates. If there is a way to break or minimise this coupling, the reverser could freely be used to modulate steam consumption, adjusting steam production via the blower only.
- The biggest breakdown is in water consumption. I have done preliminary investigations, that show that under the above scripting, water consumption is severely underestimated. Furthermore, the percentage of underestimation varies depending on speed, cut-off, and the like. The order of magnitude is in 25-50%. However, given that water consumption is basically equal to the steam mass through the cylinders - plus a bit for the air pump and the like, once again we could use the reverser to account for this.
So. That's it for now, Maybe I'll think of something to add or append to this post, but for now maybe it would be nice to have some input from others. If there's need for plots, I can do a couple of test runs and log some data!
Thanks,
Björn