Passa al contenuto principale

Direttive del preprocessore

Direttive del preprocessore​

Tramite le direttive del preprocessore è possibile influenzare le funzioni del compilatore del modulo Math, l'elaborazione delle variabili e l'esecuzione del codice. Le direttive del preprocessore devono trovarsi all'inizio di una riga nel testo delle formule e terminano con la prima fine riga non nascosta all'interno di un livello di parentesi. I commenti possono essere inseriti secondo le regole note.

Le direttive sono contrassegnate da un carattere # seguito da un identificatore. I parametri che seguono la direttiva e il loro formato dipendono dalla funzione. Formati possibili sono ad esempio:

#directiveA <parameter>
#directiveB <name>[<parameter>](<parameter>){<code>}
#directiveC <key>, <key>=<value>, …

Inserire testo di formule "#include"​

Con questa direttiva è possibile inserire testo di formule da una risorsa o da un file esterno. La sintassi utilizzata determina quale sorgente viene indirizzata.

#include "aRessource"
#include 'aRessource'
#include <aFile>

La risorsa indicata come stringa viene acquisita nel codice sorgente tenendo conto dei decoder ivi specificati oppure come testo.

Il file indicato in <…> viene acquisito nel codice sorgente. Sono ammessi percorsi assoluti e relativi, dove i percorsi relativi vengono cercati a partire da directory definite in modo fisso (percorsi di ricerca). Gli elementi in %...% vengono sostituiti dal valore corrispondente della variabile d'ambiente.

Percorsi di ricerca in WINDOWS:​

  • %USERPROFILE%/mm_lib/

  • %LOCALAPPDATA%/optimeas.osg.com/mm_lib/

  • %APPDATA%/optimeas.osg.com/mm_lib/

Percorsi di ricerca in LINUX/YOCTO:​

  • /sdi/config/mm_lib/

  • /sdi/apps/smartcore/mm_lib/

  • /var/lib/mm_lib/

  • /usr/local/lib/mm_lib/

  • /usr/lib/mm_lib/

Rimuovere il riferimento temporale "#timeless"​

Per eliminare il riferimento temporale di determinati canali di ingresso per il modulo Math è possibile utilizzare la direttiva #timeless. I nomi dei canali possono essere passati alla direttiva in un elenco con la virgola come separatore. Se i nomi contengono caratteri diversi da quelli ammessi per un identificatore, devono essere racchiusi tra '...' o "...". L'uso della sintassi $'...' non è ammesso, poiché qui viene impostato solo un attributo del canale.

#timeless <varName>, <varName2>, ...
note

La stessa funzione viene attivata o disattivata tramite la macro #property con la proprietà timeout=<bool>.

note

Una funzionalità analoga è messa a disposizione dalla funzione value() per un utilizzo mirato e locale nel testo delle formule.

Fondamenti: elaborazione dei dati corretta nel tempo e timeout​

Come descritto nell'introduzione, il modulo Math elabora i dati provenienti dalle diverse sorgenti dello smartCORE sempre in modo corretto nel tempo. In questo modo si garantisce che, ad es., un segnale di corrente e uno di tensione vengano correlati in modo coerente tra loro per il calcolo di una potenza.

Esistono tuttavia anche sorgenti di dati che forniscono nuovi valori solo molto raramente. Può trattarsi ad es. di dati di misura di una stazione meteorologica, interrogata magari solo ogni 10 minuti e scritta nei canali smartCORE, oppure di dati di un orario che viene interrogato e aggiornato da un server una sola volta al giorno.

I dati che vengono passati dallo smartCORE al modulo Math, dopo un intervallo di tempo impostabile vanno in timeout e vengono poi utilizzati ulteriormente con questo stesso scostamento temporale e con l'ultimo valore disponibile, sebbene la validità non sia confermata da misure o interrogazioni più recenti. Ne consegue che tutti i calcoli che ne dipendono vengono sì eseguiti sempre in modo corretto nel tempo, ma con un ritardo pari a questo intervallo.

L'intervallo di timeout è definito dal parametro globale inputTimeoutS e può essere sovrascritto individualmente per un canale con la macro #property e la proprietà timeout.

