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/readerlib
Then 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.0
0.2, 12.0, 23.0
The .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" ?>
<grim version="1.0">
<sources samplerate="1000"> <!- Note: samplerate in **Hz** ->
<src id="0" file="Abolute/Path/To/MeasurementFile.ext"/>
</sources>
<sensors>
<sensor name="MySensorName" unit="MySensorUnit">
<const value="1"/>
<plus src="0" sensor="0"/>
<minus src="0" sensor="0"/>
<times src="0" sensor="0"/>
<divide src="0" sensor="0"/>
</sensor>
<sensor name="MySensorName2" unit="MySensorUnit2">
<const value="0"/>
<plus src="0" sensor="0"/>
<plus value="1"/>
<minus value="1"/>
<times value="1"/>
<divide value="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>
<Version Value="1.0" /> <!- Note: PSI Version ->
<Checksum Value="0x00000000" /> <!- Note: Checksum seems to be always 0 ->
<Measurement>
<SamplingRate Value="10" /> <!- Note: the sampling rate in **kHz** ->
<SamplingCount Value="50" /> <!- Note: Number of all samples ->
</Measurement>
<DataStream Count="1"> <!- Note: Count is number of probes (two values [U/I] per probe) ->
<DataStream
Id="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>
<PSD Count="1"> <!- Note: Count is number of psd files, each psd file has the size of 1GiB ->
<Version Value="1.0" /> <!- Note: PSD Version ->
<PSDFile
Id="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 endian
double 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>
<sensor id="0" name="SensorName1" unit="SensorUnit1" />
<sensor id="0" name="SensorName2" unit="SensorUnit2" />
<sensor id="0" name="SensorName3" unit="SensorUnit3" />
</sensors>
<dataset>
<data time="0">
<value sensor="0" value="0.5" />
<value sensor="1" value="1.5" />
<value sensor="2" value="1.5" />
</data>
<data time="0.2">
<value sensor="0" value="0.5" />
<value sensor="1" value="1.5" />
<value sensor="2" value="1.5" />
</data>
</dataset>
<events>
<!- origin="-1" == global otherwise the sensor id->
<event level="1" time="3" origin="-1">
<message>MSG:TEST_GLOBAL_EVENT</message>
<data>155</data>
</event>
<event level="2" time="4" origin="2">
<message>MSG:TEST_SENSOR_2_EVENT</message>
<data>5</data>
</event>
<event level="0" time="9" origin="0">
<message>MSG:TEST_SENSOR_0_EVENT</message>
<data>664</data>
</event>
<event level="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>
int main(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;
}
return EXIT_SUCCESS;
}
#include <rlib/keysight/dlog_reader.h>
#include <rlib/csv/csv_exporter.h>
#include <iostream>
#include <cstdlib>
#include <memory>
int main(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);
return EXIT_SUCCESS;
}
To run the tests do the following:
mkdir build
cd build
cmake ..
make
make test
This 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