Page 4 sur 4

Re: PID autotune - la méthode du relais

Posté : 04 nov. 2016, 10:53
par Cyril93
Salut damiette,

Le code SCL pour Step7 V5.5 si tu veux intégrer dans le TIA il y a quelques modifs à prévoir (voir les anciens post)


====================================================================================================
Le FB de mesure de fréquence
====================================================================================================

Code : Tout sélectionner

FUNCTION_BLOCK FREQ_MEASURE
TITLE = 'FREQ_MEASURE'
//
//Adaptation du FB FREQ_MEASURE de la lib Util de 3S.
//La mesure ne doit pas dépasser 24D20H31M23S647MS car le débordement de l'horloge système n'est pas testé. 
//
VERSION : '1.0'
AUTHOR  : Cyril93
NAME    : FREQ_MEA
FAMILY  : MESURE
//KNOW_HOW_PROTECT

VAR_INPUT
    IN: BOOL;                              (* input signal *)
    PERIODS: INT :=1;                  (* out is the average frequency during PERIODS (number of periods) between 1 to 10 *)
    RESET: BOOL;                        (* reset measurement *)
END_VAR
VAR_OUTPUT
    OUT: REAL;                           (* frequency [Hz]*)
    VALID: BOOL;                        (* FALSE: not yet PERIODS measurements done OR time distance between two rising edges > 3*OUT *)
END_VAR
VAR
    OLDIN: BOOL;
    INIT: BOOL;
    OLDT: TIME;
    DIFF: DINT;
    ADIFF: ARRAY[0..9] OF DINT;
    V: INT;
    B:INT;
    I: INT;            
END_VAR


BEGIN

IF RESET THEN
    B:=0;
    V:=0;
    INIT:=FALSE;
    VALID:=FALSE;
    OUT:=0;
    RETURN;
END_IF;

IF IN AND NOT OLDIN THEN    (*rising edge *)
    IF INIT THEN
        DIFF := TIME_TO_DINT(TIME_TCK()-OLDT);
        IF Diff > 0 THEN
            ADIFF[B] := DIFF;
            B := (B+1) MOD PERIODS;
            V:=MIN(IN1:=V+1, IN2:=PERIODS);
            IF V=PERIODS THEN
                OUT := 0;
                FOR I:=0 TO PERIODS-1 DO
                    OUT := OUT + ADIFF[I];
                END_FOR;
                OUT := 1000.0 * PERIODS / OUT;
                VALID:=TRUE;
            ELSE
                VALID:=FALSE;
            END_IF;
        END_IF;
    END_IF;
    INIT := TRUE;
    OLDT := TIME_TCK();
ELSIF INIT AND VALID AND TIME_TO_DINT(TIME_TCK()-OLDT) > 3000*OUT THEN
    VALID:=FALSE;
    V:=0;
    B:=0;
END_IF;

OLDIN:=IN;

END_FUNCTION_BLOCK

====================================================================================================
Le FB de la méthode du relais (c'est ce bloc qu'il faut appelé dans le programme)
====================================================================================================

Code : Tout sélectionner

FUNCTION_BLOCK CALC_PID
TITLE = 'CALC_PID'
//
//Auto-réglage des constantes PID par la méthode du relais de Astrom-Hagglund.
//
VERSION : '1.1'
AUTHOR  : Cyril93
NAME    : CALC_PID
FAMILY  : REGUL
//KNOW_HOW_PROTECT

VAR_INPUT
    bEN : BOOL;                        (* Démarre la séquence par le front montant *)
    rSP : REAL;                         (* Point de consigne *)
    rPV: REAL;                          (* Mesure process *)
    iCY: INT:=2;                        (* Nombre de cycle du réglage automatique (minimum 2)*)
    bRST: BOOL;                       (* Remise à zéro *)
    rL_VAL: REAL;                     (* Valeur basse pour la sortie *)
    rH_VAL: REAL;                    (* Valeur haute pour la sortie *)
    iPERF: INT;                         (* Performances des constantes PID : 0=rapides, 1=normales, 2=lentes *)
