Aller au contenu principal

Tableaux et bases de données

Champs de données, tableaux et bases de données​

Pour les fonctions suivantes, les tableaux nécessaires sont transmis à la fonction sous forme de ressource. Le tableau est lu et préparé en interne.

En tant que champ de données, on interpole entre des éléments de données individuels en fonction de la valeur d'entrée.

En tant que tableau avec noms de champs, on peut rechercher une entrée correspondante dans certains champs clés et lire différents champs de cette entrée.

L'implémentation d'une interface sqlite pour l'accès à une instance de base de données locale avec des requêtes de recherche définissables est prévue.

Courbe caractéristique, champ caractéristique « lookup »​

La fonction lookup() permet d'interpoler linéairement des données issues de courbes caractéristiques ou de champs caractéristiques pour une à trois grandeurs d'entrée.

L1 = lookup(x, {...});
L2 = lookup(x, y, {...});
L3 = lookup(x, y, z, {...});
// Das Konfigurationsobjekt ist verpflichtend und muss
// auf eine Ressource verweisen:
Lx = lookup(..., {$ref:'myLookupData'});

L'objet de configuration suit une syntaxe propre et doit donc être obtenu au moyen de {$ref:'myLookupData'} depuis la zone de ressources du module mathématique. Deux formats sont pris en charge : le format texte classique et une description au format JSON simplifié1

Description des entrées / axes​

Chaque signal d'entrée se voit attribuer un axe. Celui-ci est défini par son unité <unit>, une valeur de départ <from>, l'incrément <step> et le nombre de points d'appui <count>. Les axes ne doivent pas nécessairement être triés par ordre numérique croissant.

Configuration au format texte (classique)​

Pour chaque axe, la description suivante doit être ajoutée au début du bloc de texte, donc au moins une et au maximum trois :

IN <unit> <from> <step> <count>
Configuration au format JSON :​

Au format JSON, il est en outre possible d'indiquer un nom descriptif informel <name> et, à la place de l'un des paramètres de valeur précédemment cités, la valeur finale <to>. Il faut donc définir exactement trois des quatre propriétés <from>, <step>, <count> ou <to> ; la quatrième est calculée.

{
axes: [
{ name: <str>, // optional description
unit: <str>, // recommended
// choose 3 as mandatory of the following 4:
from: <dbl>, // left-side value of input axis
step: <dbl>, // increment between interpolation points
count: <uint>, // number of interpolation points
to: <dbl> // right-side value of input axis
}, ...
], ...
}

Description des sorties​

Le signal de sortie est décrit par une unité <unit>.

Configuration au format texte (classique)​

La définition suivante doit figurer une fois après la définition des entrées :

OUT <unit>
Configuration au format JSON :​

Au format JSON, il est en outre possible d'indiquer un nom descriptif informel <name>. À la place de l'objet JSON pour chaque sortie (recommandé), on peut aussi n'indiquer que l'unité physique sous forme de chaîne.

