Jump to content
PLC Forum


85paolo

Mediana con step7

Recommended Posts

85paolo

Buonasera a tutti, esiste un FC o un modo per trovare la mediana di diversi valori?

Nel caso contrario è possibile mettere in ordine crescente dei valori?

Grazie

Edited by 85paolo
Link to post
Share on other sites

85paolo

Scusate specifico Siemens 300, vorrei evitare di farlo in SCL.

Link to post
Share on other sites
ken

Dai una guardata. È un lavoro che aveva fatto Batta tempo fa.

Link to post
Share on other sites
85paolo
7 minuti fa, ken ha scritto:

Dai una guardata. È un lavoro che aveva fatto Batta tempo fa.

Interessante ma a me servirebbe la mediana, non la media. O sennò mettere in ordine crescente o decrescente i valori.

Link to post
Share on other sites
drn5

Beh...se non puoi usare scl sul 300 in awl userei i puntatori. Ti fai un db1 che riempirai con i tuoi valori e alla fine con un loop ti vai cercare il valore superiore confrontandolo con l'ultimo letto e quando hai finito il primo giro hai il primo valore che metterai nella prima word del db2. Rifai da capo il loop e trovi il secondo valore....davanti cosi fino alla fine ... poi la solita recoladel n/2 o n/2+1 per la mediana....

Spiegato un po' in fretta ma questo è il "succo" della questione.

Ciao

Link to post
Share on other sites
batta
1 ora fa, drn5 ha scritto:

Beh...se non puoi usare scl sul 300 in awl userei i puntatori.

Il concetto di come fare l'ordinamento è indipendente dal linguaggio utilizzato, e sviluppare l'algoritmo di ordinamento in AWL, con i puntatori, è molto più complicato.

Non c'è una scorciatoia. Il testo strutturato, in questo caso, è il linguaggio migliore. Se non riesce a farlo in testo strutturato, dubito riesca a farlo in AWL.

 

4 ore fa, 85paolo ha scritto:

Perché non ho idea da dove iniziare, inoltre dove lavoro non viene usato.

Non viene usato perché non c'è l'abitudine ad usarlo, o vi mancano proprio le lienze per SCL?
Se è una questione di licenze, si dovrebbe discuterne col commerciale.
Se avete le licenze ma non siete abituati ad usare SCL, è ora di imparare ad usarlo.

 

Inoltre, anche se si sta usando un S7-300, perché non sviluppare il programma in TIA Portal, che ha SCL integrato con un editor infinitamente migliore dell'editor SCL del Simatic Manager?

Link to post
Share on other sites
85paolo
7 ore fa, batta ha scritto:

Il concetto di come fare l'ordinamento è indipendente dal linguaggio utilizzato, e sviluppare l'algoritmo di ordinamento in AWL, con i puntatori, è molto più complicato.

Non c'è una scorciatoia. Il testo strutturato, in questo caso, è il linguaggio migliore. Se non riesce a farlo in testo strutturato, dubito riesca a farlo in AWL.

Ho chiesto aiuto perché non sono in grado di eseguire questa funzione. Magari esisteva un FC con questo calcolo. I valori da mettere in ordine sono 28. 

Per quanto riguarda SCL non è utilizzabile perché non è uno standard nella nostra azienda. 

 

Link to post
Share on other sites
drn5

Non mi sembra che ci sia una funzione del genere in una delle librerie, ma puoi sempre cercare nella manualistica Siemens.

Ma forse tu speravi in una anima buona che ti scrivesse il codice....

Ciao

Link to post
Share on other sites
batta
58 minuti fa, 85paolo ha scritto:

Per quanto riguarda SCL non è utilizzabile perché non è uno standard nella nostra azienda. 

