Vai al contenuto
PLC Forum


Calcolo media temporale e Array


pegu

Messaggi consigliati

Buongiorno,

devo calcolare la media di un segnale analogico su un periodo di 5 secondi.

Dopo aver visitato il forum e aver trovato diversi esempi ( come questo) ho capito che la strategia è riempire un array (con i quali purtroppo non ho dimestichezza in TIA Portal) e quando l'array è pieno fare la somma edividere per la dimensione dell'array.

Ho provato a mettere in pratica quanto descritto (in KOP e nell'ultima versione in SCL) ma purtroppo continuo ad imbattermi nelle stesse problematiche legate al funzionamento del PLC: in particolare non riesco a riempire l'array ed aumentare il contatore che è responsabile di puntare gli elementi dell'array.

Sono abituato ad altri linguaggi di programmazione (C, C++) e faccio fatica a capire come riempire l'array in questo ambiente.

Vi lascio le schermate dell'ultima versione (noterete che è fermo al contatore=1)

 

TIA_media1.jpg

TIA_media2.jpg

TIA_media3.jpg

Link al commento
Condividi su altri siti


Mattia Spoldi

il problema nasce dal fatto che stai usando una FC, le variabili che dichiari nella sezione temp, vengono reinizializzate ad ogni scansione, perdendo il loro valore.

Riscrivi il blocco usando un FB e sposta le variabili che adesso sono in area temp nell'area stat.

Link al commento
Condividi su altri siti

Grazie mille per l'input, ho riscitto il programma in un blocco FB e l'ho rielaborato parecchio, adesso funziona. Lascio qualche screeshot per aiutare chi ha un compito simile e per chi ha qualche consiglio su come migliorarlo.

TIA_media2_2.jpg

TIA_media3_21.jpg

TIA_media3_22.jpg

TIA_media3_23.jpg

Link al commento
Condividi su altri siti

Piccole cose.
#Campiona è una variabile booleana. Non serve scrivere IF #Campiona = 1 THEN, basta scrivere IF #Campiona THEN (come in C).

 

Per fare incrementi, al posto di k := k + 1; si puiò scrivere k += 1; (come in C) .
Anche per la somma potersti scrivere: Somma += Valori[i];

 

Poi, abitudine mia personale: preferisco moltiplicare per 10 piuttosto che dividere per 0.1

Link al commento
Condividi su altri siti

11 ore fa, batta scrisse:

Poi, abitudine mia personale: preferisco moltiplicare per 10 piuttosto che dividere per 0.1

 

E corretto anche perchè le moltiplicazioni sono eseguite sempre in un tempo minore delle divisioni.

Link al commento
Condividi su altri siti

2 ore fa, Livio Orsini scrisse:

E corretto anche perchè le moltiplicazioni sono eseguite sempre in un tempo minore delle divisioni.

E' il motivo all'origine di questa mia abitudine: la divisione, tra le quattro operazioni base, è la più pesante.

Con le prestazioni delle cpu attuali non è molto importante, ma la considero comunque una buona abitudine.

Link al commento
Condividi su altri siti

Tutte le operazioni inverse sono più gravose di quelle dirette.

E vero che con l'attuale velocità di elaborazione delle CPU il tempo maggiore di una divisione, rispetto ad una moltiplicazione, non è sigificativo; però giustamente che lavora da parcchi anni è abituato a tener conto anche di quello che oggi non è più così rilevante.

Qualche decennio fa anche assegnare al moltiplicando il dato di valore maggiore, rispetto al valore del moltoplicatore, favoriva la riduzione del tempo di elaborazione.

Link al commento
Condividi su altri siti

1 ora fa, Livio Orsini scrisse:

che lavora da parcchi anni è abituato a tener conto anche di quello che oggi non è più così rilevante.

Già, ora non ci si bada più, mentre una volta era importante.
Per lo stesso motivo, se si dovevano fare moltiplicazioni o divisioni, con interi, per potenze di due, si preferifa fare shift a sinistra o a destra. Tutti piccoli accorgimenti che solo chi ha una certa età ha assimilato.
Devo comunque ammettere che io stesso non mi curo più di tanto di alleggerire il compito della attuali cpu.
Per esempio, un tempo era d'obbligo lavorare in virgola mobile solo nei casi strettamente necessari. Si cercava il più possibile di lavorare sempre con interi, moltiplicando opportunamente i valori per mantenere la precisione necessaria. Ora faccio larghissimo uso di Real e, in qualche caso, anche di LReal.

Link al commento
Condividi su altri siti

58 minuti fa, batta scrisse:

Per esempio, un tempo era d'obbligo lavorare in virgola mobile solo nei casi strettamente necessari. Si cercava il più possibile di lavorare sempre con interi, moltiplicando opportunamente i valori per mantenere la precisione necessaria. Ora faccio larghissimo uso di Real e, in qualche caso, anche di LReal.

come non condividere, quella dello shift non la ricordavo davvero ma quella degli interi è stata un abitudine dura a morire, oggigiorno merita molto di più passare al Real senza troppe fisime mentali, così si standardizza sia l'indirizzamento che la metodologia di calcolo, addirittura un tempo si economizzava sull'uso degli interi e dei doppi interi, e va beh n'è passato dl tempo...

Link al commento
Condividi su altri siti

16 ore fa, leleviola scrisse:

e va beh n'è passato dl tempo...

 

E l'evoluzione .... della spece programmatore🙂.

Link al commento
Condividi su altri siti

  • 8 months later...

riguardo i numeri real bisogna fare attenzione al risultato nei calcoli

sempre meglio usare interi o passare real in interi e poi in real

quando serve moltiplicando e dividendo opportunamente in modo da sopprimere decimali non voluti

i risultati sui confronti tra real non danno sempre il risultato aspettato

Link al commento
Condividi su altri siti

FUNCTION_BLOCK "Media_AP"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      "Var_Input" { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      Media_Type { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;   // 0=aritmetica 1=ponderata
      N_Stack { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;   // min 4 max 64
   END_VAR

   VAR_OUTPUT
      "Var_Output" { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
   END_VAR

   VAR
      Stack { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Array[0..63] of Int;
   END_VAR

   VAR_TEMP
      i : Int;
      Somma : DInt;
      Media_A : Real;
      Media_P : Real;
      Varianza : Array[0..63] of Real;
      Sum_Varianza : Real;
      Varianza_Tot : Real;
      Variante : Array[0..63] of Real;
      Peso : Array[0..63] of Real;
      Sum_Variante : Real;
      Sum_Peso : Real;
   END_VAR


BEGIN
    IF (#Media_Type = 0 OR #Media_Type = 1) AND #N_Stack >= 4 AND #N_Stack <= 64 THEN
        
        #Somma := 0;
        
        FOR #i := #N_Stack - 1 TO 1 BY -1 DO
            #Stack[#i] := #Stack[#i - 1];
        END_FOR;
        
        #Stack[0] := #Var_Input;
        
        FOR #i := 0 TO #N_Stack - 1 DO
            #Somma := #Somma + #Stack[#i];
        END_FOR;
        
        #Media_A := DINT_TO_REAL(#Somma) / INT_TO_REAL(#N_Stack);
        
        IF #Media_Type = 1 THEN
            
            #Sum_Varianza := 0.0;
            #Sum_Variante := 0.0;
            #Sum_Peso := 0.0;
            
            FOR #i := 0 TO #N_Stack - 1 DO
                #Varianza [#i] := SQR(#Media_A - #Stack[#i]);
                #Sum_Varianza += #Varianza[#i];
            END_FOR;
            
            #Varianza_Tot := #Sum_Varianza / INT_TO_REAL( #N_Stack - 1);
            
            FOR #i := 0 TO #N_Stack - 1 DO
                IF #Varianza[#i] <> 0.0 THEN
                    #Variante[#i] := #Varianza_Tot / #Varianza[#i] / 2;
                ELSE;
                    #Variante[#i] := #Stack[#i];
                END_IF;
                #Sum_Variante += #Variante[#i];
            END_FOR;
            
            FOR #i := 0 TO #N_Stack - 1 DO
                #Peso[#i] := #Stack[#i] * #Variante[#i];
                #Sum_Peso += #Peso[#i];
            END_FOR;
        
            #Media_P := #Sum_Peso / #Sum_Variante;
            
        END_IF;
        
        CASE #Media_Type OF
            0:  #Var_Output := ROUND(#Media_A)
                ;
            1:  #Var_Output := ROUND(#Media_P)
                ;
        END_CASE;
        
    ELSE
        #Var_Output := #Var_Input;
    END_IF;
 
        
END_FUNCTION_BLOCK

 

Link al commento
Condividi su altri siti

  • Livio Orsini locked this discussione
Ospite
Questa discussione è chiusa alle risposte.
×
×
  • Crea nuovo/a...