Compare commits

..

11 Commits

7 changed files with 75 additions and 15 deletions

View File

@@ -31,6 +31,8 @@ On the [Record Evolution Platform](https://www.record-evolution.de/en/home-en/),
## File format ## File format
[Warning: Take a look at [this issue](https://github.com/RecordEvolution/IMCtermite/issues/14) when reading this section regarding the file format.]
A data file of the _IMC Bus Format_ type with the extension _.raw_ is a _mixed text/binary A data file of the _IMC Bus Format_ type with the extension _.raw_ is a _mixed text/binary
file_ featuring a set of markers (keys) that indicate the start of various blocks file_ featuring a set of markers (keys) that indicate the start of various blocks
of data that provide meta information and the actual measurement data. Every single of data that provide meta information and the actual measurement data. Every single
@@ -152,8 +154,9 @@ python3 -m pip install IMCtermite
which provides binary wheels for multiple architectures on _Windows_ and _Linux_ which provides binary wheels for multiple architectures on _Windows_ and _Linux_
and most _Python 3.x_ distributions. However, if your platform/architecture is and most _Python 3.x_ distributions. However, if your platform/architecture is
not supported you can still compile the source distribution yourself, which not supported you can still compile the source distribution yourself, which
requires _python3_setuptools_ and _gcc version >= 10.2.0_. requires _python3_setuptools_ and an up-to-date compiler supporting C++11
standard (e.g. _gcc version >= 10.2.0_).
## Usage ## Usage
@@ -189,23 +192,23 @@ options `imctermite sample-data.raw -b -c -s '|'`.
### Python ### Python
Given the `imctermite` module is available, we can import it and declare an instance Given the `IMCtermite` module is available, we can import it and declare an instance
of it by passing a _raw_ file to the constructor: of it by passing a _raw_ file to the constructor:
```Python ```Python
import imc_termite import IMCtermite
imcraw = imc_termite.imctermite(b"sample/sampleA.raw") imcraw = IMCtermite.imctermite(b"sample/sampleA.raw")
``` ```
An example of how to create an instance and obtain the list of channels is: An example of how to create an instance and obtain the list of channels is:
```Python ```Python
import imc_termite import IMCtermite
# declare and initialize instance of "imctermite" by passing a raw-file # declare and initialize instance of "imctermite" by passing a raw-file
try : try :
imcraw = imc_termite.imctermite(b"samples/sampleA.raw") imcraw = IMCtermite.imctermite(b"samples/sampleA.raw")
except RuntimeError as e : except RuntimeError as e :
print("failed to load/parse raw-file: " + str(e)) print("failed to load/parse raw-file: " + str(e))

View File

@@ -318,16 +318,16 @@ namespace imc
// convert buffer to actual datatype // convert buffer to actual datatype
void convert_buffer() void convert_buffer()
{ {
// TODO no clue how/if/when to handle buffer offset/mask/subsequent_bytes
// etc. and whatever that shit is!
std::vector<imc::parameter> prms = blocks_->at(chnenv_.CSuuid_).get_parameters(); std::vector<imc::parameter> prms = blocks_->at(chnenv_.CSuuid_).get_parameters();
if ( prms.size() < 4) if ( prms.size() < 4)
{ {
throw std::runtime_error("CS block is invalid and features to few parameters"); throw std::runtime_error("CS block is invalid and features to few parameters");
} }
// extract (channel dependent) part of buffer
unsigned long int buffstrt = prms[3].begin(); unsigned long int buffstrt = prms[3].begin();
std::vector<unsigned char> CSbuffer( buffer_->begin()+buffstrt+1, std::vector<unsigned char> CSbuffer( buffer_->begin()+buffstrt+buffer_offset_+1,
buffer_->begin()+buffstrt+buffer_size_+1 ); buffer_->begin()+buffstrt+buffer_offset_+buffer_size_+1 );
// determine number of values in buffer // determine number of values in buffer
unsigned long int num_values = (unsigned long int)(CSbuffer.size()/(signbits_/8)); unsigned long int num_values = (unsigned long int)(CSbuffer.size()/(signbits_/8));

View File

@@ -84,6 +84,7 @@ namespace imc
// noncritical keys // noncritical keys
key(false,"NO","origin of data",1), key(false,"NO","origin of data",1),
key(false,"NT","timestamp of trigger",1), key(false,"NT","timestamp of trigger",1),
key(false,"NT","timestamp of trigger",2),
key(false,"ND","(color) display properties",1), key(false,"ND","(color) display properties",1),
key(false,"NU","user defined key",1), key(false,"NU","user defined key",1),
key(false,"Np","property of channel",1), key(false,"Np","property of channel",1),

View File

@@ -236,13 +236,27 @@ namespace imc
// provide UUID for channel // provide UUID for channel
chnenv.uuid_ = chnenv.CNuuid_; chnenv.uuid_ = chnenv.CNuuid_;
// for multichannel data there may be multiple channels referring to
// the same (final) CS block (in contrast to what the IMC software
// documentation seems to suggest) resulting in all channels missing
// a CS block except for the very last
if ( chnenv.CSuuid_.empty() ) {
for ( imc::block blkCS: rawblocks_ ) {
if ( blkCS.get_key().name_ == "CS"
&& blkCS.get_begin() > (unsigned long int)stol(chnenv.uuid_) ) {
chnenv.CSuuid_ = blkCS.get_uuid();
}
}
}
// create channel object and add it to the map of channels // create channel object and add it to the map of channels
channels_.insert( std::pair<std::string,imc::channel> channels_.insert( std::pair<std::string,imc::channel>
(chnenv.CNuuid_,imc::channel(chnenv,&mapblocks_,&buffer_)) (chnenv.CNuuid_,imc::channel(chnenv,&mapblocks_,&buffer_))
); );
// reset channel uuid // reset channel uuid
chnenv.CNuuid_.clear(); chnenv.reset();
//chnenv.CNuuid_.clear();
} }
} }
@@ -254,7 +268,6 @@ namespace imc
} }
} }
public: public:
// provide buffer size // provide buffer size

