This is an open source library to read and write different types of measurement data file formats.
The simplest way to include this library to your project is by adding it as a gitsubmodule to your project.
git submodule add git@github.com:MeasureTools/readerlib.git 3rdparty/readerlibThen add readerlib or readerlib_s to your CMake target_link_libraries and then include the wished header in your source code.
For example, to include the reader for Keysight dlog files use
#include<rlib/keysight/dlog_reader.h>This library requires boost and was tested with version >=1.65. It may work with earlier versions.
| Type | Exporter Support | Reader Support |
|---|---|---|
| meta | Yes | No |
| csv | Yes | Yes |
| grim | Yes | Yes |
| psi/psd | Yes | Yes |
| remote | No | Yes |
| svg | Yes | No |
| xml | Yes | Yes |
Currently the first column of the cvs needs to be the time in seconds as a floating point number. Each other column defines a sensor. The first row in the csv needs to include the sensor names and the value types. Also the seperator between the columns currently needs to be a comma(,).
Example:
time,Sensor Name (Unit),Another_Name (Unit2)0.1,10.0,22.00.2,12.0,23.0The .grim file format (while not containing any measurement data itself) allows to combine different measurement file formats and basic manipulation of the measurements.
Example for an .grim file:
<?xml version="1.0" encoding="UTF-8" ?>
<grimversion="1.0">
<sourcessamplerate="1000"> <!- Note: samplerate in **Hz** ->
<srcid="0"file="Abolute/Path/To/MeasurementFile.ext"/>
</sources>
<sensors>
<sensorname="MySensorName"unit="MySensorUnit">
<constvalue="1"/>
<plussrc="0"sensor="0"/>
<minussrc="0"sensor="0"/>
<timessrc="0"sensor="0"/>
<dividesrc="0"sensor="0"/>
</sensor>
<sensorname="MySensorName2"unit="MySensorUnit2">
<constvalue="0"/>
<plussrc="0"sensor="0"/>
<plusvalue="1"/>
<minusvalue="1"/>
<timesvalue="1"/>
<dividevalue="1"/>
</sensor>
</sensors>
</grim>The .psi/.psd file format is outputed by Hitex PowerScale Tools. Currently v1.0 of the format is supported.
Example for an .psi file with one STD probe.
<?xml version="1.0" encoding="UTF-8" ?>
<PSI>
<VersionValue="1.0" /> <!- Note: PSI Version ->
<ChecksumValue="0x00000000" /> <!- Note: Checksum seems to be always 0 ->
<Measurement>
<SamplingRateValue="10" /> <!- Note: the sampling rate in **kHz** ->
<SamplingCountValue="50" /> <!- Note: Number of all samples ->
</Measurement>
<DataStreamCount="1"> <!- Note: Count is number of probes (two values [U/I] per probe) ->
<DataStreamId="1" <!- Note: The Id marks the position of the data for this probe in a sample->
ProbeID="1" <!- Note: Port on the PowerScale HW used by the probe ->
ProbeKind="2" <!- Note: Type or probe STD=2, ACM=1 ->
voltageMin="2.5" <!- Note: Optional, min. voltage over all values of this probe ->
voltageMax="4.0" <!- Note: Optional, max. voltage over all values of this probe ->
currentMin="0" <!- Note: Optional, min. current over all values of this probe ->
currentMax="2.9" <!- Note: Optional, max. current over all values of this probe ->
/>
</DataStream>
<PSDCount="1"> <!- Note: Count is number of psd files, each psd file has the size of 1GiB ->
<VersionValue="1.0" /> <!- Note: PSD Version ->
<PSDFileId="1" <!- Note: Id of the psd file. By default this is $filename_$id.psd ->
Offset="0" <!- Note: Number of the first sample in the psd file ->
DataCount="50" <!- Note: Number of samples in the psd file ->
EventCount="0" <!- Note: Number of events with event_occur bit set to 1 ->
/>
</PSD>
</PSI>While the .psi file contains all meta information, the .psd files contain all the sample and event information as following.
struct {
struct {
struct {
double current; //In little endiandouble voltage; //In little endian
} probes[#probes];
struct {
uint16_t value : 15;
uint16_t occur : 1;//HSB
} probe_events[#probes];
struct {
uint16_t value : 15;
uint16_t occur : 1;//HSB
} global_event;
} samples[#samples_in_the_psd_file];
} psd;Example for an .xml file with measurement data supported by readerlib
<?xml version="1.0" encoding="UTF-8"?>
<output>
<sensors>
<sensorid="0"name="SensorName1"unit="SensorUnit1" />
<sensorid="0"name="SensorName2"unit="SensorUnit2" />
<sensorid="0"name="SensorName3"unit="SensorUnit3" />
</sensors>
<dataset>
<datatime="0">
<valuesensor="0"value="0.5" />
<valuesensor="1"value="1.5" />
<valuesensor="2"value="1.5" />
</data>
<datatime="0.2">
<valuesensor="0"value="0.5" />
<valuesensor="1"value="1.5" />
<valuesensor="2"value="1.5" />
</data>
</dataset>
<events>
<!- origin="-1" == global otherwise the sensor id->
<eventlevel="1"time="3"origin="-1"> <message>MSG:TEST_GLOBAL_EVENT</message>
<data>155</data>
</event>
<eventlevel="2"time="4"origin="2">
<message>MSG:TEST_SENSOR_2_EVENT</message>
<data>5</data>
</event>
<eventlevel="0"time="9"origin="0">
<message>MSG:TEST_SENSOR_0_EVENT</message>
<data>664</data>
</event>
<eventlevel="3"time="9"origin="1">
<message>MSG:TEST_SENSOR_1_EVENT</message>
<data>2</data>
</event>
</events>
</output>#include<rlib/keysight/dlog_reader.h>
#include<iostream>
#include<cstdlib>intmain(int argc, char* argv[]) {
auto reader = rlib::keysight::dlog_reader("example.dlog");
std::cout << "Filename: " << reader.filename() << std::endl;
std::cout << "----------- SENSORS -----------" << std::endl;
auto sensors = reader.sensors();
int i = 0;
for(auto& sensor : sensors) {
std::cout << "" << "Sensor No." << i << std::endl;
std::cout << "" << "Unit: " << sensor.unit << std::endl;
std::cout << "" << "Name: " << sensor.name << std::endl;
std::cout << "" << "Date: " << sensor.date << std::endl;
std::cout << "" << "Version: " << sensor.version << std::endl;
std::cout << "" << "Sampling interval: " << sensor.sampling_interval << std::endl;
std::cout << "" << "Channel: " << sensor.channel << std::endl;
std::cout << std::endl;
++i;
}
std::cout << "----------- SAMPLES -----------" << std::endl;
auto samples = reader.samples(0.0, reader.length());
for(auto& sample : samples) {
std::cout << "" << "Time:" << sample.time << " seconds" << std::endl;
int i = 0;
for(auto value : sample.values) {
std::cout << "" << "Sensor No." << i << " Value: " << value << std::endl;
++i;
}
std::cout << std::endl;
}
std::cout << "----------- EVENTS -----------" << std::endl;
auto events = reader.events(0.0, reader.length());
for(auto& event : events) {
switch(event.event_level) {
case rlib::common::VERBOS:
std::cout << "" << "LEVEL:VERBOS" << std::endl;
break;
case rlib::common::DEBUG:
std::cout << "" << "LEVEL:DEBUG" << std::endl;
break;
case rlib::common::WARNING:
std::cout << "" << "LEVEL:WARNING" << std::endl;
break;
case rlib::common::ERROR:
std::cout << "" << "LEVEL:ERROR" << std::endl;
break;
}
std::cout << "" << "Time:" << event.time << " seconds" << std::endl;
if (event.origin < 0) {
std::cout << "" << "Origin: GLOBAL" << std::endl;
}
else {
std::cout << "" << "Origin: Sensor No." << event.origin << std::endl;
}
std::cout << "" << "Message:" << event.message << std::endl;
std::cout << std::endl;
}
returnEXIT_SUCCESS;
}#include<rlib/keysight/dlog_reader.h>
#include<rlib/csv/csv_exporter.h>
#include<iostream>
#include<cstdlib>
#include<memory>intmain(int argc, char* argv[]) {
auto shared_reader = std::make_shared<rlib::keysight::dlog_reader>("example.dlog");
std::ofstream output("example.csv", std::ios::binary);
rlib::csv::csv_exporter exporter(shared_reader);
exporter.data_export(0.0, shared_reader->length(), output);
returnEXIT_SUCCESS;
}To run the tests do the following:
mkdir build
cd build
cmake ..
make
make testThis project is licensed under a modified BSD 1-Clause License with an additional non-military use clause - see the LICENSE file for details.
- TU Dortmund Embedded System Software Group which made this release possible