Male. Gli standard, come tutto il resto, si devono evolvere. Soprattutto se sono standard sbagliati, come in questo caso.
La programmazione dei plc in generale (non solo Siemens, anzi, in questo, molti sono arrivati prima di Siemens), si sta spostando sempre di più verso il testo strutturato.
Decidere di non usare il testo strutturato significa decidere di rimanere indietro.
Cerca di farlo capire ai responsabili.

 

1 ora fa, 85paolo ha scritto:

Magari esisteva un FC con questo calcolo.

Esiste per il 1200/1500, e la trovi nella libreria LGF (gratuita). Ovviamente, è sviluppata in testo strutturato.
Per il 300, non credo esista.

Link to post
Share on other sites
Livio Orsini
Il 7/7/2020 alle 19:05 , 85paolo ha scritto:

Buonasera a tutti, esiste un FC o un modo per trovare la mediana di diversi valori?

Nel caso contrario è possibile mettere in ordine crescente dei valori?

 

Anche usando AWL non è poi così difficile eseguire un media aritmetica tra un certo numero di valori, oppure fare una finestra scorrevole con media.

Un algoritmo di sorting per orinare in ordine crescente un certo numero di valori è quasi banale.

 

Perchè non dici di quanti valori si tratta e spieghi un po' meglio cosa devi fare.

 

Probabilmente usando SCL o altro linguaggio a livello più alto dell'AWL rende più veloce la stesura, però se 85paolo può usare solo l'AWL è inutile insistere a dire che con SCL si lavora meglio.

Link to post
Share on other sites
batta
45 minuti fa, Livio Orsini ha scritto:

però se 85paolo può usare solo l'AWL è inutile insistere a dire che con SCL si lavora meglio.

S\, Livio, hai ragione ma, se insisto, è perché trovo assurdo, nel 2020, non usare il testo strutturato. E trovo assurdo anche usare ancora il 300 invece del 1500. Ha senso solo se si mettono le mani su un impianto già esistente.

Sono scelte anacronistiche, scelte che fanno rimanere indietro, e che si pagheranno molto care in un futuro prossimo. Per questo insisto.

E' come se un autoriparatore si fosse fermato all'accensione con puntine e spinterogeno.

 

Oggi, se mi prende la voglia, potrei buttare giù qualcosa in AWL.

 

Link to post
Share on other sites
85paolo
1 ora fa, Livio Orsini ha scritto:

Perchè non dici di quanti valori si tratta e spieghi un po' meglio cosa devi fare.

Sono 28 valori da mettere in ordine crescente per poi fare la media con i due centrali. 

 

Se invece faccio la media con tutti i valori e ci sono dei valori all'estremità errati la media viene modificata eccessivamente. Per questo motivo ho la necessità di fare la mediana dei 28 valori.

Link to post
Share on other sites
Livio Orsini

Ti crei un array vuoto di 28 elementi.

Trasferisci il primo valore nel primo elemento dell'array.

Confronti il prossimo valore con il primo memorizzato: se è maggiore lo memorizzi nell'elemeto seguente, se è minore sposti in avanti l'elemento memorizzato ed inserisci il nuovo elemento.

Con il terzo valore, parti dal prino elemento, confornti, se è minore sposti tutti gli elementi di un passo ed inserisci il nuovo valore, seè maggiore fai il confronto con con gli altri elementi memorizzati, al primo confronto che trovi minore inserisci il nuovo valore e spsoti in avanti gli altri, se non trovi alcun elemento minore memorizzi in testa alla pila.

Ripeti il confronto sino a che sei arrivato al 28° valore.

A questo punto disponi di un vettore ordinato in ordine crescente.

Poi puoi eseguire la media ponderata o altra media che più si avvicina alle tue esigenze.

 

Questo è uno dei metodi possibili per ordinare gli elementi di un vettore in ordine crescente o decrescente.

 

Circa 50 anni fa mi toccò questo esercizio, oltre ad altri 2, nello scritto dell'esame universitario di "macchine calcolatrici".

Link to post
Share on other sites
batta

