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:
Das „klassische“ netCDF-Format wie im Link oben beschrieben. Dateigröße maximal 2 GBytes. Die ersten drei Zeichen der Datei sind „CDF“.
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“.
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 überLoadLibrary
, (LoadLibraryEx
,GetModuleHandle
) undGetProcAddress
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 Attributenc_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
- undNC_FLOAT
-Kanälen der Zahlenwert1e10
für die ungültigen Werte geschrieben werden. Bei Integer-Kanälen sollte das Kanal-Attributmissing_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 alsNC_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 beiNC_FLOAT
undNC_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¶
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