Questo ritardo può avere effetti sfavorevoli nella rappresentazione dei dati MQTT nel cloud o anche per compiti di controllo.

Con le funzioni

è possibile interrogare i diversi stati di una variabile di ingresso. Nel caso in cui non sia stato possibile collegare alcun canale smartCORE o questo canale non fornisca ancora dati, viene assegnato un valore default, impostabile tramite la macro #property <channel>, default=<var>.

Qual è l'effetto dell'attributo timeless?​

I canali di ingresso contrassegnati come timeless sono sempre validi dall'inizio alla fine del rispettivo intervallo di calcolo evaluationTimeMs, riferito al rispettivo tempo di sistema.

Schema timeless

Nell'esempio mostrato il calcolo del set di formule viene eseguito agli istanti t0,t_0, t1t_1 e t2t_2. Fino all'istante t0t_0 sul canale era stato impostato solo il valore y0y_0. Fino all'istante t1t_1 la sorgente del segnale fornisce i punti dati y1,y_1, y2y_2 e y3y_3. I punti dati y4y_4 e y5y_5 vengono prodotti solo fino all'istante t2t_2, sebbene il loro timestamp sia ancora precedente a t1t_1.

Per l'inizio dell'intervallo viene sempre utilizzato il record di dati del canale immediatamente precedente, indipendentemente da quanto sia vecchio. Per l'intervallo ]t0,t1]]t_0,t_1] quindi il punto dati y1,y_1, per l'intervallo ]t1,t2]]t_1,t_2] il punto dati y5y_5.

Se nuovi valori di dati ricadono casualmente nell'intervallo di calcolo corrente e vi sono già registrati in tempo utile, vengono presi in considerazione con i loro istanti. Per l'intervallo ]t0,t1]]t_0,t_1] si tratta dei punti dati y2y_2 e y3y_3.

La validità del record di dati più recente disponibile (qui y3y_3) viene prolungata automaticamente fino alla fine dell'intervallo (qui t1t_1), in modo che questo canale non possa in definitiva bloccare i calcoli che ne dipendono.

warning

Il prezzo da pagare è che eventuali brevi variazioni del segnale che ricadono in questo intervallo di validità prolungato non confluiscono più nei calcoli. Nell'esempio il punto dati y4y_4 viene "tralasciato", poiché si trova in un intervallo di tempo già completato dall'automatismo. Partendo dal presupposto che questi canali forniscano dati solo raramente, ciò non dovrebbe costituire un problema.

Impostare le proprietà di una variabile "#property" 1​

Con questa direttiva del preprocessore è possibile impostare proprietà e meta-informazioni di una variabile di ingresso o di uscita.

#property <channel>, <key>=<value>, ...
ArgomentoTipoDescrizione
channel<str>Il nome del canale deve essere indicato come primo argomento. Se contiene caratteri speciali come spazi o virgole, deve essere racchiuso tra virgolette. L'uso della sintassi $'...' non è ammesso, poiché qui vengono impostate solo proprietà del canale.
key<str>Il nome della proprietà, vedere la tabella seguente
value<var>Il nuovo valore della proprietà (Variant)

La tabella seguente è un elenco delle proprietà possibili e ammesse e dei loro valori:

ProprietàTipoDescrizione
default<var>Il valore default che viene assegnato a una variabile fino all'arrivo dei primi valori di dati dal canale smartCORE. In questo modo è possibile reagire nel modulo Math a flussi di dati che si avviano in ritardo.
timeout<dbl>Valore di timeout individuale per questo canale, sovrascrive inputTimeoutS
timeless<bool>Attiva o disattiva la funzione timeless per questo canale. Corrisponde alla macro #timeless

Impostare un fuso orario locale "#timezone" 2​

Con questa macro è possibile impostare un fuso orario locale per funzioni selezionate di data e ora.

