July 29, 2026

#311 - Comparing PIDE (Rockwell) with PID_Compact (Siemens) and PIDFF (Schneider)

- Simulation code for Rockwell (simulation_routine_ST.L5X called before the PID routine):

// First Scan Initialization
IF S:FS THEN 
	// Process parameters
	SIMULATION_SampleTime := 0.5; // [s]
	SIMULATION_Process_Tau := 150.0; // [s]
	SIMULATION_Process_Gain := 1.136; // PV/CV = 100.0/88.0
	SIMULATION_Process_DeadTime := 30.0; // [s]
	SIMULATION_Process_Lag_Out := 20.0; // [degC]
	SIMULATION_Disturbance_Period := 240.0; // [s]
	SIMULATION_Disturbance_Angle := 0.0; // [rad]
	SIMULATION_Disturbance_Amplitude := 0.2; // [degC]
	SIMULATION_Disturbance_Load := 0.0; // [degC]
	SIMULATION_Disturbance_Load_Tau := 10.0; // [s]
	SIMULATION_Disturbance_Load_Ramp := 0.0;
	SIMULATION_Disturbance := 0.0;
	SIMULATION_Min_PV := 20.0; // [degC]
	SIMULATION_2PI := 6.28318531; //[rad]
	SIMULATION_DeadTime_SampleTime_Ratio := 0;
	SIMULATION_Delay_Index := 0;
	SIMULATION_SIZE_DELAY_BUFFER_ARRAY := 500; 
	
	// Valve disturbance modes enabled and parameters
	SIMULATION_Enable_ActuatorLag := 0; 
	SIMULATION_Enable_Stiction := 0;
	SIMULATION_Enable_NonLinearity := 0;

	SIMULATION_Stiction_S := 1.5;   // Deadband [%]
	SIMULATION_Stiction_J := 0.8;   // Jump [%]	
	SIMULATION_Actuator_Tau := 2.0;   // [s]
	SIMULATION_Actuator_Offset := 0.1;   // [%]
	SIMULATION_Valve_Curve_Exp := 2.0;   // [%]
	
	SIMULATION_Delayed_CV := 0.0; // [%]
	SIMULATION_Target_CV := 0.0;
	SIMULATION_Lagged_CV := 0.0;
	SIMULATION_Actual_CV := 0.0;
	SIMULATION_Effective_CV := 0.0;

	FOR i := 0 TO SIMULATION_SIZE_DELAY_BUFFER_ARRAY - 1 Do
		SIMULATION_Delay_Buffer[i] := 0.0;
	END_FOR;	
END_IF;	


// VALVE DYNAMICS
// Valve Stiction (Choudhury Model)
IF SIMULATION_Enable_Stiction THEN
    IF ABS(PID_CV - SIMULATION_Target_CV) >= (SIMULATION_Stiction_S / 2.0) THEN
        IF (PID_CV - SIMULATION_Target_CV) > 0.0 THEN
            SIMULATION_Target_CV := PID_CV - ((SIMULATION_Stiction_S / 2.0) - SIMULATION_Stiction_J);
        ELSE
            SIMULATION_Target_CV := PID_CV + ((SIMULATION_Stiction_S / 2.0) - SIMULATION_Stiction_J);
        END_IF;
    END_IF;
	IF SIMULATION_Target_CV < 0.0 THEN
    	SIMULATION_Target_CV := 0.0;
	END_IF;
ELSE
    SIMULATION_Target_CV := PID_CV;
END_IF;

// Actuator Lag and Offset (Euler - First Order Lag Filter)
IF SIMULATION_Enable_ActuatorLag THEN
    SIMULATION_Lagged_CV := SIMULATION_Lagged_CV + (SIMULATION_SampleTime / SIMULATION_Actuator_Tau) * ((SIMULATION_Target_CV - SIMULATION_Actuator_Offset) - SIMULATION_Lagged_CV) ;
	IF SIMULATION_Lagged_CV < 0.0 THEN
    	SIMULATION_Lagged_CV := 0.0;
	END_IF;
ELSE
    SIMULATION_Lagged_CV := SIMULATION_Target_CV;
END_IF;