{
outputs: [
{ name: <str>, // optional description
unit: <str> // recommended
}, ... // prepared to support vector output in future
<str>, ... // alternative to define output by unit
], ...

Champ de données​

Le champ de données se compose de valeurs <dbl>. L'ordre des points d'appui découle du pseudo-code suivant :

foreach(z : axis3)
foreach(y : axis2)
foreach(x : axis1)
Value[x,y,z];
Configuration au format texte (classique)​

Les valeurs de données sont simplement séparées les unes des autres, au choix, par des espaces, des tabulations ou des retours à la ligne, et lues dans l'ordre dans les points d'appui de la courbe caractéristique ou du champ caractéristique.

0 42.942 87.924 134.946
184.008 235.11 288.252
... continued up to 161 data points
Configuration au format JSON :​

Au format JSON, toutes les valeurs de données sont indiquées dans un tableau de nombres à virgule flottante.

{
data: [
<dbl>, ...
], ...
}

Résumé​

Configuration au format texte (classique)​

Courbe caractéristique :

IN kPa 0.0 0.167751 161
OUT l

0
42.942
87.924
134.946
184.008
235.11
288.252
343.434
400.656
459.918
521.22
... continued up to 161 data points

Champ caractéristique :

IN g/h 0 10000 22
IN 1/min 900 100 10
OUT kW
0.0 40.8 81.6 132.9 185.2 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0 200.0
0.0 40.0 80.0 131.3 184.3 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0 230.0
0.0 38.5 76.9 125.8 182.4 233.5 286.9 310.0 310.0 310.0 310.0 310.0 310.0 310.0 310.0 310.0 310.0 310.0 310.0 310.0 310.0 310.0
... 7 more rows with 22 data points each
Configuration au format JSON simplifié​

L'objet de configuration peut aussi être décrit au format JSON simplifié1.

{
    axes: [
  { name: <str>,        // optional description
        unit: <str>,        // recommended
        from: <dbl>,        // left-side value of input axis
        step: <dbl>,        // increment between interpolation points
        count: <uint>,       // number of interpolation points
        to: <dbl>         // right-side value of input axis
}, ...
    ],
    outputs: [
{ name: <str>,        // optional description
        unit: <str>         // recommended
}, ...                 // prepared to support vector output in future
     <str>, ...             // alternative to define output by unit
    ],
    data: [
<dbl>, ...
    ]
}

Mise à disposition comme ressource​

Il existe de multiples possibilités d'intégrer cette description de courbe caractéristique ou de champ caractéristique dans les ressources du module mathématique.

Pour de petits champs caractéristiques ou courbes caractéristiques, le formatage comme ressource texte convient :

"resources": {
"myLookupData": [
"IN kPa 0.0 0.167751 161"
, "OUT l"
, "0 42.942 87.924 134.946 184.008 235.11 288.252 343.434"
, "400.656 459.918 521.22 584.562 649.944 717.366 785.90745"
, "854.45145 ... and more"
], ...

Alternativement, le même champ caractéristique au format JSON simplifié :

"resources": {
"myLookupData": {
axes: [{ name: "HydroStatPressure", unit: "kPa"
, from: 0.0, step: 0.167751, count: 161 }],
outputs: [{ name: "Volume", unit: "l" }],
data: [
0, 42.942, 87.924, 134.946, 184.008, 235.11, 288.252, 343.434
, 400.656, 459.918, 521.22, 584.562, 649.944, 717.366, 785.90745
, 854.45145, // ... and more
]
}, ...

Pour des champs caractéristiques plus grands, ou ceux qui ne doivent pas apparaître ou être lisibles dans la configuration JSON du smartCORE, une chaîne de caractères traitée serait judicieuse.

D'abord avec un fichier de champ caractéristique myLookupData.tab comme source de données, qui suit la syntaxe citée ci-dessus (texte/JSON) :

"resources": {
"myLookupData": {
"decoder": ["file"],
"value": "myLookupData.tab"
}, ...

ou, si le champ caractéristique se présente sous forme compressée :

"resources": {
"myLookupData": {
"decoder": ["file", "unzip"],
"value": "myLookupData.gz"
}, ...

Alternativement, les données peuvent aussi être intégrées dans la ressource sous forme de chaîne base64 :

"resources": {
"myLookupData": {
"decoder": ["base64"],
"value": "Q09MCWcvaAkwCTEwMDAwCTIyDQpST1cJMS9taW4JOTAwCTEw..."
}, ...

... ou le fichier compressé sous forme de chaîne base64 :

"resources": {
"myLookupData": {
"decoder": ["base64", "unzip"],
"value": "UEsDBBQAAgAIACt3cUoHOG6qmgEAAD4FAAAcAAAAUF9lZmZf..."
}

Requête de recherche « selectRow »​

La fonction selectRow() parcourt séquentiellement toutes les lignes d'un tableau simple à la recherche d'une correspondance avec les clés indiquées et renvoie l'index de ligne trouvé. Si aucune correspondance n'est trouvée, -1 est renvoyé. Une recherche n'est exécutée que si au moins l'une des valeurs de clé demandées change.

Cet index de ligne peut être utilisé dans getField() pour lire n'importe quelles valeurs dans les champs de données du tableau.

m1 = selectRow(key1, ..., { table: <str> // mandatory
, colSep: <regex>
, anyKey: <var>
, key: <str>        // mandatory (*)
, keys: [<str>]     // mandatory (*)
});
// (*) exactly one of key or keys must be defined
PropriétéValeurDescription
table<str>Obligatoire : nom d'une ressource texte qui définit le contenu du tableau. Les éléments de données sont interprétés comme des Variants et fournissent ainsi le meilleur type de données possible. Les nombres à virgule flottante doivent s'écrire avec un point comme séparateur décimal.
colSep<regex>Expression régulière qui définit les séparateurs de colonnes. Par défaut : "[,;|\t]", utilisable universellement pour un seul des caractères indiqués dans [].
anyKey<var>Un élément de données de cette valeur fournit un résultat positif pour n'importe quelle valeur de clé, par défaut : "*"
key<str>Obligatoire (*, **) : un champ de données du tableau dans lequel est recherchée la première et unique valeur de clé key1.
keys[<str>]Obligatoire (*, **) : un vecteur de plusieurs champs de données, à appliquer dans l'ordre indiqué aux valeurs de clé key1, key2, key3, ...

(*) Exactement l'une des propriétés key ou keys doit être utilisée pour sélectionner la ou les colonnes clés.

(**) Par défaut, c'est toujours une correspondance exacte de la valeur de clé avec les entrées de la colonne du tableau qui est recherchée. Les opérateurs de comparaison suivants peuvent facultativement précéder l'identifiant du champ pour modifier la requête ; des espaces peuvent être insérés entre l'opérateur et l'identifiant :

OpérateurSignificationExempleExécution comme...
KEY est un identifiant de champ dans keys:[..]keyN est la valeur de clé transmise en paramètre
==Correspondance exacte (par défaut)'KEY'
'==KEY'
keyN == Table[KEY]
*=pour <str> :
contient
*=KEYkeyN contains Table[KEY]
&=pour <uint>|<int> :
tous les bits du masque sont positionnés
'&=KEY'bAnd(keyN, Table[KEY]) == Table[KEY]
&>pour <uint>|<int> :
au moins un bit du masque est positionné
'&>KEY'bAnd(keyN, Table[KEY]) > 0
&0pour <uint>|<int> :
aucun bit du masque n'est positionné
'&0 KEY'bAnd(keyN, Table[KEY]) == 0
<=Inférieur ou égal'<=KEY'keyN <= Table[KEY]
<Inférieur à'<KEY'keyN < Table[KEY]
>=Supérieur ou égal'>=KEY'keyN >= Table[KEY]
>Supérieur à'>KEY'keyN > Table[KEY]

Pour le type de données <str>, les comparaisons se rapportent à l'ordre alphabétique.

Formatage du tableau​

  • Le tableau est chargé à partir d'une ressource texte (ASCII, UTF-8)

  • Les séparateurs de colonnes sont définis via la propriété colSep.

  • Le même tableau peut être utilisé dans plusieurs fonctions selectRow(). L'indication colSep doit être identique pour toutes, car on ne sait pas laquelle des fonctions interprète le tableau en premier (et donc aussi pour toutes les autres instances).

  • La première ligne contient les noms de champs, avec lesquels sont ensuite aussi définis les colonnes clés et les champs de résultat.

  • Les lignes vides sont ignorées.

  • Les lignes qui commencent par 3 caractères identiques du groupe _ - = ~ * sont interprétées comme ligne de séparation et ignorées.

  • Chaque champ de données est lu et traité individuellement comme Variant. Il n'y a donc pas de types de données fixes pour une colonne.

  • La recherche s'effectue toujours séquentiellement sur toutes les lignes.

Lecture d'une entrée de tableau « getField »​

La fonction getField() lit, dans un tableau table interprété avec selectRow(), pour l'index de ligne trouvé rowIdx, l'élément de données correspondant dans le champ de données field. Le type de données est déterminé par l'élément de données en tant que Variant.

Si rowIdx est < 0 ou en dehors de la plage valide, le Variant défini avec notFound est renvoyé.

v1 = getField(rowIdx, { table: <str> // mandatory
                , field: <str>     // mandatory
, notFound: <var>
});
PropriétéValeurDescription
table<str>Obligatoire : nom d'une ressource texte qui définit le contenu du tableau. Celui-ci doit avoir été interprété et chargé dans une fonction selectRow().
field<str>Obligatoire : nom d'un champ de données dans lequel lire la valeur de résultat.
notFound<var>Ce Variant est fourni comme résultat si rowIdx ne désigne pas un résultat de recherche valide. Par défaut : false.

Lecture de données enregistrées « playback » 2​

Under Construction Cette fonction est en cours de réalisation et n'est pas encore destinée à un usage productif.

La fonction playback() ouvre un fichier « Tape » et en extrait les évolutions temporelles de canaux de données sélectionnés, les « Tracks ».

attention

Selon la structure et la longueur des sources de données utilisées, des violations de mémoire et des plantages du smartCORE peuvent encore se produire.

Les tracks peuvent être publiés, avec un préfixe supplémentaire, comme variables dans le module Math, puis transmis aussi au smartCORE comme variables de sortie.

À l'instar d'un magnétophone classique, des marqueurs peuvent être placés pour la lecture d'une section de temps déterminée, et les fonctions de commande (Stop, Play, Pause, Rewind) peuvent aussi être déclenchées par une logique étendue.

Studer A800

Actuellement, le format de fichier OSF non compressé est pris en charge. D'autres formats, par exemple WAV, CSV, ... pourraient suivre dans de futures versions.

astuce

Les évolutions injectées dans le système depuis un tape peuvent servir de référence pour des signaux de mesure, afin de suivre et de surveiller leur évolution dynamique après un événement de départ.

astuce

Pour tester de nouvelles fonctions dans le module Math, des données de mesure issues de l'exploitation productive peuvent être rejouées en temps réel sur un système de laboratoire stationnaire. optiCONTROL offre diverses possibilités de préparation des données : fusion, découpage ou sélection de canaux.

astuce

Pour protéger les fichiers OSF sur le lecteur /sde de la compression automatique, il suffit d'utiliser une autre extension de fichier, par exemple *.osf_pb ou *.osf_tape.

t1 = playback(ctrl, {...});
t2 = playback(ctrl, tInfo, {...});
t3 = playback(ctrl, tInfo, source, {...});
// Configuration is mandatory for paths and keys
tx = playback(..., { directory: <str>     // mandatory!
, source: <str>        // mandatory! (or by parameter)
                   , varPrefix: <str>
                 , keys: [<str>] // mandatory!
    , tBegin: <date>
                 , tRewind: <date>
             , tEnd: <date>
, result: <enum>
, loop: <bool>
, tZoom: <dbl>
, endVar: <str>
});

Le paramètre tInfo peut contenir une valeur scalaire ou un vecteur d'au plus 3 composantes. La description figure également dans le tableau suivant.

PropriétéValeurDescription
directory<str>Chemin du répertoire contenant les tapes
source<str>Tape initial, peut être écrasé par un paramètre. Chaque changement charge, depuis le tape désigné, les canaux sélectionnés par keys
varPrefix<str>Le préfixe est placé devant les canaux sélectionnés pour la publication en tant que variable, par ex. « Tape. »
keys[<str>]Liste de noms de canaux du fichier tape, chargés pour la lecture.
tBegin<date>Instant de départ sur le tape sélectionné
tRewind<date>Point cible pour le retour en arrière ou l'avance rapide
tEnd<date>Instant de fin de la lecture ou retour automatique
result<enum>Sortie de la position du tape sous la forme
abs : horodatage absolu (par défaut)
relOrigin : horodatage relatif au début du tape
relBegin : horodatage relatif au repère tBegin
relInterval : position relative [0..1][0..1] dans l'intervalle [tBegin,tEnd][tBegin, tEnd]
loop<bool>Lorsque le repère tEnd est atteint, on revient à tRewind et la lecture se poursuit. (déf. : false)
tZoom<dbl>Facteur de zoom de l'axe temporel pendant la lecture (déf. : 1.0),
>1.0>1.0 : accéléré
<1.0<1.0 : ralenti
endVar<str>Variable de sortie <bool>, mise à 'true' lorsque le marqueur tEnd est atteint.
tInfo<dbl>:=tRewind:= tRewind
tInfo[<dbl>, <dbl>]:=[tRewind,tEnd]:= [tRewind, tEnd]
tInfo[<dbl>, <dbl>, <dbl>]:=[tBegin,tRewind,tEnd]:= [tBegin, tRewind, tEnd]

Footnotes​

  1. À l'exception des commentaires ↩ ↩2

  2. Disponible à partir de la version de catalogue 11. ↩