END_VAR
VAR_OUTPUT
    bEND: BOOL;                        (* Fin séquence *)
    rSQ_VAL: REAL;                    (* Sortie onde carrée pour l'exitation du process *)
    rKP: REAL;                           (* Gain proportionnel *)
    rTN: REAL;                           (* Temps d'intégrale en s *)
    rTV: REAL;                           (* Temps de dérivée en s *)
END_VAR
VAR
    PU: REAL;                          (* Gain ultime *)
    TU: REAL;                          (* Période ultime *)
    b: REAL;                           (* Amplitude de PV *)
    a: REAL;                           (* Amplitude de SQ_VAL *)
  
    Tu_Freq: FREQ_MEASURE;          
    b_Min: REAL;
    b_Max: REAL;
    EdgeEnd: BOOL;
    FlagEnd: BOOL;
    End: BOOL;
    
    status: INT;
    cpt: INT;
    old_bEN: BOOL;
    RstFreq: BOOL;
    PerFreq: INT;
            
END_VAR
CONST
    PI := REAL#3.14159265358979323846264338327950288;
END_CONST


BEGIN
(*** Séquence autotune ***)

IF bRST THEN
    status:=0;
END_IF;

CASE status OF
0: (* Attente Démarrage autotune *)
    rSQ_VAL:=rL_VAL;
    IF bEN AND NOT old_bEN THEN
        RstFreq:=TRUE;
        b_Min:=3.402823E+38 ;
        b_Max:=-3.402823E+38 ;
        rKP:=0;
        rTN:=0;
        rTV:=0;
        cpt:=0;
        bEND:=FALSE;
        status:=1;
        End:=FALSE;
    END_IF;

1: (* Onde carrée haute *)
    rSQ_VAL:=rH_VAL;
    IF rPV > rSP THEN
        rSQ_VAL:=rL_VAL;
        cpt:=cpt+1;
        status:=2;
    END_IF;

2: (* Onde carrée basse et fin de séquence *)
    IF rPV < rSP THEN
        cpt:=cpt+1;
        IF cpt >= iCY THEN
            status:=1;
            End:=TRUE;
        ELSE
            status:=1;
        END_IF;
    END_IF;

END_CASE;

old_bEN:=bEN;

(*** Calcul des paramètres ***)

(* min/max et freq de PV  *)

IF rPV<b_Min THEN
    b_Min:=rPV;
END_IF;
IF rPV>b_Max THEN
    b_Max:=rPV;
END_IF;

(* Nombre de période pour le bloc FREQ_MEASURE *)
PerFreq:=(iCY/2)-1;
PerFreq:=LIMIT(MN:=1, IN:=PerFreq, MX:=10);

Tu_Freq(
    IN := rPV > rSP ,
    PERIODS :=PerFreq  ,
    RESET := RstFreq); 
    
RstFreq:=FALSE;  

(* Calcul sur front montant de End et valeur de sortie de FREQ_MEASURE ok *)
EdgeEnd:= End AND Tu_Freq.OUT <> 0 AND NOT FlagEnd; 
FlagEnd:= End AND Tu_Freq.OUT <> 0; 

IF EdgeEnd THEN
    
    (* amp de SQ_VAL *)
    a:=rH_VAL-rL_VAL;

    (* amp de PV *)
    b:=b_Max-b_Min;

    (* Gain et période ultime *)
    PU:=(4 * b)/(PI * a);
    TU:=1/Tu_Freq.OUT;

    (* Valeur PID *)
    CASE iPERF OF
    0:(* Performances rapides *)
        rKP:= 0.6 * PU;
        rTN:= 0.5 * TU;
        rTV:= 0.125 * TU;

    1:(* Performances normales *)
        rKP:= 0.25 * PU;
        rTN:= 0.5 * TU;
        rTV:= 0.125 * TU;

    2:(* Performances lentes *)
        rKP:= 0.15 * PU;
        rTN:= 0.5 * TU;
        rTV:= 0.125 * TU;
    END_CASE;
    
    bEND:=TRUE;
    status:=0;

END_IF;

END_FUNCTION_BLOCK


Re: PID autotune - la méthode du relais

Posté : 04 nov. 2016, 11:07
par Cyril93
et le DFB pour unity pro, je l'ai fait avec la V5 mais ça doit être compatible avec les autres versions

nota : copier coller dans un éditeur de texte et sauver en .XDB puis importer les DFB dans Unity Pro

Code : Tout sélectionner

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FBExchangeFile>
	<fileHeader company="Schneider Automation" product="Unity Pro XL V5.0 - 100504A" dateTime="date_and_time#2016-5-4-10:34:10" content="Fichier source bloc fonctions" DTDVersion="41"></fileHeader>
	<contentHeader name="Projet" version="0.0.95" dateTime="date_and_time#2016-5-4-11:33:51"></contentHeader>
	<FBSource nameOfFBType="CALC_PID" version="0.02" dateTime="dt#2016-05-04-10:33:47">
		<comment>Auto-réglage des constantes PID par la méthode du relais de Astrom-Hagglund.</comment>
		<inputParameters>
			<variables name="bEN" typeName="BOOL">
				<comment>Démarre la séquence par le front montant</comment>
				<attribute name="PositionPin" value="1"></attribute>
			</variables>
			<variables name="rSP" typeName="REAL">
				<comment>Point de consigne</comment>
				<attribute name="PositionPin" value="2"></attribute>
			</variables>
			<variables name="rPV" typeName="REAL">
				<comment>Mesure process</comment>
				<attribute name="PositionPin" value="3"></attribute>
			</variables>
			<variables name="iCY" typeName="INT">
				<comment>Nombre de cycle du réglage automatique</comment>
				<attribute name="PositionPin" value="4"></attribute>
			</variables>
			<variables name="bRST" typeName="BOOL">
				<comment>Remise à zéro</comment>
				<attribute name="PositionPin" value="5"></attribute>
			</variables>
			<variables name="rL_VAL" typeName="REAL">
				<comment>Valeur basse pour la sortie</comment>
				<attribute name="PositionPin" value="6"></attribute>
			</variables>
			<variables name="rH_VAL" typeName="REAL">
				<comment>Valeur haute pour la sortie</comment>
				<attribute name="PositionPin" value="7"></attribute>
			</variables>
			<variables name="iPERF" typeName="INT">
				<comment>Performances des constantes PID : 0=rapides, 1=normales, 2=lentes</comment>
				<attribute name="PositionPin" value="8"></attribute>
			</variables>
		</inputParameters>
		<outputParameters>
			<variables name="bEND" typeName="BOOL">
				<comment>Fin séquence</comment>
				<attribute name="PositionPin" value="1"></attribute>
			</variables>
			<variables name="rSQ_VAL" typeName="REAL">
				<comment>Sortie onde carrée pour l'exitation du process</comment>
				<attribute name="PositionPin" value="2"></attribute>
			</variables>
			<variables name="rKP" typeName="REAL">
				<comment>Gain proportionnel</comment>
				<attribute name="PositionPin" value="3"></attribute>
			</variables>
			<variables name="rTN" typeName="REAL">
				<comment>Temps d'intégrale en s</comment>
				<attribute name="PositionPin" value="4"></attribute>
			</variables>
			<variables name="rTV" typeName="REAL">
				<comment>Temps de dérivée en s </comment>
				<attribute name="PositionPin" value="5"></attribute>
			</variables>
		</outputParameters>
		<publicLocalVariables>
			<variables name="PU" typeName="REAL">
				<comment>Gain ultime</comment>
			</variables>
			<variables name="TU" typeName="REAL">
				<comment>Période ultime</comment>
			</variables>
		</publicLocalVariables>
		<privateLocalVariables>
			<variables name="b" typeName="REAL"></variables>
			<variables name="a" typeName="REAL"></variables>
			<variables name="Tu_Freq" typeName="FREQ_MEASURE"></variables>
			<variables name="b_Min" typeName="REAL"></variables>
			<variables name="b_Max" typeName="REAL"></variables>
			<variables name="EdgeEnd" typeName="BOOL"></variables>
			<variables name="FlagEnd" typeName="BOOL"></variables>
			<variables name="End" typeName="BOOL"></variables>
			<variables name="status" typeName="INT"></variables>
			<variables name="cpt" typeName="INT"></variables>
			<variables name="old_bEN" typeName="BOOL"></variables>
			<variables name="RstFreq" typeName="BOOL"></variables>
			<variables name="PerFreq" typeName="INT"></variables>
			<variables name="PI" typeName="REAL">
				<comment>Constante PI</comment>
				<variableInit value="3.14159265358979323846264338327950288"></variableInit>
			</variables>
		</privateLocalVariables>
		<FBProgram name="CALC_PID">
			<STSource>(*** Séquence autotune ***)

IF bRST THEN
    status:=0;
END_IF;

CASE status OF
0: (* Attente Démarrage autotune *)
    rSQ_VAL:=rL_VAL;
    IF bEN AND NOT old_bEN THEN
        RstFreq:=TRUE;
        b_Min:=3.402823E+38 ;
        b_Max:=-3.402823E+38 ;
        rKP:=0.0;
        rTN:=0.0;
        rTV:=0.0;
        cpt:=0;
        bEND:=FALSE;
        status:=1;
	End:=FALSE;
    END_IF;

1: (* Onde carrée haute *)
    rSQ_VAL:=rH_VAL;
    IF rPV > rSP THEN
        rSQ_VAL:=rL_VAL;
        cpt:=cpt+1;
        status:=2;
    END_IF;

2: (* Onde carrée basse et fin de séquence *)
    IF rPV < rSP THEN
        cpt:=cpt+1;
        IF cpt >= iCY THEN
            status:=1;
            End:=TRUE;
        ELSE
            status:=1;
        END_IF;
    END_IF;

END_CASE;

old_bEN:=bEN;

(*** Calcul des paramètres ***)

(* min/max et freq de PV  *)

IF rPV<b_Min THEN
    b_Min:=rPV;
END_IF;
IF rPV>b_Max THEN
    b_Max:=rPV;
END_IF;

(* Nombre de période pour le bloc FREQ_MEASURE *)
PerFreq:=(iCY/2)-1;
PerFreq:=LIMIT(1, PerFreq, 10);

Tu_Freq(
    IN := rPV > rSP ,
    PERIODS :=PerFreq  ,
    RESET := RstFreq); 
    
RstFreq:=FALSE;                                           

(* Calcul sur front montant de End et valeur de sortie de FREQ_MEASURE ok *)
EdgeEnd:= End AND Tu_Freq.OUT <> 0.0 AND NOT FlagEnd;
FlagEnd:= End AND Tu_Freq.OUT <> 0.0 ;


IF EdgeEnd THEN
    (* amp de SQ_VAL *)
    a:=rH_VAL-rL_VAL;

    (* amp de PV *)
    b:=b_Max-b_Min;

    (* Gain et période ultime *)
    PU:=(4.0 * b)/(PI * a);
    TU:=1.0/Tu_Freq.OUT;

    (* Valeur PID *)
    CASE iPERF OF
    0:(* Performances rapides *)
        rKP:= 0.6 * PU;
        rTN:= 0.5 * TU;
        rTV:= 0.125 * TU;

    1:(* Performances normales *)
        rKP:= 0.25 * PU;
        rTN:= 0.5 * TU;
        rTV:= 0.125 * TU;

    2:(* Performances lentes *)
        rKP:= 0.15 * PU;
        rTN:= 0.5 * TU;
        rTV:= 0.125 * TU;
    END_CASE;

    bEND:=TRUE;
    status:=0;

END_IF;
</STSource>
		</FBProgram>
	</FBSource>
	<FBSource nameOfFBType="FREQ_MEASURE" version="0.02" dateTime="dt#2016-04-27-14:11:07">
		<comment>Adaptation du FB FREQ_MEASURE de la lib Util de 3S.</comment>
		<inputParameters>
			<variables name="IN" typeName="BOOL">
				<comment>input signal</comment>
				<attribute name="PositionPin" value="1"></attribute>
			</variables>
			<variables name="PERIODS" typeName="INT">
				<comment>out is the average frequency during PERIODS (number of periods) between 1 to 10</comment>
				<attribute name="PositionPin" value="2"></attribute>
				<variableInit value="1"></variableInit>
			</variables>
			<variables name="RESET" typeName="BOOL">
				<comment>reset measurement</comment>
				<attribute name="PositionPin" value="3"></attribute>
			</variables>
		</inputParameters>
		<outputParameters>
			<variables name="OUT" typeName="REAL">
				<comment>frequency [Hz]</comment>
				<attribute name="PositionPin" value="1"></attribute>
			</variables>
			<variables name="VALID" typeName="BOOL">
				<comment>FALSE: not yet PERIODS measurements done OR time distance between two rising edges > 3*OUT</comment>
				<attribute name="PositionPin" value="2"></attribute>
			</variables>
		</outputParameters>
		<privateLocalVariables>
			<variables name="OLDIN" typeName="BOOL"></variables>
			<variables name="INIT" typeName="BOOL"></variables>
			<variables name="OLDT" typeName="DINT"></variables>
			<variables name="DIFF" typeName="DINT"></variables>
			<variables name="ADIFF" typeName="ARRAY[0..9] OF DINT"></variables>
			<variables name="V" typeName="INT"></variables>
			<variables name="B" typeName="INT"></variables>
			<variables name="I" typeName="INT"></variables>
		</privateLocalVariables>
		<FBProgram name="FREQ_MEASURE">
			<STSource>(* Adaptation du FB FREQ_MEASURE de la lib Util de 3S. *)

IF RESET THEN
    B:=0;
    V:=0;
    INIT:=FALSE;
    VALID:=FALSE;
    OUT:=0.0;
    RETURN;
END_IF;

IF IN AND NOT OLDIN THEN    (*rising edge *)
    IF INIT THEN
        DIFF := (FREERUN ()-OLDT)/1000;
        IF Diff > 0 THEN
            ADIFF[B] := DIFF;
            B := (B+1) MOD PERIODS;
            V:=MIN(IN1:=V+1, IN2:=PERIODS);
            IF V=PERIODS THEN
                OUT := 0.0;
                FOR I:=0 TO PERIODS-1 DO
                    OUT := OUT + DINT_TO_REAL(ADIFF[I]);
                END_FOR;
                OUT := 1000.0 * INT_TO_REAL(PERIODS) / OUT;
                VALID:=TRUE;
            ELSE
                VALID:=FALSE;
            END_IF;
        END_IF;
    END_IF;
    INIT := TRUE;
    OLDT := FREERUN ();
ELSIF INIT AND VALID AND ((FREERUN ()-OLDT)/1000) > REAL_TO_DINT(3000.0*OUT) THEN
    VALID:=FALSE;
    V:=0;
    B:=0;
END_IF;

OLDIN:=IN;
</STSource>
		</FBProgram>
	</FBSource>
</FBExchangeFile>


Re: PID autotune - la méthode du relais

Posté : 04 nov. 2016, 13:36
par damiette
OK, Merci beaucoup