#timezone <tzIdentifier>
tzIdentifierAbbreviazioni del fuso orarioCodici paese
Europe/Berlin
Europe/Stockholm
Europe/Oslo
Europe/Copenhagen
CET / CESTDE, DK, NO, SE, SJ
Europe/Brussels
Europe/Amsterdam
Europe/Luxembourg
CET / CESTBE, LU, NL
Europe/Paris
Europe/Vienna
Europe/Warsaw
Europe/Zurich
Europe/Rome
CET / CESTFR, MC, AT, PL, CH, IT
Europe/Kiev
Europe/Kyiv
EET / EESTUA
Asia/Singapore
Asia/Kuala_Lumpur
+08:00MY
...

Un elenco dei fusi orari è consultabile su Wikipedia.

In background viene utilizzata la libreria usuale in Linux HowardHinnant/date: A date and time library based on the C++11/14/17 <chrono> header , che si basa sul database dei fusi orari IANA. Questo viene distribuito sui sistemi con lo stato aggiornato nella distribuzione Yocto.

Un estratto di esso viene distribuito insieme al software optiCONTROL, poiché la libreria matematica è integrata anche lì nell'editor per il modulo Math.

Definizione di funzioni "#define"​

Under Construction Questa funzione è in preparazione.

#define <newFunction>(<argsList>)[<options>]{<code>}

Informazioni di debug "#dump"​

warning

For Debugging Only Questa direttiva del preprocessore è prevista esclusivamente per diagnosi e sviluppo. Produce moltissime uscite informative nel file di log dello smartCORE e dovrebbe quindi essere utilizzata solo per brevi periodi.

Il parametro della direttiva #dump è un elenco di key o key-value separati da virgole e agisce sul testo delle formule successivo:

#dump <key>, <key>=<value>, ...
KeyValueDescrizione
treeEmette l'albero degli oggetti tradotto. Per l'interpretazione vedere sotto.
node<uint>Aggiunge un determinato nodo oggetto per il monitoraggio continuo (3, 4).
var<str>Aggiunge un'espressione regex per la selezione di nomi di canale i cui accessi devono essere registrati (3)
trace<enum>attiva l'uscita del flusso di dati per
- in ingressi,
- out uscite o
- io entrambe le direzioni dei dati.
clearCancella tutte le impostazioni di dump per la sezione di codice successiva.

Esempi:

#dump tree
#dump node=5, node=9
#dump var='Temp.*', trace=out

Uscita dell'albero degli oggetti​

L'uscita dell'albero degli oggetti tramite #dump tree fornisce informazioni dettagliate sulle relazioni funzionali del set di formule definito. L'analisi è riservata a collaboratori esperti di optiMEAS.

+---o [0]: sequencer, bareImpl, op: ';' listOfArgs
> out: nullptr
+---o [1]: operatorNode, followInputs, op: '=' orderR2L
| > out: { n:'duration', s:[upLnk, wrVar], *rd[0], *wr[1], h:'=', empty}
| +---o [2]: operatorNode, followInputs, op: '*' orderL2R
| | > out: { n:'', s:[upLnk], *rd[1], *wr[2], h:'*', empty}
| | +---o [3]: varPoolSource, followInputs
| | | > var: { n:'wv2', s:[rdVar], *rd[3], empty}
| | | > out: { n:'', s:[upLnk], *rd[2], *wr[3], empty}
| | +---o [4]: constValueNode, constValue
| | | > out: { n:'', s:[upLnk, const], *rd[2], *wr[4], [1]={t: INF, d: TrustedTimestamp }, [0]={t: 0, d: (cScalar, cInt) 59}}}

Le uscite di trace per un elemento di collegamento del flusso di dati (out: o var:, canale o TS_Stream) hanno la seguente struttura compatta:

{ n:'duration', s:[upLnk, wrVar], *rd[0], *wr[1], h:'=', [9]={t: 48, d: (cScalar, cDbl) 54.978065}, ... [0]={t: 20, d: (cScalar, cDbl) 0.000000}}}

Al suo interno significano:

