netCDF-SDK

Hier wird beschrieben, wie die von UniPlot verwendeten Messdaten-Dateien mit C-Programmen (oder Programmen mit C-Anbindung) gelesen und geschrieben werden können.

Inhalt

Die folgenden Dateien müssen mit Ihrer Anwendung installiert werden. Diese Dateien können Sie einem installierten UniPlot entnehmen (R2018 oder später). Es können die 32-Bit oder die 64-Bit Version oder beide Versionen getrennt verwendet werden. Die Datei license.txt finden Sie im Verzeichnis UniPlot\samples\SDK\netCDF.

rs_updf_nc.dll
rs_updf.dll
rs_xlib.dll
zlib.dll
license.txt

Sonstige Dateien aus dem Verzeichnis UniPlot\samples\SDK\netCDF:

ncread.c            - Ein einfaches Beispiel-Programm zum Lesen.
ncwrite.c           - Ein einfaches Beispiel-Programm zum Schreiben.
win32\rs_updf_nc.lib      - Die 32-Bit Import-Library.
x64\rs_updf_nc.lib  - Die 64-Bit Import-Library.
up-nc.h             - Die Header-Datei.
map-data.nc2        - Einfache Beispiel-Datei.

Einige Anmerkungen

  • Das UniPlot-netCDF-SDK verwendet die API von netCDF 2.4.

    http://www.unidata.ucar.edu/software/netcdf/old_docs/really_old/guide_toc.html

  • Die von UniPlot verwendeten netCDF-Dateien können in drei verschiedenen Formaten vorliegen:

    1. Das „klassische“ netCDF-Format wie im Link oben beschrieben. Dateigröße maximal 2 GBytes. Die ersten drei Zeichen der Datei sind „CDF“.

    2. Eine speziell für UniPlot abgewandelte Form mit Intel-Byteorder (Little Endian). Diese Dateien können von Standard-netCDF-Librarys nicht gelesen werden. Dateigröße ebenfalls maximal 2 GBytes. Die ersten drei Zeichen der Datei sind „CDH“.

    3. Ein spezielles UniPlot-Format, dass von dem netCDF-Format nur noch die API verwendet. Es unterstützt Kompression und schnelles Löschen und Zufügen von Kanälen und Attributen. Die ersten drei Zeichen der Datei sind „UPD“. Diese Dateien sind wie ein Dateisystem aufgebaut. Die Informationen befinden sich in Sektoren, in denen sich Daten und Inhaltsverzeichnisse befinden. Es hat einige Ähnlichkeiten mit dem auf HDF aufbauenden netCDF-4, ist aber ein eigenes, unabhängiges Dateiformat und wesentlich einfacher als netCDF-4.

      Dateigröße maximal 1 TB, Kanallänge in dieser Version 2^31-1 Datenpunkte.

  • Falls Sie einen Microsoft C-Compiler verwenden, können Sie das Beispielprogramm mit:

    cl ncread.c x64\rs_updf_nc.lib
    

    übersetzen. Die Pfade für den C-Compiler müssen richtig gesetzt sein.

    Starten Sie das Programm mit:

    ncread map-data.nc2
    

    Es gibt die ersten 10 Datenpunkte aller Kanäle der Datendatei aus. Testdateien in verschiedenen Formaten können Sie mit UniPlot erstellen. Schalten Sie dazu aber in Extras=>Weitere Optionen von UniPlot Verzögertes Laden von Datenkanälen ab.

  • Anstatt die Import-Library rs_updf_nc.lib zu verwenden, können Sie die Funktionen auch über LoadLibrary, (LoadLibraryEx, GetModuleHandle) und GetProcAddress dynamisch laden.

  • Bei einigen Ursprungsformaten (z. B. INCA-MDF) konvertiert UniPlot die Dateien optional nicht komplett in einem Zug in das netCDF-Format. In diesen Dateien sind zwar alle globalen Attribute, die Definition der Kanäle sowie die Attribute der Kanäle enthalten, jedoch sind die Daten nicht von allen Kanälen enthalten.

    Ob die Daten des Kanals vorhanden sind, kann über das Kanal-Attribut _nc_dl_loaded gleich 0 oder 1 festgestellt werden. Über das globale Attribut _nc_dl_loadcount kann die Anzahl der geladenen Kanäle ermittelt werden.