// Non-Linear Flow Characteristic (Power Law Curve)
IF SIMULATION_Enable_NonLinearity THEN
    IF SIMULATION_Lagged_CV > 0.0 THEN
        SIMULATION_Actual_CV := 100.0 * ((SIMULATION_Lagged_CV / 100.0) ** SIMULATION_Valve_Curve_Exp);
    ELSE
        SIMULATION_Actual_CV := 0.0;
    END_IF;
	IF SIMULATION_Actual_CV < 0.0 THEN
    	SIMULATION_Actual_CV := 0.0;
	END_IF;
ELSE
    SIMULATION_Actual_CV := SIMULATION_Lagged_CV;
END_IF;

SIMULATION_Effective_CV := SIMULATION_Actual_CV;


// FOPDT PROCESS SIMULATION
// Cyclic Disturbance wave
SIMULATION_Disturbance_Angle := SIMULATION_Disturbance_Angle + ((SIMULATION_SampleTime / SIMULATION_Disturbance_Period) * SIMULATION_2PI);
IF SIMULATION_Disturbance_Angle >= SIMULATION_2PI THEN
    SIMULATION_Disturbance_Angle := SIMULATION_Disturbance_Angle - SIMULATION_2PI;
END_IF;
SIMULATION_Disturbance := SIN(SIMULATION_Disturbance_Angle) * SIMULATION_Disturbance_Amplitude;

// Write CV to dead-time buffer
SIMULATION_Delay_Buffer[SIMULATION_Delay_Index] := SIMULATION_Effective_CV;

// Read CV from dead-time buffer
SIMULATION_DeadTime_SampleTime_Ratio := SIMULATION_Process_DeadTime / SIMULATION_SampleTime;
SIMULATION_Delayed_CV := SIMULATION_Delay_Buffer[(SIMULATION_Delay_Index - SIMULATION_DeadTime_SampleTime_Ratio + SIMULATION_SIZE_DELAY_BUFFER_ARRAY) MOD SIMULATION_SIZE_DELAY_BUFFER_ARRAY]; 

// Increment buffer index
SIMULATION_Delay_Index := (SIMULATION_Delay_Index + 1) MOD SIMULATION_SIZE_DELAY_BUFFER_ARRAY;

// Process Lag (Euler - First Order Lag Filter)
SIMULATION_Process_Lag_Out := SIMULATION_Process_Lag_Out + (SIMULATION_SampleTime / SIMULATION_Process_Tau) * ((SIMULATION_Process_Gain * SIMULATION_Delayed_CV) - SIMULATION_Process_Lag_Out);

// Load Disturbance Lag (Euler - First Order Lag Filter)
SIMULATION_Disturbance_Load_Ramp := SIMULATION_Disturbance_Load_Ramp + (SIMULATION_SampleTime / SIMULATION_Disturbance_Load_Tau) * (SIMULATION_Disturbance_Load - SIMULATION_Disturbance_Load_Ramp);

// Combine outputs
PID_PV := SIMULATION_Disturbance + SIMULATION_Process_Lag_Out + SIMULATION_Disturbance_Load_Ramp;
IF PID_PV < SIMULATION_Min_PV THEN
    PID_PV := SIMULATION_Min_PV;
END_IF;

- PID block configuration and trend to validate the process simulation:

- Simulation code for Schneider (simulation.xst):