Eccomi qua. Mi ha preso la voglia di fare ancora qualcosa in AWL.

Questo è il risultato:

FUNCTION "FC_BubbleSort" : Void

VERSION : 0.1
   VAR_INPUT 
      Execute : Bool;
      BufferAdr : Pointer;
      NrElements : Int;
   END_VAR

   VAR_TEMP 
      DB_Nr : Int;
      adr_start : DInt;
      adr_i : DInt;
      adr_j : DInt;
      adr_minVal : DInt;
      i : Int;
      j : Int;
      MinVal : Int;
      i_minVal : Int;
      id_loop_i : Int;
      id_loop_j : Int;
   END_VAR


BEGIN
NETWORK
TITLE = Sort
// By Batta
// 9 luglio 2020
// Riordinamento con algoritmo Bubble Sort
// Vengono eseguiti due loop, uno interno all'altro.
// Il loop esterno punta agli elementi dal primo al penultimo.
// Il loop interno punta agli elementi dall'elemento del loop esterno
// fino all'ultimo elemento.
// Il loop interno si occupa di trovare l'indice dell'elemento contenente il valore minore.
// Una volta trovato l'indice, scambia i valori tra il primo elemento del confronto (indice j)
// e l'elemento con valore minore.
// Questo loop è richiamato all'interno di un loop che incrementa l'indice del primo elemento
// di confronto fino al penultimo elemento dell'array.
// Il numero di confronti totali sarà pari a NrElementi * (NrElementi - 1) / 2.

// Questo metodo ha come vantaggio di lavorare sugli indici, che sono variabili locali
// (quindi con accessi veloci), e riduce al minimo le scritture sugli elementi dell'array
// (con accessi più lenti).
// Come svantaggio, c'è che il numero dei confronti sarà sempre uguale, anche in caso di array già ordinato.

// Altri sistemi consentono di terminare i controlli se l'array è già ordinato, ma devono effettuare
// molte più scritture sugli elementi dell'array.

// Esistono poi algoritmi più efficienti, ma anche più comlessi da implementare.
// Se il numero di elementi da riordinare non è elevato, ritengo che questo sia un sistema valido.

// Se non c'è il comando Execute, terminare l'elaborazione del blocco.
      UN #Execute;
      BEB;

// Carica in AR1 l'indirizzo della variabile Pointer che contiene
// l'indirizzo dell'inizio dell'array da riordinare
      L P##BufferAdr;
      LAR1;