Beispiele

 1/*
 2 compile: cl ncwrite.c rs_updf_nc.lib
 3*/
 4
 5#include <stdlib.h>
 6#include <stdio.h>
 7#include "up-nc.h"
 8
 9int error(char *msg)
10{
11    fprintf(stderr, "%s", msg);
12    exit(1);
13}
14
15void main(int argc, char *argv[])
16{
17    test();
18    exit(0);
19}
20
21int test()
22{
23    int ncid;
24    double *p;
25    int dimid;
26    int i, varid, start, count, len;
27    double scale = 1.0, offset = 0.0;
28
29    ncid = nccreate("test1.nc2");
30    if (ncid == -1) {
31        error("cannot open output file");
32    }
33
34    ncredef(ncid);
35
36    // Globale Attribute
37
38    varid = -1;
39    ncattput(ncid, varid, "Origin", NC_CHAR, 1, "");
40    ncattput(ncid, varid, "Source", NC_CHAR, 1, "");
41    len = strlen("FEV Software and Testing Solutions GmbH (www.uniplot.com)")+1;
42    ncattput(ncid, varid, "Creator", NC_CHAR, len, "FEV Software and Testing Solutions GmbH (www.uniplot.com)");
43    ncattput(ncid, varid, "Date", NC_CHAR, strlen("15 Nov 2013")+1, "15 Nov 2013");
44    ncattput(ncid, varid, "Time", NC_CHAR, strlen("09:24:20")+1, "09:24:20");
45
46    // Dimensionen
47    dimid = ncdimdef(ncid, "n", 100);
48
49    // Kanäle und Kanal-Attribute
50    varid = ncvardef(ncid, "var1", NC_DOUBLE, 1, &dimid);
51    ncattput(ncid, varid, "units", NC_CHAR, strlen("1/min")+1, "1/min");
52
53    ncattput(ncid, varid, "scale_factor", NC_DOUBLE, 1, &scale);
54    ncattput(ncid, varid, "add_offset", NC_DOUBLE, 1, &offset);
55
56    ncendef(ncid);
57
58    // Nun die Kanäle schreiben
59
60    p = (double*) malloc(100*sizeof(double));
61    for (i = 0; i < 100; i++) p[i] = (double) i;
62    start = 0;
63    count = 100;
64    ncvarput(ncid, varid, &start, &count, p);
65    free(p);
66    ncclose(ncid);
67    return 0;
68}

Schreiben eines String-Kanals

 1// compile: cl test_nc_string.c rs_updf_nc.lib
 2
 3#include <stdlib.h>
 4#include <stdio.h>
 5#include "up-nc.h"
 6
 7#define MIN(a,b) (((a)<(b))?(a):(b))
 8
 9void main()
10{
11    int ncid, varid, n1, len1, start[2], count[2], dimids[2];
12    char *s;
13
14    ncid = nccreate("d:\\test2.nc2");
15
16    // Kanallänge 10.000
17    n1 = ncdimdef(ncid, "n", 10000);
18
19    // Max. Anzahl an Zeichen in einer Zeichenkette, z. B. 32
20    len1 = ncdimdef(ncid, "len", 32);
21
22    dimids[0] = n1;
23    dimids[1] = len1;
24    varid = ncvardef(ncid, "StringChannel", NC_CHAR, 2, dimids);
25    ncendef(ncid);
26
27    start[0] = 0;
28    start[1] = 0;
29    count[0] = 1;
30    count[1] = 5;
31    ncvarput(ncid, varid, start, count, "Hallo");
32
33    s = "Dies ist ein längerer String";
34    start[0] = 10;
35    start[1] = 0;
36    count[0] = 1;
37    count[1] = MIN(32, strlen(s));
38    ncvarput(ncid, varid, start, count, s);
39
40    ncclose(ncid);
41}