(* First Scan Initialization *)
IF FIRST_TASKRUN_RESET THEN 
	(* Process Parameters *)
	SIMULATION_SampleTime := 0.5; (* [s] *)
	SIMULATION_Process_Tau := 150.0; (* [s] *)
	SIMULATION_Process_Gain := 1.136; (* PV/CV = 100.0/88.0 *)
	SIMULATION_Process_DeadTime := 30.0; (* [s] *)
	SIMULATION_Process_Lag_Out := 20.0; (* [degC] *)
	SIMULATION_Disturbance_Period := 240.0; (* [s] *)
	SIMULATION_Disturbance_Angle := 0.0; (* [rad] *)
	SIMULATION_Disturbance_Amplitude := 0.2; (* [degC] *)
	SIMULATION_Disturbance_Load := 0.0; (* [degC] *)
	SIMULATION_Disturbance_Load_Tau := 10.0; (* [s] *)
	SIMULATION_Disturbance_Load_Ramp := 0.0; 
	SIMULATION_Disturbance := 0.0;
	SIMULATION_Min_PV := 20.0; (* [degC] *)
	SIMULATION_2PI := 6.28318531; (* [rad] *)
	SIMULATION_Delay_Index := 0; 
	SIMULATION_SIZE_ARRAY := 500; 

	(* Valve disturbance modes enable and parameters *)
	SIMULATION_Enable_ActuatorLag := FALSE; 
	SIMULATION_Enable_Stiction := FALSE;
	SIMULATION_Enable_NonLinearity := FALSE;

	SIMULATION_Stiction_S := 1.5;   (* Deadband [%] *)
	SIMULATION_Stiction_J := 0.8;   (* Jump [%] *)	
	SIMULATION_Actuator_Tau := 2.0;   (* [s] *)
	SIMULATION_Actuator_Offset := 0.1;   (* [%] *)
	SIMULATION_Valve_Curve_Exp := 2.0;   (* [%] *)
	
	SIMULATION_Delayed_CV := 0.0; (* [%] *)
	SIMULATION_Target_CV := 0.0;
	SIMULATION_Lagged_CV := 0.0;
	SIMULATION_Actual_CV := 0.0;
	SIMULATION_Effective_CV := 0.0;

	(* PID parameters *)
	PIDFF_PARA.pv_inf := 0.0;
	PIDFF_PARA.pv_sup := 110.0;
	PIDFF_PARA.out_inf := 0.0;
	PIDFF_PARA.out_sup := 100.0; 
	PIDFF_PARA.out_min := 0.0;
	PIDFF_PARA.out_max := 100.0; 
	PIDFF_PARA.kp := 2.5;
	PIDFF_PARA.ti := t#60s;
	PIDFF_PARA.td := t#12s;

	(* Clear buffer array *)
	FOR i := 0 TO SIMULATION_SIZE_ARRAY -1 BY 1 DO
 		SIMULATION_Delay_Buffer[i] := 0.0;
 	END_FOR;
END_IF;	

(* VALVE DYNAMICS *)
(* Valve Stiction (Choudhury Model) *)
IF SIMULATION_Enable_Stiction THEN
    IF ABS(PID_CV - SIMULATION_Target_CV) >= (SIMULATION_Stiction_S / 2.0) THEN
        IF (PID_CV - SIMULATION_Target_CV) > 0.0 THEN
            SIMULATION_Target_CV := PID_CV - ((SIMULATION_Stiction_S / 2.0) - SIMULATION_Stiction_J);
        ELSE
            SIMULATION_Target_CV := PID_CV + ((SIMULATION_Stiction_S / 2.0) - SIMULATION_Stiction_J);
        END_IF;
    END_IF;
	IF SIMULATION_Target_CV < 0.0 THEN
    	SIMULATION_Target_CV := 0.0;
	END_IF;
ELSE
    SIMULATION_Target_CV := PID_CV;
END_IF;

(* Actuator Lag and Offset (Euler - First Order Lag Filter) *)
IF SIMULATION_Enable_ActuatorLag THEN
	SIMULATION_Lagged_CV := SIMULATION_Lagged_CV + (SIMULATION_SampleTime / SIMULATION_Actuator_Tau) * ((SIMULATION_Target_CV - SIMULATION_Actuator_Offset) - SIMULATION_Lagged_CV) ;
	IF SIMULATION_Lagged_CV < 0.0 THEN
    		SIMULATION_Lagged_CV := 0.0;
	END_IF;
ELSE
	SIMULATION_Lagged_CV := SIMULATION_Target_CV;
END_IF;


(* Non-Linear Flow Characteristic (Power Law Curve) *)
IF SIMULATION_Enable_NonLinearity THEN
	IF SIMULATION_Lagged_CV > 0.0 THEN
        	SIMULATION_Actual_CV := 100.0 * EXPT_REAL_REAL((SIMULATION_Lagged_CV / 100.0),SIMULATION_Valve_Curve_Exp); 
    	ELSE
        	SIMULATION_Actual_CV := 0.0;
	END_IF;
	IF SIMULATION_Actual_CV < 0.0 THEN
    		SIMULATION_Actual_CV := 0.0;
	END_IF;
