Thanks for confirming.
In that case the main issue is that the PID output is being fed directly back into the process value. In your second example you are doing:
I_PV := controller.Next(I_PV, I_setpoint);
This effectively makes the controller control itself, which is why the value jumps between +INF and -INF.
A PID controller should not replace the process value. The output of the PID should represent the control signal to the system, not the measured value itself.
So the usual structure looks more like this:
S_outputPID := controller.Next(I_PV, I_setpoint);
Then that output should influence your process model, which then produces a new I_PV over time.
Another thing to verify is the error direction. Most PID implementations expect:
error = setpoint - processValue
If the error sign is reversed (PV - setpoint), the controller will continuously drive the system away from the target.
Finally, it is also important to limit the PID output range (for example min/max output). Otherwise the integral term can keep growing and lead to values like +INF.
So in short:
That should allow the controller to approach and stabilize around the setpoint.
I think i get it now. This is just for me to confirm that i'm right. I clamp the PID output signal between 0% and 100% and i use this to control the system in question. Because i haven't got real hardware i need to simulate the system dynamics to get a new value for I_PV.
Could you just confirm that i'm correct in reasoning like this or not?
Yes, your reasoning is mostly correct now.
The important idea is: PID → control output → process/system dynamics → new PV
So the PID output should be clamped (0–100%) and used as the control signal, not written directly back into I_PV.
Your simulation approach is fine for testing the control loop. However, in a more realistic simulation the process dynamics should depend on the control output, not directly on whether I_PV is above or below the setpoint.
So overall, you are on the right track, especially compared to the earlier version where the PID output was assigned directly to I_PV.