Directivas del preprocesador
Directivas del preprocesador
Mediante las directivas del preprocesador se pueden influir en las funciones del compilador del módulo Math, en el procesamiento de las variables y en la ejecución del código. Las directivas del preprocesador deben estar al principio de una línea en el texto de las fórmulas y terminan con el primer final de línea que no esté oculto dentro de un nivel de paréntesis. Los comentarios pueden insertarse según las reglas conocidas.
Las directivas se identifican mediante un carácter # seguido de un identificador. Los parámetros que siguen a la directiva y su formato dependen de la función. Algunos formatos posibles son, por ejemplo:
#directiveA <parameter>
#directiveB <name>[<parameter>](<parameter>){<code>}
#directiveC <key>, <key>=<value>, …
Insertar texto de fórmulas "#include"
Con esta directiva se puede insertar texto de fórmulas procedente de un recurso o de un archivo externo. La sintaxis utilizada determina qué fuente se direcciona.
#include "aRessource"
#include 'aRessource'
#include <aFile>
El recurso indicado como cadena se incorpora al código fuente como texto, teniendo en cuenta los decoder especificados en él.
El archivo indicado entre <…> se incorpora al código fuente. Se permiten rutas absolutas y relativas; las rutas relativas se buscan a partir de directorios determinados de forma fija (rutas de búsqueda).
Los elementos entre %...% se sustituyen por el valor correspondiente de la variable de entorno.
Rutas de búsqueda en WINDOWS:
-
%USERPROFILE%/mm_lib/ -
%LOCALAPPDATA%/optimeas.osg.com/mm_lib/ -
%APPDATA%/optimeas.osg.com/mm_lib/
Rutas de búsqueda en LINUX/YOCTO:
-
/sdi/config/mm_lib/ -
/sdi/apps/smartcore/mm_lib/ -
/var/lib/mm_lib/ -
/usr/local/lib/mm_lib/ -
/usr/lib/mm_lib/
Eliminar la referencia temporal "#timeless"
Para disolver la referencia temporal de determinados canales de entrada del módulo Math, puede utilizarse la directiva #timeless. Los nombres de canal pueden pasarse a la directiva en una lista con una coma como separador. Si los nombres contienen caracteres distintos de los permitidos para un identificador, deben ir entre '...' o "...". No se permite el uso de la sintaxis $'...', ya que aquí solo se establece un atributo del canal.
#timeless <varName>, <varName2>, ...
La misma función se activa o desactiva mediante la macro #property con la propiedad timeless=<bool>.
Una funcionalidad similar se proporciona mediante la función value() para un uso selectivo y local en el texto de las fórmulas.
Fundamento: procesamiento de datos con corrección temporal y timeout
Como se describe en la introducción, el módulo Math procesa siempre los datos de las distintas fuentes de smartCORE con corrección temporal. Con ello se garantiza que, por ejemplo, una señal de corriente y una de tensión se correlacionen entre sí de forma coherente para calcular una potencia.
Sin embargo, también hay fuentes de datos que proporcionan nuevos valores muy raramente. Pueden ser, por ejemplo, datos de medición de una estación meteorológica que quizá solo se consultan cada 10 minutos y se escriben en los canales de smartCORE, o datos de un horario que solo se consultan y actualizan una vez al día desde un servidor.
Los datos que smartCORE transfiere al módulo Math entran en timeout transcurrido un intervalo de tiempo configurable y se siguen utilizando entonces con ese mismo desfase temporal y con el último valor pendiente, aunque la validez no esté confirmada por mediciones o consultas más recientes. Como consecuencia, todos los cálculos que dependen de ellos se siguen ejecutando con corrección temporal, pero con un retraso de ese lapso de tiempo.
El intervalo de tiempo del timeout se define mediante el parámetro global inputTimeoutS y puede sobrescribirse individualmente para un canal con la macro #property y la propiedad timeout.
Este retraso puede tener efectos desfavorables en la representación de los datos MQTT en la nube o también en tareas de control.
Si un cálculo va retrasado respecto a la hora actual más de lo que explican su propio retraso y dos veces el intervalo de tiempo del timeout, el módulo Math lo notifica una vez como WARNING, p. ej. 'y', node 3 find(...): calculation lags 130.0 s behind (limit 120.0 s), backlog builds up. Se nombra la variable y la función en la que se origina el retraso, no los cálculos que dependen de ellas. Si el cálculo se pone al día, sigue calculation has caught up como INFO. Las funciones que retrasan su resultado por diseño, como shiftT() con desplazamiento negativo o find() hasta T_age, tienen en cuenta su propio retraso.
Con las funciones
se pueden consultar los distintos estados de una variable de entrada. En el caso de que no se haya podido conectar ningún canal de smartCORE o de que este canal todavía no proporcione datos, se asigna un valor default, que puede establecerse mediante la macro #property <channel>, default=<var>.
¿Qué efecto tiene el atributo timeless?
Los canales de entrada marcados como timeless son siempre válidos desde el principio hasta el final del respectivo intervalo de cálculo evaluationTimeMs, referido a la hora del sistema correspondiente.
En el ejemplo mostrado, el cálculo del conjunto de fórmulas se ejecuta en los instantes y . Hasta el instante solo se había establecido el valor en el canal. Hasta el instante la fuente de señal proporciona los puntos de datos e . Los puntos de datos e no se producen hasta el instante , aunque su marca de tiempo es anterior a .
Para el comienzo del intervalo se utiliza siempre el registro del canal situado inmediatamente antes, sin importar su antigüedad. Para el intervalo es, por tanto, el punto de datos y para el intervalo el punto de datos .
Si nuevos valores de datos caen casualmente en el intervalo de cálculo actual y ya están registrados allí a tiempo, se tienen en cuenta con sus instantes. Para el intervalo son los puntos de datos e .
La validez del registro más reciente disponible (aquí ) se prolonga automáticamente hasta el final del intervalo (aquí ), de modo que este canal no puede, en definitiva, retener ningún cálculo que dependa de él.
El precio es que posibles cambios breves de señal que se sitúen en este intervalo de validez prolongado ya no se incorporen a los cálculos. En el ejemplo, el punto de datos se «pasa por alto», ya que se encuentra en un intervalo de tiempo que ya ha sido completado por el automatismo. Partiendo de la suposición y la condición de que estos canales solo proporcionan datos raramente, esto no debería suponer un problema.
Establecer propiedades de una variable "#property" 1
Con esta directiva del preprocesador se pueden establecer propiedades y metainformación de una variable de entrada o de salida.
#property <channel>, <key>=<value>, ...
| Argumento | Tipo | Descripción |
|---|---|---|
| channel | <str> | El nombre del canal debe indicarse como primer argumento. Si contiene caracteres especiales como espacios o comas, debe ir entre comillas. No se permite el uso de la sintaxis $'...', ya que aquí solo se establecen propiedades del canal. |
| key | <str> | El nombre de la propiedad, véase la tabla siguiente |
| value | <var> | El nuevo valor de la propiedad (Variant) |
La tabla siguiente es una relación de las propiedades posibles y permitidas y de sus valores:
| Propiedad | Tipo | Descripción |
|---|---|---|
default | <var> | El valor default que se asigna a una variable hasta que llegan los primeros valores de datos del canal de smartCORE. Con ello es posible reaccionar en el módulo Math a flujos de datos de inicio retardado. |
timeout | off/<time> | Valor de timeout individual para este canal, sobrescribe inputTimeoutS. Como duración en segundos o en el formato [[[d:]h:]m:]s.f2; un valor con : debe ir entre comillas simples, p. ej. timeout='1:30'.off2, 0 o un valor negativo: el canal no recibe un timeout propio, se aplica inputTimeoutS. Un valor no válido se notifica como WARNING. |
timeless | <bool> | Con ello se activa o desactiva la función timeless para este canal. Equivale a la macro #timeless |
Establecer una zona horaria local "#timezone" 3
Con esta macro se puede establecer una zona horaria local para funciones de fecha y hora seleccionadas.
#timezone <tzIdentifier>
| tzIdentifier | Abreviaturas de zona horaria | Códigos de país |
|---|---|---|
Europe/BerlinEurope/StockholmEurope/OsloEurope/Copenhagen | CET / CEST | DE, DK, NO, SE, SJ |
Europe/BrusselsEurope/AmsterdamEurope/Luxembourg | CET / CEST | BE, LU, NL |
Europe/ParisEurope/ViennaEurope/WarsawEurope/ZurichEurope/Rome | CET / CEST | FR, MC, AT, PL, CH, IT |
Europe/KievEurope/Kyiv | EET / EEST | UA |
Asia/SingaporeAsia/Kuala_Lumpur | +08:00 | MY |
| ... |
Puede consultarse una lista de zonas horarias en Wikipedia.
En segundo plano se utiliza la biblioteca habitual en Linux HowardHinnant/date: A date and time library based on the C++11/14/17 <chrono> header , que se basa en la IANA Timezone Database. Esta se despliega en los sistemas con su versión actual en la distribución Yocto.
Un extracto de ella se distribuye junto con el software optiCONTROL, ya que la biblioteca matemática también está integrada allí en el editor del módulo Math.
Definición de funciones "#define"
Esta función está en preparación.
#define <newFunction>(<argsList>)[<options>]{<code>}
Información de depuración "#dump"
Esta directiva del preprocesador está prevista exclusivamente para diagnóstico y desarrollo. Produce una gran cantidad de salidas informativas en el archivo de registro de smartCORE y, por ello, solo debe utilizarse durante periodos cortos.
El parámetro de la directiva #dump es una lista de claves o de pares clave-valor separados por comas y afecta al texto de fórmulas siguiente:
#dump <key>, <key>=<value>, ...
| Key | Value | Descripción |
|---|---|---|
| tree | Emite el árbol de objetos traducido. Para su interpretación, véase más abajo. | |
| node | <uint> | Añade un nodo de objeto determinado para la monitorización continua (4, 5). |
| var | <str> | Añade una expresión regular para seleccionar nombres de canal cuyos accesos deben registrarse (4) |
| trace | <enum> | habilita la salida del flujo de datos para - in entradas, - out salidas o - io ambos sentidos de datos . |
| clear | Elimina todos los ajustes de dump para la sección de código siguiente. |
Ejemplos:
#dump tree
#dump node=5, node=9
#dump var='Temp.*', trace=out
Salida del árbol de objetos
La salida del árbol de objetos mediante #dump tree proporciona información detallada sobre las relaciones funcionales del conjunto de fórmulas definido. La evaluación está reservada a empleados cualificados de 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}}}
Las salidas de traza de un elemento de conexión del flujo de datos (out: o var:, canal o TS_Stream) tienen la siguiente estructura compacta:
{ 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}}}
En ella significan:
| Abreviatura | Flags | Descripción |
|---|---|---|
n:'...' | el nombre del canal, siempre que se trate de una variable | |
s:[] | flags de estado del canal | |
upLnk | Up-Link, conexión de un nodo subordinado al nodo superior | |
rdVar | Read Variable, variable de entrada, la proporciona smartCORE y solo se lee | |
wrVar | Write Variable, variable de salida, puede devolverse a smartCORE | |
inz | Initializer, tiene un nodo inicializador | |
const | Constant value, el valor no cambia durante el tiempo de ejecución. | |
discr | Discrete evaluation, este canal se calcula en pasos de muestreo discretos | |
ev@0 | Evaluate at Start, el canal discreto se ha inicializado | |
evDT | Evaluate Delta-T, se ha calculado un paso de muestreo para el canal discreto | |
expl | Explicit name, la variable se definió con la sintaxis $'…' y debe existir en smartCORE | |
fldE | Field-Element, el canal alimenta un campo de datos determinado en una estructura multidimensional (vector, matriz, …) | |
priv | Private, una variable creada por un bloque funcional y utilizada exclusivamente por este | |
prop | En la variable se han establecido propiedades adicionales con #property. | |
noT | noTime, este canal se marcó como #timeless y es siempre válido hasta el final del intervalo de cálculo. | |
+=dT | El canal tiene un desfase temporal constante procedente de shiftT() | |
nRec | NoRecursion, esta variable no puede utilizarse en un bucle de recursión. | |
toVal | Propiedad timeout asignada | |
fdVal | Propiedad default asignada | |
noCh | Este canal no se pudo conectar como entrada con un canal de smartCORE. => Se asignó el valor default como valor constante. Véase también isConnected() | |
TOut | Timeout de los datos de entrada, siempre que el canal todavía esté vacío (noD) o no se haya marcado como #timeless. Véase también isTimeout() | |
H1 | Interpolación lineal explícitamente permitida (1st-order hold) | |
:=fd | El valor default se ha escrito en el canal, véase también #property <channel>, default=<var> | |
*rd[] | Los índices de los nodos de objeto que acceden al canal en lectura | |
*wr[] | El índice del nodo de objeto que accede al canal en escritura | |
*@0[] | El índice del nodo de objeto que ejecuta la inicialización del canal discreto. | |
h:'...' | Indicación de la función del nodo escritor, p. ej. '*' o 'sin(…)' | |
[n]={} | la muestra almacenada en la posición más reciente n (corresponde al número de entradas - 1) con... | |
t: | Marca de tiempo en ns desde el 01.01.1970, INF (infinito) o NAV (no válido) | |
d: | Valor de datos con (estructura, tipo) valor o TrustedTimestamp, es decir, el valor anterior conserva su validez hasta este instante. El instante puede crecer de forma monótona en cada intervalo de cálculo. | |
[0]={} | la muestra almacenada en la posición más antigua (opcional) |
Seguir el desarrollo del cálculo "#monitor"
¡ADVERTENCIA! Esta directiva del preprocesador está prevista exclusivamente para diagnóstico y desarrollo. Produce una gran cantidad de salidas informativas en el archivo de registro de smartCORE y, por ello, solo debe utilizarse durante periodos cortos.
Monitorización de los búferes internos "#warn"
¡ADVERTENCIA! Esta directiva del preprocesador está prevista exclusivamente para diagnóstico y desarrollo. Produce una gran cantidad de salidas informativas en el archivo de registro de smartCORE y, por ello, solo debe utilizarse durante periodos cortos. Además, esta opción genera carga de CPU adicional y solo debe aplicarse temporalmente y bajo observación !!!
El parámetro de la directiva #warn es una lista de claves o de pares clave-valor separados por comas y afecta al texto de fórmulas siguiente:
| Key | Value | Descripción |
|---|---|---|
| maxbuflen | <uint> | Supervisa el número máximo de registros en una cola de datos. Se emite una advertencia cuando se supera el valor límite. Para el mensaje siguiente, el límite se eleva un 25 % de maxbuflen. |
| timeout | off/<time> | Supervisa el intervalo de tiempo entre la primera muestra de datos y el instante de ejecución. Se emite una advertencia cuando este tiempo es mayor que el valor establecido en s. Formato como en #property timeout2; off2 o 0: sin supervisión. |
| clear | Elimina todos los ajustes de advertencia para la sección de código siguiente. |
Ejemplos:
#warn maxBufLen=10, timeout=1000
// Formeltext zur Überwachung
#warn clear