ELSE
	SIMULATION_Actual_CV := SIMULATION_Lagged_CV;
END_IF;

SIMULATION_Effective_CV := SIMULATION_Actual_CV;


(* FOPDT PROCESS SIMULATION *)
(* Cyclic Disturbance wave*)
SIMULATION_Disturbance_Angle := SIMULATION_Disturbance_Angle + (( SIMULATION_SampleTime / SIMULATION_Disturbance_Period) * SIMULATION_2PI);
IF SIMULATION_Disturbance_Angle >= SIMULATION_2PI THEN
	SIMULATION_Disturbance_Angle := SIMULATION_Disturbance_Angle - SIMULATION_2PI;
END_IF;
SIMULATION_Disturbance := SIN(SIMULATION_Disturbance_Angle) * SIMULATION_Disturbance_Amplitude;

(* Write CV to dead-time buffer *)
SIMULATION_Delay_Buffer[SIMULATION_Delay_Index] := SIMULATION_Effective_CV;

(* Read CV FROM dead-time buffer *)
SIMULATION_Delayed_CV := SIMULATION_Delay_Buffer[(SIMULATION_Delay_Index - REAL_TO_DINT (IN := SIMULATION_Process_DeadTime / SIMULATION_SampleTime) + SIMULATION_SIZE_ARRAY) MOD SIMULATION_SIZE_ARRAY]; 

(* Increment buffer index *)
SIMULATION_Delay_Index := (SIMULATION_Delay_Index + 1) MOD SIMULATION_SIZE_ARRAY;