SiglaFlagDescrizione
n:'...'il nome del canale, se si tratta di una variabile
s:[]Flag di stato del canale
upLnkUp-Link, collegamento da un nodo figlio al nodo padre
rdVarRead Variable, variabile di ingresso, messa a disposizione dallo smartCORE e solo letta
wrVarWrite Variable, variabile di uscita, può essere restituita allo smartCORE
inzInitializer, ha un nodo di inizializzazione
constConstant value, il valore non cambia durante l'esecuzione.
discrDiscrete evaluation, questo canale viene calcolato a passi di campionamento discreti
ev@0Evaluate at Start, il canale discreto è stato inizializzato
evDTEvaluate Delta-T, per il canale discreto è stato calcolato un passo di campionamento
explExplicit name, la variabile è stata definita con la sintassi $'…' e deve esistere nello smartCORE
fldEField-Element, il canale alimenta un determinato campo dati in una struttura multidimensionale (vettore, matrice, …)
privPrivate, una variabile creata da un blocco funzionale e utilizzata esclusivamente da questo
propSulla variabile sono state impostate ulteriori proprietà con #property.
noTnoTime, questo canale è stato contrassegnato come #timeless ed è sempre valido fino alla fine dell'intervallo di calcolo.
+=dTIl canale ha uno scostamento temporale costante da shiftT()
nRecNoRecursion, questa variabile non deve essere utilizzata in un ciclo di ricorsione.
toValProprietà timeout assegnata
fdVal Proprietà default assegnata
noChQuesto canale non ha potuto essere collegato come ingresso a un canale smartCORE. => Default assegnato come valore costante. Vedere anche isConnected()
TOutTimeout per i dati di ingresso, se il canale è ancora vuoto (noD) o non è stato contrassegnato come #timeless. Vedere anche isTimeout()
H1Interpolazione lineare esplicitamente ammessa (1st-order hold)
:=fdIl valore default è stato scritto nel canale, vedere anche #property <channel>, default=<var>
*rd[]Gli indici dei nodi oggetto che accedono al canale in lettura
*wr[]L'indice del nodo oggetto che accede al canale in scrittura
*@0[]L'indice del nodo oggetto che esegue l'inizializzazione del canale discreto.
h:'...'Indicazione della funzione del nodo di scrittura, ad es. '*' o 'sin(…)'
[n]={}il campione memorizzato alla posizione più recente n (corrisponde al numero di voci - 1) con...
t:Timestamp in ns dal 01.01.1970, INF (infinito) o NAV (non valido)
d:Valore dei dati con valore (struttura, tipo) o TrustedTimestamp, cioè il valore precedente mantiene la sua validità fino a questo istante. L'istante può crescere in modo monotono a ogni intervallo di calcolo.
[0]={}il campione memorizzato alla posizione più vecchia (opzionale)

Seguire l'esecuzione del calcolo "#monitor"​

For Debugging Only ATTENZIONE! Questa direttiva del preprocessore è prevista esclusivamente per diagnosi e sviluppo. Produce moltissime uscite informative nel file di log dello smartCORE e dovrebbe quindi essere utilizzata solo per brevi periodi.

Monitoraggio dei buffer interni "#warn"​

For Debugging Only ATTENZIONE! Questa direttiva del preprocessore è prevista esclusivamente per diagnosi e sviluppo. Produce moltissime uscite informative nel file di log dello smartCORE e dovrebbe quindi essere utilizzata solo per brevi periodi. Inoltre questa opzione genera un carico CPU aggiuntivo e deve essere applicata solo temporaneamente e sotto osservazione !!!

Il parametro della direttiva #warn è un elenco di key o key-value separati da virgole e agisce sul testo delle formule successivo:

KeyValueDescrizione
maxbuflen<uint>Monitora il numero massimo di record di dati in una coda di dati. Viene emesso un avviso quando il valore limite viene superato. Il limite viene innalzato del 25% di maxbuflen per il messaggio successivo.
timeout<dbl>Monitora l'intervallo di tempo tra il primo campione di dati e il tempo di esecuzione. Viene emesso un avviso quando questo tempo è maggiore del valore impostato in s.
clearCancella tutte le impostazioni di avviso per la sezione di codice successiva.

Esempi:

#warn maxBufLen=10, timeout=1000
// Formeltext zur Überwachung
#warn clear

Footnotes​

  1. Disponibile a partire dalla versione di catalogo 10. ↩

  2. Disponibile a partire dalla versione di catalogo 13. ↩

  3. L'opzione può essere indicata più volte. ↩ ↩2

  4. Numeri di nodo dall'albero degli oggetti ↩