Lesen einer Datei:

  1/*
  2 compile:
  3
  4 cl ncread.c rs_updf_nc.lib
  5
  6 See also
  7
  8 * readme.txt
  9
 10 * http://www.unidata.ucar.edu/software/netcdf/old_docs/really_old/guide_toc.html
 11
 12*/
 13
 14#include <stdlib.h>
 15#include <stdio.h>
 16#include "up-nc.h"
 17
 18int error(char *msg)
 19{
 20    fprintf(stderr, "%s", msg);
 21    exit(0);
 22}
 23
 24int att_print(int ncid, int varid, int attnum)
 25{
 26    char name[MAX_NC_NAME+1];
 27    int i, data_type, len;
 28    double *dVal;
 29    float *fVal;
 30    int *iVal;
 31    short *sVal;
 32    char *cVal;
 33
 34    ncattname(ncid, varid, attnum, name);
 35    ncattinq(ncid, varid, name, &data_type, &len);
 36    switch (data_type) {
 37    case NC_CHAR:
 38        cVal = (char*) malloc(len * sizeof(char));
 39        ncattget(ncid, varid, name, cVal);
 40        printf("%s = ", name);
 41        for (i = 0; i < len; i++) {
 42            printf("%c", cVal[i]);
 43        }
 44        printf("\n");
 45        free(cVal);
 46        break;
 47
 48    case NC_BYTE:
 49        cVal = (char*) malloc(len * sizeof(char));
 50        ncattget(ncid, varid, name, cVal);
 51        printf("%s = ", name);
 52        for (i = 0; i < len; i++) {
 53            printf("%d ", cVal[i]);
 54        }
 55        printf("\n");
 56        free(cVal);
 57        break;
 58
 59    case NC_SHORT:
 60        sVal = (short*) malloc(len * sizeof(short));
 61        ncattget(ncid, varid, name, sVal);
 62        printf("%s = ", name);
 63        for (i = 0; i < len; i++) {
 64            printf("%d ", sVal[i]);
 65        }
 66        printf("\n");
 67        free(sVal);
 68        break;
 69
 70    case NC_LONG:
 71        iVal = (int*) malloc(len * sizeof(int));
 72        ncattget(ncid, varid, name, iVal);
 73        printf("%s = ", name);
 74        for (i = 0; i < len; i++) {
 75            printf("%d ", iVal[i]);
 76        }
 77        printf("\n");
 78        free(iVal);
 79        break;
 80
 81    case NC_FLOAT:
 82        fVal = (float*) malloc(len * sizeof(float));
 83        ncattget(ncid, varid, name, fVal);
 84        printf("%s = ", name);
 85        for (i = 0; i < len; i++) {
 86            printf("%f ", fVal[i]);
 87        }
 88        printf("\n");
 89        free(fVal);
 90        break;
 91
 92    case NC_DOUBLE:
 93        dVal = (double*) malloc(len * sizeof(double));
 94        ncattget(ncid, varid, name, dVal);
 95        printf("%s = ", name);
 96        for (i = 0; i < len; i++) {
 97            printf("%lf ", dVal[i]);
 98        }
 99        printf("\n");
100        free(dVal);
101        break;
102    }
103    return 0;
104}
105
106void main(int argc, char *argv[])
107{
108    int ncid;
109    int nvars, ngatts, data_type, ndims, natts, length, length2;
110    int dimids[MAX_NC_DIMS];
111    int i, j;
112    char name[136];
113    double *vals;
114    float *fvals;
115    char *cvals;
116    unsigned char *bvals;
117    short *svals;
118    int *ivals;
119    int ret, start;
120    int st[2], le[2];
121
122    int max_len = 10;
123
124    if (argc != 2) {
125        error("usage: ncread nc-file-name");
126    }
127
128    ncid = ncopen(argv[1], 0);
129    if (ncid == -1) {
130        error("cannot open input file");
131    }
132    ncinquire(ncid, 0, &nvars, &ngatts, 0);
133
134    printf("ngatts=%d\n", ngatts);
135    for (i = 0; i < ngatts; i++) {
136        att_print(ncid, -1, i);
137    }
138
139    printf("\nnvars=%d\n", nvars);
140
141    for (i = 0; i < nvars; i++) {
142        ncvarinq(ncid, i, name, &data_type, &ndims, dimids, &natts);
143
144        printf("%s\n", name);
145
146        printf("natts=%d\n", natts);
147        for (j = 0; j < natts; j++) {
148            att_print(ncid, i, j);
149        }
150
151        if (ndims != 1 && data_type != NC_CHAR) {
152            printf("Variable %s wird im Beispielprog. ignoriert wg. Anzahl Dimensionen != 1", name);
153            continue;
154        }
155        switch (data_type) {
156        case NC_CHAR:
157            if (ndims != 2) {
158                printf("Variable %s wird im Beispielprog. ignoriert wg. Anzahl Dimensionen != 2", name);
159                continue;
160            }
161            ncdiminq(ncid, dimids[0], 0, &length);
162            ncdiminq(ncid, dimids[1], 0, &length2);
163            cvals = (char*) malloc(length2 * sizeof(char));
164            if (cvals == 0) {
165                error("out of memory");
166            }
167            printf("len=%d\n", length);
168            for (j = 0; j < min(max_len, length); j++) {
169                st[0] = j;
170                st[1] = 0;
171                le[0] = 1;
172                le[1] = length2;
173                ret = ncvarget(ncid, i, st, le, cvals);
174                printf("%s\n", cvals);
175            }
176            free(cvals);
177            break;
178
179        case NC_BYTE:
180            ncdiminq(ncid, dimids[0], 0, &length);
181            bvals = (unsigned char*) malloc(length * sizeof(unsigned char));
182            if (bvals == 0) {
183                error("out of memory");
184            }
185            start = 0;
186            ret = ncvarget(ncid, i, &start, &length, bvals);
187            printf("len=%d\n", length);
188            for (j = 0; j < min(max_len, length); j++) {
189                printf("%d\n", bvals[j]);
190            }
191            free(bvals);
192            break;
193
194        case NC_SHORT:
195            ncdiminq(ncid, dimids[0], 0, &length);
196            svals = (short*) malloc(length * sizeof(short));
197            if (svals == 0) {
198                error("out of memory");
199            }
200            start = 0;
201            ret = ncvarget(ncid, i, &start, &length, svals);
202            printf("len=%d\n", length);
203            for (j = 0; j < min(max_len, length); j++) {
204                printf("%d\n", svals[j]);
205            }
206            free(svals);
207            break;
208
209        case NC_LONG:
210            ncdiminq(ncid, dimids[0], 0, &length);
211            ivals = (int*) malloc(length * sizeof(int));
212            if (ivals == 0) {
213                error("out of memory");
214            }
215            start = 0;
216            ret = ncvarget(ncid, i, &start, &length, ivals);
217            printf("len=%d\n", length);
218            for (j = 0; j < min(max_len, length); j++) {
219                printf("%d\n", ivals[j]);
220            }
221            free(ivals);
222            break;
223
224        case NC_FLOAT:
225            ncdiminq(ncid, dimids[0], 0, &length);
226            fvals = (float*) malloc(length * sizeof(float));
227            if (fvals == 0) {
228                error("out of memory");
229            }
230            start = 0;
231            ret = ncvarget(ncid, i, &start, &length, fvals);
232            printf("len=%d\n", length);
233            for (j = 0; j < min(max_len, length); j++) {
234                printf("%f\n", fvals[j]);
235            }
236            free(fvals);
237            break;
238
239        case NC_DOUBLE:
240            ncdiminq(ncid, dimids[0], 0, &length);
241            vals = (double*) malloc(length * sizeof(double));
242            if (vals == 0) {
243                error("out of memory");
244            }
245            start = 0;
246            ret = ncvarget(ncid, i, &start, &length, vals);
247            printf("len=%d\n", length);
248            for (j = 0; j < min(max_len, length); j++) {
249                printf("%lf\n", vals[j]);
250            }
251            free(vals);
252            break;
253        }
254    }
255
256    ncclose(ncid);
257}