(* Process Lag (Eurler - First Order Lag Filter *)
SIMULATION_Process_Lag_Out := SIMULATION_Process_Lag_Out + (SIMULATION_SampleTime / SIMULATION_Process_Tau) * ((SIMULATION_Process_Gain * SIMULATION_Delayed_CV) - SIMULATION_Process_Lag_Out);

(* Load Disturbance Lag (Eurler - First Order Lag Filter *)
SIMULATION_Disturbance_Load_Ramp := SIMULATION_Disturbance_Load_Ramp + (SIMULATION_SampleTime / SIMULATION_Disturbance_Load_Tau) * (SIMULATION_Disturbance_Load - SIMULATION_Disturbance_Load_Ramp);

(* Combine the lag process output with the sine wave disturbance *)
PID_PV := SIMULATION_Disturbance + SIMULATION_Process_Lag_Out + SIMULATION_Disturbance_Load_Ramp; 
IF PID_PV < SIMULATION_Min_PV THEN
	PID_PV := SIMULATION_Min_PV;
END_IF;

Schneider PIDFF configuration and trend:

- Simulation code for Siemens (simulation.scl FB called before the PID routine):

FUNCTION_BLOCK "SIMULATION"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR 
      SIMULATION_SampleTime : Real;
      SIMULATION_Process_Tau : Real;
      SIMULATION_Process_Gain : Real;
      SIMULATION_Process_DeadTime : Real;
      SIMULATION_Process_Lag_Out : Real;
      SIMULATION_Disturbance_Period : Real;
      SIMULATION_Disturbance_Angle : Real;
      SIMULATION_Disturbance_Amplitude : Real;
      SIMULATION_Disturbance_Load : Real;
      SIMULATION_Disturbance_Load_Tau : Real;
      SIMULATION_Disturbance_Load_Ramp : Real;
      SIMULATION_Disturbance : Real;
      SIMULATION_Delayed_CV : Real;
      SIMULATION_2PI : Real;
      SIMULATION_Delay_Index : DInt;
      SIMULATION_SIZE_DELAY_BUFFER_ARRAY : DInt;
      SIMULATION_Delay_Buffer : Array[0..499] of Real;
      SIMULATION_Min_PV : Real;
      SIMULATION_Effective_CV : Real;
      SIMULATION_Enable_ActuatorLag : Bool;
      SIMULATION_Enable_Stiction : Bool;
      SIMULATION_Enable_NonLinearity : Bool;
      SIMULATION_Stiction_S : Real;
      SIMULATION_Stiction_J : Real;
      SIMULATION_Actuator_Tau : Real;
      SIMULATION_Actuator_Offset : Real;
      SIMULATION_Valve_Curve_Exp : Real;
      SIMULATION_Target_CV : Real;
      SIMULATION_Lagged_CV : Real;
      SIMULATION_Actual_CV : Real;
   END_VAR

   VAR_TEMP 
      i : DInt;
   END_VAR

BEGIN
	// First Scan Initialization
	IF "FIRSTSCAN_TP".Q THEN
	    // Process parameters
	    #SIMULATION_SampleTime := 0.5; // [s]
	    #SIMULATION_Process_Tau := 150.0; // [s]
	    #SIMULATION_Process_Gain := 1.136; // PV/CV = 100.0/88.0
	    #SIMULATION_Process_DeadTime := 30.0; // [s]
	    #SIMULATION_Process_Lag_Out := 20.0; // [degC]
	    #SIMULATION_Disturbance_Period := 240.0; // [s]
	    #SIMULATION_Disturbance_Angle := 0.0; // [rad]
	    #SIMULATION_Disturbance_Amplitude := 0.2; // [degC]
	    #SIMULATION_Disturbance_Load := 0.0; // [degC]
	    #SIMULATION_Disturbance_Load_Tau := 10.0; // [s]
	    #SIMULATION_Disturbance_Load_Ramp := 0.0;
	    #SIMULATION_Disturbance := 0.0;
	    #SIMULATION_Min_PV := 20.0; // [degC]
	    #SIMULATION_2PI := 6.28318531; //[rad]
	    #SIMULATION_Delay_Index := 0;
	    #SIMULATION_SIZE_DELAY_BUFFER_ARRAY := 500;
	    
	    // Valve disturbance modes enabled and parameters
	    #SIMULATION_Enable_ActuatorLag := FALSE;
	    #SIMULATION_Enable_Stiction := FALSE;
	    #SIMULATION_Enable_NonLinearity := FALSE;
	    
	    #SIMULATION_Stiction_S := 1.5;   // Deadband [%]
	    #SIMULATION_Stiction_J := 0.8;   // Jump [%] 
	    #SIMULATION_Actuator_Tau := 2.0;   // [s]
	    #SIMULATION_Actuator_Offset := 0.1;   // [%]
	    #SIMULATION_Valve_Curve_Exp := 2.0;   // [%]
	    
	    #SIMULATION_Delayed_CV := 0.0; // [%]
	    #SIMULATION_Target_CV := 0.0;
	    #SIMULATION_Lagged_CV := 0.0;
	    #SIMULATION_Actual_CV := 0.0;
	    #SIMULATION_Effective_CV := 0.0;
	    
	    FOR #i := 0 TO #SIMULATION_SIZE_DELAY_BUFFER_ARRAY - 1 DO
	        #SIMULATION_Delay_Buffer[#i] := 0.0;
	    END_FOR;
	END_IF;
	
	// VALVE DYNAMICS
	// Valve Stiction (Choudhury Model)
	IF #SIMULATION_Enable_Stiction THEN
	    IF ABS("PID_CV" - #SIMULATION_Target_CV) >= (#SIMULATION_Stiction_S / 2.0) THEN
	        IF ("PID_CV" - #SIMULATION_Target_CV) > 0.0 THEN
	            #SIMULATION_Target_CV := "PID_CV" - ((#SIMULATION_Stiction_S / 2.0) - #SIMULATION_Stiction_J);
	        ELSE
	            #SIMULATION_Target_CV := "PID_CV" + ((#SIMULATION_Stiction_S / 2.0) - #SIMULATION_Stiction_J);
	        END_IF;
	    END_IF;
	    IF #SIMULATION_Target_CV < 0.0 THEN
	        #SIMULATION_Target_CV := 0.0;
	    END_IF;
	ELSE
	    #SIMULATION_Target_CV := "PID_CV";
	END_IF;
	
	// Actuator Lag and Offset (Euler - First Order Lag Filter)
	IF #SIMULATION_Enable_ActuatorLag THEN
	    #SIMULATION_Lagged_CV := #SIMULATION_Lagged_CV + (#SIMULATION_SampleTime / #SIMULATION_Actuator_Tau) * ((#SIMULATION_Target_CV - #SIMULATION_Actuator_Offset) - #SIMULATION_Lagged_CV);
	    IF #SIMULATION_Lagged_CV < 0.0 THEN
	        #SIMULATION_Lagged_CV := 0.0;
	    END_IF;
	ELSE
	    #SIMULATION_Lagged_CV := #SIMULATION_Target_CV;
	END_IF;
	
	// Non-Linear Flow Characteristic (Power Law Curve)
	IF #SIMULATION_Enable_NonLinearity THEN
	    IF #SIMULATION_Lagged_CV > 0.0 THEN
	        #SIMULATION_Actual_CV := 100.0 * ((#SIMULATION_Lagged_CV / 100.0) ** #SIMULATION_Valve_Curve_Exp);
	    ELSE
	        #SIMULATION_Actual_CV := 0.0;
	    END_IF;
	    IF #SIMULATION_Actual_CV < 0.0 THEN
	        #SIMULATION_Actual_CV := 0.0;
	    END_IF;
	ELSE
	    #SIMULATION_Actual_CV := #SIMULATION_Lagged_CV;
	END_IF;
	
	#SIMULATION_Effective_CV := #SIMULATION_Actual_CV;
	
	// FOPDT PROCESS SIMULATION
	// Cyclic Disturbance wave
	#SIMULATION_Disturbance_Angle := #SIMULATION_Disturbance_Angle + ((#SIMULATION_SampleTime / #SIMULATION_Disturbance_Period) *  #SIMULATION_2PI);
	IF #SIMULATION_Disturbance_Angle >= #SIMULATION_2PI THEN
	    #SIMULATION_Disturbance_Angle := #SIMULATION_Disturbance_Angle - #SIMULATION_2PI;
	END_IF;
	#SIMULATION_Disturbance := SIN(#SIMULATION_Disturbance_Angle) * #SIMULATION_Disturbance_Amplitude;
	
	// Write CV to dead-time buffer
	#SIMULATION_Delay_Buffer[#SIMULATION_Delay_Index] := #SIMULATION_Effective_CV;
	
	// Read CV from dead-time buffer
	#SIMULATION_Delayed_CV := #SIMULATION_Delay_Buffer[(#SIMULATION_Delay_Index - REAL_TO_DINT(#SIMULATION_Process_DeadTime / #SIMULATION_SampleTime) + #SIMULATION_SIZE_DELAY_BUFFER_ARRAY) MOD #SIMULATION_SIZE_DELAY_BUFFER_ARRAY];
	
	// Increment buffer index
	#SIMULATION_Delay_Index := (#SIMULATION_Delay_Index + 1) MOD #SIMULATION_SIZE_DELAY_BUFFER_ARRAY;
	
	// Process Lag (Euler - First Order Lag Filter)
	#SIMULATION_Process_Lag_Out := #SIMULATION_Process_Lag_Out + (#SIMULATION_SampleTime / #SIMULATION_Process_Tau) * ((#SIMULATION_Process_Gain * #SIMULATION_Delayed_CV) - #SIMULATION_Process_Lag_Out);
	
	// Load Disturbance Lag (Euler - First Order Lag Filter)
	#SIMULATION_Disturbance_Load_Ramp := #SIMULATION_Disturbance_Load_Ramp + (#SIMULATION_SampleTime / #SIMULATION_Disturbance_Load_Tau) * (#SIMULATION_Disturbance_Load - #SIMULATION_Disturbance_Load_Ramp);
	
	// Combine outputs
	"PID_PV" := #SIMULATION_Disturbance + #SIMULATION_Process_Lag_Out + #SIMULATION_Disturbance_Load_Ramp;
	IF "PID_PV" < #SIMULATION_Min_PV THEN
	    "PID_PV" := #SIMULATION_Min_PV;
	END_IF;
END_FUNCTION_BLOCK

- Siemens PID_Compact configuration and trend:

No comments:

Post a Comment