// Estrai il numero del DB dalla variabile pointer, ed apri il DB
      L W[ AR1, P#0.0];
      T #DB_Nr;
      AUF DB[ #DB_Nr];
// Estrai l'indirizzo dove inizia l'array dalla variabile pointer
      L D[ AR1, P#2.0];
      T #adr_start;

// Inizializza indice j
      L 0;
      T #j;

// LOOP j (numero di elementi -1)
      L #NrElements;
      + -1;
NX_j:      T #id_loop_j;

// Inizializza valori indici i e i_minVal
      L #j;
      T #i_minVal;
      + 1;
      T #i;

// Calcola indirizzo elemento j
      L L#16;
      L #j;
      ITD;
      *D;
      L #adr_start;
      +D;
      T #adr_j;
// Inizializza valore minimo con valore elemento j
      L DBW[ #adr_j];
      T #MinVal;

// LOOP i (numero di elementi - j -1)
      L #NrElements;
      L #j;
      -I;
      + -1;
NX_i:      T #id_loop_i;

// Calcola indirizzo elemento i
      L L#16;
      L #i;
      ITD;
      *D;
      L #adr_start;
      +D;
      T #adr_i;

// Ricerca indice elemento con valore minore
      L #MinVal;
      L DBW[ #adr_i];
      <=I;
      SPB _000;
// Trovato valore minore: aggiornare nuovo valore minimo,
// aggiornare indice valore minimo.
      T #MinVal;
      L #i;
      T #i_minVal;
_000:      NOP 0;

// incremento indice i
      L #i;
      + 1;
      T #i;

// Controlla fine loop i
      L #id_loop_i;
      LOOP NX_i;

// Terminato ciclo ricerca valore minimo da j a ultimo elemento:
// scambiare valore elementi j e i_minVal

// Copia valore elemento j in elemento i_minVal
// Calcolo indirizzo elemento i_minVal
      L L#16;
      L #i_minVal;
      ITD;
      *D;
      L #adr_start;
      +D;
      T #adr_minVal;

      L DBW[ #adr_j];
      T DBW[ #adr_minVal];

// Copia valore minimo attuale in elemento j
      L #MinVal;
      T DBW[ #adr_j];

// Incrementare j e controllare se loop j è finito
      L #j;
      + 1;
      T #j;

      L #id_loop_j;
      LOOP NX_j;

END:      NOP 0;

END_FUNCTION

Crea un nuovo sorgente, e copia tutto il codice.
Nella tabella dei simboli inserisci una FC con simbolo FC_BubbleSort.

Compila il sorgente.

Al parametro in ingresso "BufferAdr" dovrai passare l'indirizzo dell'inizio dell'array. Esempio: P#DB10.DBX200.0

Poi devi indicare quanti elementi dell'array dovrai riordinare.
Non è nemmeno importante che le variabili siano in un array, basta che siano consecutive.

La funzione è stata sviluppata per riordinare variabili di tipo INT. Se devi riordinare variabili di tipo diverso, dovrai modificare il codice.
Non ci sno controlli sulla validità dei parametri passati alla funzione.

 

Questa funzione l'ho fatta per divertimento, per vedere se ancora mi ricordo come si usa AWL. Torno però a martellare sempre sullo stesso chiodo: la stessa funzione sviluppata in testo strutturato sarebbe molto più facile sia da scrivere, che da comprendere.
Con una cpu 1200/1500 poi, potresti usare le variabili di tipo VARIANT, e scrivere una funzione che va bene per tutti i formati.
Potresti anche passare l'intero array come parametro IN/OUT, e rilevare da codice la lunghezza dell'array, senza bisogno di scrivere indirizzi e numero di elementi, riducendo le possibilità di errori.


Usare AWL perchè il vostro standard non contempla il testo strutturato, non ha senso, significa solo volersi fare del male.

Link to post
Share on other sites
batta
4 ore fa, 85paolo ha scritto:

Sono 28 valori da mettere in ordine crescente per poi fare la media con i due centrali. 

Non credo che abbia molto senso. Chi ti garantisce che i due valori centrali non siano siano sballati?

Piuttosto, fai una media scartando i campionamenti che si scostano troppo dalla media.

Link to post
Share on other sites
85paolo
4 ore fa, batta ha scritto:

Chi ti garantisce che i due valori centrali non siano siano sballati?

Interessante quello che hai detto potresti aver ragione.

 

4 ore fa, batta ha scritto:

Piuttosto, fai una media scartando i campionamenti che si scostano troppo dalla media.

Come faccio a scaricare i campionamenti che si scostano troppo prima di effettuare la media?

Link to post
Share on other sites
Livio Orsini

Durante il sorting memorizzi i 2 valori massimi ed i 2 valori minimo, li scarti e fai la media sugli altri 24.
La media è comunque un dato statistico. Togliendo 4 valori estremi ha un dato più rispondente alla realtà.

 

Perchè non ci scrivi cosa rappresentano que 28 valori e come vengono acquisiti?, magari potremmo aver qualche suggerimento da darti, basato su precedenti esperienze in merito.

Link to post
Share on other sites
85paolo

Vediamo se ho capito... Sono tutti valori reali. Quindi modifico le variabili temporanee da Int a real?

Creo un db (esempio db400 con i miei 28 real), carico P#Db400.dbd0 al posto di P##BufferAdr?

Dove dove inserisco gli elementi Array da riordinare?

 

Con mia Array che parte da db400.dbd0 e arriva a db400.dbd112...

Edited by Livio Orsini
Tolto messaggio quotato
Link to post
Share on other sites
batta
55 minuti fa, 85paolo ha scritto:

Vediamo se ho capito... Sono tutti valori reali. Quindi modifico le variabili temporanee da Int a real?

No.
L'unica variabile locale che dovrai cambiare da INT a REAL è MinVal.
Poi devi modificare dove c'è l'accesso alle variabili del DB, tipo DBW [adr____] e scrivere DBD al posto di DBW. Poi, dove vengono calcolati gli indirizzi moltiplicando x16, dovrai moltiplicare x32.

Per finire, dove c'è la comparazione per cercare il valore minore, al posto di "<=I" dovrai mettere "<=R".

Provo a correggere il sorgente. Se non ho saltato qualcosa, ora funziona con variabili di tipo REAL.

FUNCTION "FC_BubbleSort" : Void

VERSION : 0.1
   VAR_INPUT 
      Execute : Bool;
      BufferAdr : Pointer;
      NrElements : Int;
   END_VAR

   VAR_TEMP 
      DB_Nr : Int;
      adr_start : DInt;
      adr_i : DInt;
      adr_j : DInt;
      adr_minVal : DInt;
      i : Int;
      j : Int;
      MinVal : Real;
      i_minVal : Int;
      id_loop_i : Int;
      id_loop_j : Int;
   END_VAR


BEGIN
NETWORK
TITLE = Sort
// By Batta
// 9 luglio 2020
// Riordinamento con algoritmo Bubble Sort
// Vengono eseguiti due loop, uno interno all'altro.
// Il loop esterno punta agli elementi dal primo al penultimo.
// Il loop interno punta agli elementi dall'elemento del loop esterno
// fino all'ultimo elemento.
// Il loop interno si occupa di trovare l'indice dell'elemento contenente il valore minore.
// Una volta trovato l'indice, scambia i valori tra il primo elemento del confronto (indice j)
// e l'elemento con valore minore.
// Questo loop è richiamato all'interno di un loop che incrementa l'indice del primo elemento
// di confronto fino al penultimo elemento dell'array.
// Il numero di confronti totali sarà pari a NrElementi * (NrElementi - 1) / 2.

// Questo metodo ha come vantaggio di lavorare sugli indici, che sono variabili locali
// (quindi con accessi veloci), e riduce al minimo le scritture sugli elementi dell'array
// (con accessi più lenti).
// Come svantaggio, c'è che il numero dei confronti sarà sempre uguale, anche in caso di array già ordinato.

// Altri sistemi consentono di terminare i controlli se l'array è già ordinato, ma devono effettuare
// molte più scritture sugli elementi dell'array.

// Esistono poi algoritmi più efficienti, ma anche più comlessi da implementare.
// Se il numero di elementi da riordinare non è elevato, ritengo che questo sia un sistema valido.

// Se non c'è il comando Execute, terminare l'elaborazione del blocco.
      UN #Execute;
      BEB;

// Carica in AR1 l'indirizzo della variabile Pointer che contiene
// l'indirizzo dell'inizio dell'array da riordinare
      L P##BufferAdr;
      LAR1;
// Estrai il numero del DB dalla variabile pointer, ed apri il DB
      L W[ AR1, P#0.0];
      T #DB_Nr;
      AUF DB[ #DB_Nr];
// Estrai l'indirizzo dove inizia l'array dalla variabile pointer
      L D[ AR1, P#2.0];
      T #adr_start;

// Inizializza indice j
      L 0;
      T #j;

// LOOP j (numero di elementi -1)
      L #NrElements;
      + -1;
NX_j:      T #id_loop_j;

// Inizializza valori indici i e i_minVal
      L #j;
      T #i_minVal;
      + 1;
      T #i;

// Calcola indirizzo elemento j
      L L#32;
      L #j;
      ITD;
      *D;
      L #adr_start;
      +D;
      T #adr_j;
// Inizializza valore minimo con valore elemento j
      L DBD[ #adr_j];
      T #MinVal;

// LOOP i (numero di elementi - j -1)
      L #NrElements;
      L #j;
      -I;
      + -1;
NX_i:      T #id_loop_i;

// Calcola indirizzo elemento i
      L L#32;
      L #i;
      ITD;
      *D;
      L #adr_start;
      +D;
      T #adr_i;

// Ricerca indice elemento con valore minore
      L #MinVal;
      L DBD[ #adr_i];
      <=R;
      SPB _000;
// Trovato valore minore: aggiornare nuovo valore minimo,
// aggiornare indice valore minimo.
      T #MinVal;
      L #i;
      T #i_minVal;
_000:      NOP 0;

// incremento indice i
      L #i;
      + 1;
      T #i;

// Controlla fine loop i
      L #id_loop_i;
      LOOP NX_i;

// Terminato ciclo ricerca valore minimo da j a ultimo elemento:
// scambiare valore elementi j e i_minVal

// Copia valore elemento j in elemento i_minVal
// Calcolo indirizzo elemento i_minVal
      L L#32;
      L #i_minVal;
      ITD;
      *D;
      L #adr_start;
      +D;
      T #adr_minVal;

      L DBD[ #adr_j];
      T DBD[ #adr_minVal];

// Copia valore minimo attuale in elemento j
      L #MinVal;
      T DBD[ #adr_j];

// Incrementare j e controllare se loop j è finito
      L #j;
      + 1;
      T #j;

      L #id_loop_j;
      LOOP NX_j;

END:      NOP 0;

END_FUNCTION

 

Link to post
Share on other sites
batta
1 ora fa, 85paolo ha scritto:

Con mia Array che parte da db400.dbd0 e arriva a db400.dbd112...

Una volta fatte le modifiche di cui sopra, come parametri alla funzione dovrai passare:
BufferAdr = P#DB400.DBX0.0

NrElements = 28

 

Mi sa che mi devi una birra virtuale da 1 litro.
Bella fresca, mi raccomando. Possibilmente non filtrata. ;-)

Link to post
Share on other sites
Yiogo

tanti anni fa usavo IL, ma usarlo ancora nel 2020 mi sembra del tutto anacronistico

l'ho abbandonato molto prima e gli ultimi anni uso sempre più ST

Link to post
Share on other sites
85paolo
2 ore fa, batta ha scritto:

Una volta fatte le modifiche di cui sopra, come parametri alla funzione dovrai passare:
BufferAdr = P#DB400.DBX0.0

NrElements = 28

 

Mi sa che mi devi una birra virtuale da 1 litro.
Bella fresca, mi raccomando. Possibilmente non filtrata. 😉

Grazie mille!!!

Link to post
Share on other sites
85paolo
4 ore fa, Livio Orsini ha scritto:

Durante il sorting memorizzi i 2 valori massimi ed i 2 valori minimo, li scarti e fai la media sugli altri 24.
La media è comunque un dato statistico. Togliendo 4 valori estremi ha un dato più rispondente alla realtà.

 

Perchè non ci scrivi cosa rappresentano que 28 valori e come vengono acquisiti?, magari potremmo aver qualche suggerimento da darti, basato su precedenti esperienze in merito.

Sono 28 raggi di una circonferenza non perfetta presi da una foto. Con disturbi vari dati da parti di materiale di scarto dopo la lavorazione. Quindi non posso fare una media da usare come filtro, da lì parte l'idea prendere il valore a metà...

Link to post
Share on other sites
Guest
This topic is now closed to further replies.

×
×
  • Create New...