Konventionen

  • Kanalnamen und Attributnamen sollten aus folgenden Zeichen bestehen: _[a-z][A-Z][0-9], Zahlen nicht am Anfang des Namens, Länge maximal 128 Zeichen. Die folgenden 10 Sonderzeichen sind in Kanalnamen und Attributnamen ebenfalls zulässig: . - + $ # ~ ! ^ & %.

  • Kanal- und Attributnamen sollten nicht mit einem Unterstrich _ oder den Zeichen nc_` beginnen. Diese Namen sind reserviert für interne Zwecke (z. B. werden die Attribute nc_min, nc_monotone, _FillValue, _nc_dl_loadinfo intern verwendet).

  • Kanalnamen müssen eindeutig sein, die Anzahl an Kanälen ist auf 20.000 pro Datei beschränkt.

  • Missing Values: Sind einzelne Werte eines Kanals ungültig, sollte bei NC_DOUBLE- und NC_FLOAT-Kanälen der Zahlenwert 1e10 für die ungültigen Werte geschrieben werden. Bei Integer-Kanälen sollte das Kanal-Attribut missing_value geschrieben werden.

  • Zeitkanäle mit Sekunden und Sekundenbruchteilen sollten als NC_DOUBLE (8 Bytes) geschrieben werden, Daten die durch Transformation aus 16Bit-Integer-Kanälen entstanden sind, können als NC_FLOAT (4 Bytes) geschrieben werden.

  • Zeitkanäle die neben der Zeit noch das Datum enthalten, sollten als NC_DOUBLE geschrieben werden. UniPlot verwendet das gleiche Format wie Microsoft-Excel:

    uniplot_time = unix_time / 86400 + 25569
    
    Unix-Datum sind die Sekunden seit 1.1.1970 00:00:00.
    Excelzeit sind die Tage seit dem 31.12.1899
    
    86400: Sekunden eines Tages (24*60*60)
    25569: Tage zwischen 31.12.1899 und 1.1.1970
    

    Für den Kanal muss ausserdem das Attribut datatype mit einem der Werte „date“, „time“ oder „datetime“ geschrieben werden.

    Normalerweise sind Zeitkanäle aber normale NC_DOUBLE-Kanäle mit der Einheit Sekunde. Der Beginn der Messung wird dann als Datum/Zeit in globale Attribute geschrieben.

  • Stringkanäle sind Matrizen vom Typ NC_CHAR. Die zweite Dimension sollte nur so lang wie nötig sein, da alle Strings mit Nullen aufgefüllt werden. Siehe Beispiel oben.

  • Folgende globale Attribute (Attribute für die ganze Datei) sollten vorhanden sein:

    Attribut-Name

    Datentyp

    Bedeutung

    Origin

    NC_CHAR

    Name aus der die netCDF-Datei entstanden ist, z. B. c:\test-data\test.mdf4, kann leer gelassen werden, wenn es keine Quell-Datei gibt.

    Source

    NC_CHAR

    Ersteller des Import-Filters, z. B. FEV Software and Testing Solutions GmbH (www.uniplot.com)

    Creator

    NC_CHAR

    Name des Import-Filters, dem Namen kann eine Versionsnummer folgen. Z. B. MDF 4.1

    Date

    NC_CHAR

    Datum als Zeichenkette, z. B. 14 Nov 2013

    Time

    NC_CHAR

    Zeit als Zeichenkette, z. B. 12:11:31,345

    Daneben kann die Datei noch weitere beliebige Attribute enthalten. Z. B. die Datei-Attribute, die in dem Quellformat vorhanden sind, wie Projekt-Nummer oder Bearbeiter.

    Der Formelinterpreter kann auf globale Attribute zugreifen. Beispiel: Der Luftdruck (barom) während der Messung könnte als Kanal angegeben werden, oder, wenn er während der Messung konstant war, als globales Attribut:

    barom = 1013.4
    

    Es sollte dann ein weiteres Attribut mit der Einheit geben:

    barom.units = "mbar"
    

    Ab UniPlot 2014 kann das Attribut auch als Zeichenkette mit Angabe der Einheit verwendet werden:

    barom = "1013.4 mbar"
    
  • Alle Kanäle sollten die folgenden Attribute besitzen:

    Attribut-Name

    Datentyp

    Bedeutung

    title

    NC_CHAR

    Titel für Anzeigezwecke in Diagrammen, kann gleich dem Kanalnamen sein.

    long_name

    NC_CHAR

    Titel für Anzeigezwecke in Diagrammen, kann gleich dem Kanalnamen sein, optional mit Einheit in eckigen Klammern: zlrsb_w\ETKC:1 [s]

    units

    NC_CHAR

    Physikalische Einheit, z. B. Nm.

    scale_factor

    NC_DOUBLE

    Im Allgemeinen der Wert 1.

    add_offset

    NC_DOUBLE

    Im Allgemeinen der Wert 0.

    Die folgenden Attribute sind optional.

    Attribut-Name

    Datentyp

    Bedeutung

    missing_value

    wie Kanal

    Der Datentyp des Attributs missing_value ist der Datentyp des Kanals. Nur erforderlich bei Integer-Kanälen, bzw. wenn bei NC_FLOAT und NC_DOUBLE der Wert 1e10 nicht verwendet werden soll.

    Type

    NC_CHAR

    Wert ist entweder „Time Channel“ oder „Data Channel“.

    datatype

    NC_CHAR

    Bei Datum/Zeitkanälen: Mögliche Werte: „date“, „time“, „datetime“

    C_format

    NC_CHAR

    Formatzeichenkette zur Anzeige der Daten im Browser, z. B. %.2lf für die Ausgabe von 2 Nachkommastellen oder %.6lf für 6 Nachkommastellen, siehe printf. Der Wert kann weggelassen werden, wenn ein sinnvoller Wert nicht bekannt.

    Description

    NC_CHAR

    Beschreibung des Kanals, z. B. Anzahl der Dynamikmessungen LSU oder leerer String.

    Comment

    NC_CHAR

    Kommentar zum Kanal.

    Daneben kann der Kanal beliebige weitere Attribute enthalten.

Siehe auch

Überblick UniPlot-Datendateien

ncdump.exe

ncgen.exe

Überblick Datum und Zeit

History

Version

Beschreibung

1.4 (28.01.2019)

zlib.dll zugefügt.

1.4 (01.11.2017)

Korrekturen. Die beiden mitgelieferten Import-Libraries konnten nur mit R2015.x verwendet werden. Die nun mitgelieferten sind für R2016 und höher.

1.3 (09.01.2015)

Beschreibung ergänzt.

1.3 (09.01.2015)

Beschreibung ergänzt.

1.2 (21.11.2013)

Beschreibung ergänzt.

1.1 (25.03.2011)

Schreiben zugefügt.

1.0 (21.03.2011)

Erste Version.

id-1961936