I have now managed to successfully map my engine simulator for the fuel injection timings across all loads and engine speeds. I have set up a two dimensional array, of speed and throttle position, and inside each element is the time in microseconds (us) that the fuel injector should be open for. I’ve also added closed loop lambda feedback.
To populate the map, I set the engine throttle position to 100% and manually adjusted the fuel pulse width until the engine speed was at its highest point (this means that it’s producing the highest torque at AFR around 12.8 – remember this is only a rough simulation). I then stored this value in the map and moved onto the next one by increasing the engine loading and repeated the same again. Once I had done this until the engine stopped producing any torque, I then set the load to 0 and reduced the throttle position down. This meant that the engine speed dropped, and at speed intervals of 500 RPM I adjusted the fuel pulse width and stored the value in the map.
When this was complete I then interpolated the map through all of the throttle positions and speeds. This is a pretty crude way of doing this and on the real engine I will properly map each point, but I know that my simulation is only simple and is linear across the throttle positions so it works fine. Once the mapping process is finished, the map can be used to set the fuel injector pulse width. The code looks in the map for the current engine speed and throttle position and finds the fuel injector open time, and loads value this into a timer. When the timer elapses the fuel injector is then switched off again. I tested this with the engine simulator and it is fairly effective, and managed to control the AFR between about 10 and 20.
I then preceded to add lambda feedback from the engine simulator to the Arduino engine control system. The map value was used as a basis for the fuel injector pulse width but with an adjustment made according to the lambda reading. If the mixture is too lean, the fuel injector is opened for longer and if it is too rich then it is closed sooner. This type of control is called closed loop feedback, and is the mode in which modern vehicles operate once they are warmed up.
This fine tuning control is provided by Proportional Integral Derivative (PID) control. This is an algorithm which can adjust an output in order to maintain some input at a set level. In this case the output is the fuel injector pulse width, the input is the lambda sensor value, and the set point is around 12.8 AFR. The PID algorithm requires tuning before it will work correctly. For this system, I found that it helped to increase the sample time between PID calculations which allowed me to see what was going on. I then set all of the gain values to 0 and started BT increasing the proportional part slightly. Because the lambda sensor reading coming into my Arduino is not a very steady signal (it is smoothed PWM from the engine simulator microcontroller) I found that I had to use a very small value for the proportional gain otherwise the system would quickly begin to oscillate. A proportional gain of 0.01 showed that there were some adjustments being made, just that they were very slow. I then began to increase the integral gain. This saw big improvements with a gain of 1, and very accurate but slow response with a gain of 10. I finally increased the proportional gain to 0.05 which made for a pretty steady accurate and fast system. I left the derivative gain at 0 since I’m not too fussed about getting things perfect with then engine simulator, as I want to move on to the real engine soon.
This same PID set up also worked well on its own without the engine map to set and restrict initial fuel timings. The problem with this is that the fuel timings are not restricted to predefined safe values and so the PID algorithm could end up outputting any amount of fuel and either causing the engine to run very inefficiently, too lean or to stall.