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