View File

@@ -31,7 +31,7 @@ INST := /usr/local/bin
#-----------------------------------------------------------------------------# #-----------------------------------------------------------------------------#
# C++ and CLI tool # C++ and CLI tool
# build exectuable # build executable
$(EXE): check-tags $(GVSN) main.o $(EXE): check-tags $(GVSN) main.o
$(CC) $(OPT) main.o -o $@ $(CC) $(OPT) main.o -o $@

View File

@@ -1 +1 @@
2.0.3 2.0.7

View File

@@ -0,0 +1,43 @@
import IMCtermite
import pandas
import datetime
def add_trigger_time(trigger_time, add_time) :
trgts = datetime.datetime.strptime(trigger_time,'%Y-%m-%dT%H:%M:%S')
dt = datetime.timedelta(seconds=add_time)
return (trgts + dt).strftime('%Y-%m-%dT%H:%M:%S:%f')
if __name__ == "__main__" :
# read file and extract data
imctm = IMCtermite.imctermite(b"Measurement.raw")
chns = imctm.get_channels(True)
# prepare abscissa
xcol = "time ["+chns[0]['xunit']+"]"
#xcol = "timestamp"
xsts = [add_trigger_time(chns[0]['trigger-time'],tm) for tm in chns[0]['xdata']]
# sort channels
chnnms = sorted([chn['name'] for chn in chns], reverse=False)
chnsdict = {}
for chn in chns :
chnsdict[chn['name']] = chn
# construct dataframe
df = pandas.DataFrame()
df[xcol] = pandas.Series(chns[0]['xdata'])
#df[xcol] = pandas.Series(xsts)
#for idx,chn in enumerate(chns) :
for chnnm in chnnms :
chn = chnsdict[chnnm]
#xcol = (chn['xname'] if chn['xname'] != '' else "x_"+str(idx))+" ["+chn['xunit']+"]"
#df[xcol] = pandas.Series(chn['xdata'])
ycol = chn['yname']+" ["+chn['yunit']+"]"
df[ycol] = pandas.Series(chn['ydata'])
# show entire dataframe and write file
print(df)
df.to_csv("Measurement.csv",header=True,sep='\t',index=False)