New upstream version 0.1.2
Rafael Laboissiere
4 years ago
15 | 15 | |
16 | 16 | # shared library API versioning (soversion) -- NOT the same as the release version |
17 | 17 | # it follows first number |
18 | set(GDF_VERSION "0.1.1") | |
18 | set(GDF_VERSION "0.1.2") | |
19 | 19 | string( REGEX MATCH "^[0-9]+" GDF_SHAREDLIB_SOVERSION ${GDF_VERSION}) |
20 | 20 | |
21 | 21 | set_target_properties(GDF PROPERTIES |
0 | ||
1 | Development Head | |
2 | =================== | |
3 | * Support for Big-Endian architecture | |
4 | * Improved Matlab wrapper | |
5 | * Changelog | |
6 | ||
7 | Version 0.1.1 | |
8 | =================== | |
9 | ||
10 | Version 0.1.0 | |
11 | =================== |
25 | 25 | * MainHeader.patient_ICD is defined as byte[6]. Implemented as a string of length 6. |
26 | 26 | |
27 | 27 | * SignalHeader.physical_dimension is specified as a 6 byte long char[8]. Implemented as a string of length 6. |
28 | ||
29 | * Digital minimum and maximum range are 64 bit floating point numbers. Thus making storage of 64 bit integers at full precision impossible. Only integers up to 52 bit can be stored in full precision, according to the spec. |
115 | 115 | /// Serializer |
116 | 116 | void tostream( std::ostream &out ) |
117 | 117 | { |
118 | out.write( reinterpret_cast<char*>(&m_data[0]), sizeof(T)*m_data.size() ); | |
118 | //std::cout << "Channel -> Stream" << std::endl; | |
119 | //out.write( reinterpret_cast<char*>(&m_data[0]), sizeof(T)*m_data.size() ); | |
120 | for( size_t i=0; i<m_data.size(); i++ ) | |
121 | { | |
122 | writeLittleEndian( out, m_data[i] ); | |
123 | } | |
119 | 124 | } |
120 | 125 | |
121 | 126 | /// Deserializer |
122 | 127 | void fromstream( std::istream &in ) |
123 | 128 | { |
129 | //std::cout << "Stream -> Channel" << std::endl; | |
130 | //in.read( reinterpret_cast<char*>(&m_data[0]), sizeof(T)*m_data.size() ); | |
131 | ||
132 | for( size_t i=0; i<m_data.size(); i++ ) | |
133 | { | |
134 | readLittleEndian( in, m_data[i] ); | |
135 | } | |
136 | ||
124 | 137 | //char *charbuf = new char[sizeof(T)*m_data.size()]; |
125 | 138 | |
126 | in.read( reinterpret_cast<char*>(&m_data[0]), sizeof(T)*m_data.size() ); | |
127 | 139 | /*in.read( charbuf, sizeof(T)*m_data.size() ); |
128 | 140 | |
129 | 141 | for( size_t i=0; i<m_data.size(); i++ ) |
100 | 100 | struct HeaderItem : public HeaderItemBase |
101 | 101 | { |
102 | 102 | HeaderItem( ) : item(), pos(P) { } |
103 | void tostream( std::ostream & out ) const { out.write( reinterpret_cast<const char*>(&item), sizeof(item) ); } | |
104 | void fromstream( std::istream &in ) { in.read( reinterpret_cast<char*>(&item), sizeof(item) ); } | |
103 | //void tostream( std::ostream & out ) const { out.write( reinterpret_cast<const char*>(&item), sizeof(item) ); } | |
104 | //void fromstream( std::istream &in ) { in.read( reinterpret_cast<char*>(&item), sizeof(item) ); } | |
105 | void tostream( std::ostream & out ) const { writeLittleEndian( out, item ); } | |
106 | void fromstream( std::istream &in ) { readLittleEndian( in, item ); } | |
105 | 107 | T item; |
106 | 108 | size_t pos; |
107 | 109 | }; |
113 | 115 | HeaderArray( ) : pos(P), len(L) { } |
114 | 116 | T &operator[]( size_t idx ) { return item[idx]; } |
115 | 117 | const T &operator[]( size_t idx ) const { return item[idx]; } |
116 | void tostream( std::ostream & out ) const { out.write( reinterpret_cast<const char*>(item), sizeof(item) ); } | |
117 | void fromstream( std::istream &in ) { in.read( reinterpret_cast<char*>(item), sizeof(item) ); } | |
118 | ||
119 | //void tostream( std::ostream & out ) const { out.write( reinterpret_cast<const char*>(item), sizeof(item) ); } | |
120 | //void fromstream( std::istream &in ) { in.read( reinterpret_cast<char*>(item), sizeof(item) ); } | |
121 | ||
122 | void tostream( std::ostream & out ) const | |
123 | { | |
124 | for(size_t i=0; i<L; i++) | |
125 | writeLittleEndian( out, item[i] ); | |
126 | } | |
127 | ||
128 | void fromstream( std::istream &in ) | |
129 | { | |
130 | for(size_t i=0; i<L; i++) | |
131 | readLittleEndian( in, item[i] ); | |
132 | } | |
133 | ||
118 | 134 | T item[L]; |
119 | 135 | size_t pos, len; |
120 | 136 | }; |
20 | 20 | |
21 | 21 | #include "GDF/Exceptions.h" |
22 | 22 | #include <boost/cstdint.hpp> |
23 | #include <boost/detail/endian.hpp> | |
24 | #include <iostream> | |
23 | 25 | |
24 | 26 | namespace gdf |
25 | 27 | { |
52 | 54 | |
53 | 55 | size_t datatype_size( uint32 t ); |
54 | 56 | |
57 | template<typename T> | |
58 | T switch_endian( const T &source ) | |
59 | { | |
60 | T dest; | |
61 | const char *A = reinterpret_cast<const char*>(&source); | |
62 | char *B = reinterpret_cast<char*>(&dest); | |
63 | ||
64 | int a = 0; | |
65 | int b = sizeof(T)-1; | |
66 | ||
67 | while( b >= 0 ) | |
68 | { | |
69 | B[b] = A[a]; | |
70 | } | |
71 | } | |
72 | ||
73 | template<typename T> | |
74 | void writeLittleEndian( std::ostream &out, T item ) | |
75 | { | |
76 | #if defined(BOOST_LITTLE_ENDIAN) | |
77 | out.write( reinterpret_cast<const char*>(&item), sizeof(item) ); | |
78 | #elif defined(BOOST_BIG_ENDIAN) | |
79 | const char* p = reinterpret_cast<const char*>(&item) + sizeof(item)-1; | |
80 | for( size_t i=0; i<sizeof(item); i++ ) | |
81 | out.write( p--, 1 ); | |
82 | #else | |
83 | #error "Unable to determine system endianness." | |
84 | #endif | |
85 | } | |
86 | ||
87 | template<typename T> | |
88 | void readLittleEndian( std::istream &in, T &item ) | |
89 | { | |
90 | #if defined(BOOST_LITTLE_ENDIAN) | |
91 | in.read( reinterpret_cast<char*>(&item), sizeof(item) ); | |
92 | #elif defined(BOOST_BIG_ENDIAN) | |
93 | char* p = reinterpret_cast<char*>(&item) + sizeof(item)-1; | |
94 | for( size_t i=0; i<sizeof(item); i++ ) | |
95 | in.read( p--, 1 ); | |
96 | #else | |
97 | #error "Unable to determine system endianness." | |
98 | #endif | |
99 | } | |
100 | ||
55 | 101 | } |
56 | 102 | |
57 | 103 | #endif |
35 | 35 | |
36 | 36 | void EventHeader::toStream( std::ostream &stream ) |
37 | 37 | { |
38 | uint32 mode_and_num = ( getMode( ) ) + ( getNumEvents( ) << 8 ); | |
39 | stream.write( reinterpret_cast<const char*>(&mode_and_num), 4 ); | |
40 | ||
41 | float32 efs = getSamplingRate( ); | |
42 | stream.write( reinterpret_cast<const char*>(&efs), 4 ); | |
38 | stream.write( reinterpret_cast<const char*>(&m_mode), 1 ); | |
39 | ||
40 | // convert number of events to 24bit little endian representation | |
41 | uint32 numev = getNumEvents( ); | |
42 | char tmp[3]; | |
43 | tmp[0] = numev % 256; | |
44 | tmp[1] = (numev / 256) % 256; | |
45 | tmp[2] = (numev / 65536) % 256; | |
46 | stream.write( tmp, 3 ); | |
47 | ||
48 | writeLittleEndian( stream, getSamplingRate( ) ); | |
43 | 49 | |
44 | 50 | if( getMode() == 1 ) |
45 | 51 | { |
48 | 54 | for( size_t i=0; i<getNumEvents(); i++) |
49 | 55 | { |
50 | 56 | getEvent( i, e ); |
51 | stream.write( reinterpret_cast<const char*>(&e.position), sizeof(e.position) ); | |
57 | writeLittleEndian( stream, e.position ); | |
52 | 58 | } |
53 | 59 | // write event types |
54 | 60 | for( size_t i=0; i<getNumEvents(); i++) |
55 | 61 | { |
56 | 62 | getEvent( i, e ); |
57 | stream.write( reinterpret_cast<const char*>(&e.type), sizeof(e.type) ); | |
63 | writeLittleEndian( stream, e.type ); | |
58 | 64 | } |
59 | 65 | } |
60 | 66 | else if( getMode() == 3 ) |
64 | 70 | for( size_t i=0; i<getNumEvents(); i++) |
65 | 71 | { |
66 | 72 | getEvent( i, e ); |
67 | stream.write( reinterpret_cast<const char*>(&e.position), sizeof(e.position) ); | |
73 | writeLittleEndian( stream, e.position ); | |
68 | 74 | } |
69 | 75 | // write event types |
70 | 76 | for( size_t i=0; i<getNumEvents(); i++) |
71 | 77 | { |
72 | 78 | getEvent( i, e ); |
73 | stream.write( reinterpret_cast<const char*>(&e.type), sizeof(e.type) ); | |
79 | writeLittleEndian( stream, e.type ); | |
74 | 80 | } |
75 | 81 | // write event channels |
76 | 82 | for( size_t i=0; i<getNumEvents(); i++) |
77 | 83 | { |
78 | 84 | getEvent( i, e ); |
79 | stream.write( reinterpret_cast<const char*>(&e.channel), sizeof(e.channel) ); | |
85 | writeLittleEndian( stream, e.channel ); | |
80 | 86 | } |
81 | 87 | // write event durations |
82 | 88 | for( size_t i=0; i<getNumEvents(); i++) |
83 | 89 | { |
84 | 90 | getEvent( i, e ); |
85 | stream.write( reinterpret_cast<const char*>(&e.duration), sizeof(e.duration) ); | |
91 | writeLittleEndian( stream, e.duration ); | |
86 | 92 | } |
87 | 93 | } |
88 | 94 | } |
91 | 97 | { |
92 | 98 | clear( ); |
93 | 99 | |
94 | uint32 mode_and_num; | |
95 | stream.read( reinterpret_cast<char*>(&mode_and_num), 4 ); | |
96 | setMode( mode_and_num & 0x000000FF ); | |
97 | uint32 nev = (mode_and_num & 0xFFFFFF00 ) >> 8; | |
100 | uint8 mode; | |
101 | stream.read( reinterpret_cast<char*>(&mode), sizeof(mode) ); | |
102 | setMode( mode ); | |
103 | ||
104 | char tmp[3]; | |
105 | stream.read( tmp, 3 ); | |
106 | ||
107 | uint32 nev = tmp[0] + tmp[1]*256 + tmp[2]*65536; | |
98 | 108 | |
99 | 109 | float32 efs; |
100 | stream.read( reinterpret_cast<char*>(&efs), 4 ); | |
110 | readLittleEndian( stream, efs ); | |
101 | 111 | setSamplingRate( efs ); |
102 | 112 | |
103 | 113 | std::vector<uint32> positions; |
104 | 114 | std::vector<uint16> types; |
105 | 115 | positions.resize( nev ); |
106 | 116 | types.resize( nev ); |
107 | for( size_t i=0; i<nev; i++ ) stream.read( reinterpret_cast<char*>(&positions[i]), sizeof(uint32) ); | |
108 | for( size_t i=0; i<nev; i++ ) stream.read( reinterpret_cast<char*>(&types[i]), sizeof(uint16) ); | |
117 | for( size_t i=0; i<nev; i++ ) | |
118 | readLittleEndian( stream, positions[i] ); | |
119 | for( size_t i=0; i<nev; i++ ) | |
120 | readLittleEndian( stream, types[i] ); | |
109 | 121 | |
110 | 122 | if( getMode() == 1 ) |
111 | 123 | { |
123 | 135 | std::vector<uint32> durations; |
124 | 136 | channels.resize( nev ); |
125 | 137 | durations.resize( nev ); |
126 | for( size_t i=0; i<nev; i++ ) stream.read( reinterpret_cast<char*>(&channels[i]), sizeof(uint16) ); | |
127 | for( size_t i=0; i<nev; i++ ) stream.read( reinterpret_cast<char*>(&durations[i]), sizeof(uint32) ); | |
138 | for( size_t i=0; i<nev; i++ ) | |
139 | readLittleEndian( stream, channels[i] ); | |
140 | for( size_t i=0; i<nev; i++ ) | |
141 | readLittleEndian( stream, durations[i] ); | |
128 | 142 | for( size_t i=0; i<nev; i++ ) |
129 | 143 | { |
130 | 144 | Mode3Event e; |
0 | function gdf_remove_eog( inputfile, outputfile, reffile, eegchan, eogchan ) | |
1 | ||
2 | % gdf_remove_eog( inputfile, outputfile, reffile ) | |
3 | % | |
4 | % Remove eog artifacts by regression. | |
5 | % | |
6 | % Inputs: | |
7 | % inputfile : filename of the original raw data | |
8 | % outputfile : output filename | |
9 | % reffile : file that contains eog reference data | |
10 | % eegchan : EEG channel numbers | |
11 | % eogchan : EOG channel numbers | |
12 | ||
13 | % apply spatial filter matrix to a gdf | |
14 | ||
15 | % load gdf files | |
16 | ||
17 | [s, h, e] = gdf_reader( inputfile, 'dataformat', 'single' ); | |
18 | input.s = s; | |
19 | input.h = h; | |
20 | input.e = e; | |
21 | ||
22 | [s, h, e] = gdf_reader( reffile, 'dataformat', 'single' ); | |
23 | ref.s = s; | |
24 | ref.h = h; | |
25 | ref.e = e; | |
26 | ||
27 | % calculate eog regression | |
28 | ||
29 | refeeg = [ref.s{eegchan}]; | |
30 | refeog = [ref.s{eogchan}]; | |
31 | ||
32 | refeeg( any( isnan( refeeg ), 2 ), : ) = []; | |
33 | refeog( any( isnan( refeog ), 2 ), : ) = []; | |
34 | ||
35 | Y = refeeg; | |
36 | U = refeog; | |
37 | ||
38 | CNN = U'*U/size(U,1); | |
39 | CNY = U'*Y/size(U,1); | |
40 | eog_weights = CNN\CNY; | |
41 | ||
42 | % apply eog correction | |
43 | ||
44 | eeg = [input.s{eegchan}]; | |
45 | eog = [input.s{eogchan}]; | |
46 | ||
47 | eeg = eeg - eog * eog_weights; | |
48 | ||
49 | % 4. save new gdf | |
50 | ||
51 | handle = gdf_writer( 'init' ); | |
52 | ||
53 | for c = 1 : input.h.file.num_signals | |
54 | gdf_writer( 'createsignal', handle, c ); | |
55 | end | |
56 | ||
57 | gdf_writer( 'setheader', handle, input.h ); | |
58 | ||
59 | gdf_writer( 'recordduration', handle, 0 ); % automatic record duration | |
60 | ||
61 | gdf_writer( 'eventconfig', handle, input.e.mode, input.e.sample_rate ); | |
62 | ||
63 | gdf_writer( 'open', handle, outputfile ); | |
64 | ||
65 | chunksize = 1; % seconds | |
66 | num_chunks = ceil( length(input.s{1}) / (chunksize*input.h.signals(1).sampling_rate) ); | |
67 | datapos = ones(1,input.h.file.num_signals); | |
68 | ||
69 | for d = 1 : num_chunks | |
70 | for c = 1 : input.h.file.num_signals | |
71 | datalen = chunksize * input.h.signals(c).sampling_rate; | |
72 | if find( eegchan==c ) | |
73 | data = input.s{c}( datapos(c) + (1:datalen) - 1 ); | |
74 | else | |
75 | data = input.s{c}( datapos(c) + (1:datalen) - 1 ); | |
76 | end | |
77 | gdf_writer( 'blitsamples', handle, c, data ); | |
78 | datapos(c) = datapos(c) + datalen; | |
79 | end | |
80 | end | |
81 | ||
82 | if input.e.mode == 1 | |
83 | for e = 1 : length( input.e.position ) | |
84 | gdf_writer( 'mode1ev', handle, input.e.position(e), input.e.event_code(e) ); | |
85 | end | |
86 | elseif input.e.mode == 3 | |
87 | for e = 1 : length( input.e.position ) | |
88 | gdf_writer( 'mode3ev', handle, input.e.position(e), input.e.event_code(e), input.e.channel(e), input.e.duration(e) ); | |
89 | end | |
90 | end | |
91 | ||
92 | gdf_writer( 'close', handle ); | |
93 | ||
94 | gdf_writer( 'clear', handle ); | |
95 | ||
96 | end |
1 | 1 | |
2 | 2 | % 1. load gdf file |
3 | 3 | |
4 | [signals, header, events] = gdf_reader( inputfile, 'multiratesignals', 'single' ); | |
4 | [signals, header, events] = gdf_reader( inputfile, 'multiratesignals', 'single', 'dataorientation', 'row' ); | |
5 | 5 | |
6 | 6 | num_channels = length( signals ); |
7 | 7 | |
42 | 42 | end |
43 | 43 | |
44 | 44 | % 3. fix event positions |
45 | ||
46 | if events.mode == 3 | |
47 | events.duration = events.duration * double(fs_new / events.sample_rate); | |
48 | end | |
45 | 49 | |
46 | 50 | events.position = events.position * double(fs_new / events.sample_rate); |
47 | 51 | events.sample_rate = fs_new; |
91 | 95 | |
92 | 96 | gdf_writer( 'clear', handle ); |
93 | 97 | |
94 | end⏎ | |
98 | end |
17 | 17 | |
18 | 18 | #include "gdf_mex.h" |
19 | 19 | #include "matlab_tools/mxStructAccess.h" |
20 | #include <GDF/EventConverter.h> | |
20 | 21 | #include <GDF/Reader.h> |
21 | 22 | #include <mex.h> |
22 | 23 | |
23 | 24 | #include <boost/lexical_cast.hpp> |
25 | ||
26 | ||
27 | #define VERBOSE | |
24 | 28 | |
25 | 29 | |
26 | 30 | using namespace std; |
42 | 46 | #define OPTION_DATAFORMAT_COL1 "COL" |
43 | 47 | #define OPTION_DATAFORMAT_COL2 "COLUMN" |
44 | 48 | |
49 | #define OPTION_CONVERTEVENTS "FORCEMODE3EVENTS" | |
50 | ||
45 | 51 | enum eMultirateMode |
46 | 52 | { |
47 | 53 | MR_UPSAMPLE, |
53 | 59 | { |
54 | 60 | DO_ROW, |
55 | 61 | DO_COL |
62 | }; | |
63 | ||
64 | enum eVerboseLevels | |
65 | { | |
66 | V_NONE = 0, | |
67 | V_CONSTRUCTOR_CALLS, | |
68 | V_FUNCTION_CALLS, | |
69 | V_FUNCTION_DETAILS, | |
70 | V_FUNCTION_LOOPS, | |
71 | V_ALL | |
56 | 72 | }; |
57 | 73 | |
58 | 74 | // =========================================================================== |
102 | 118 | |
103 | 119 | void parseInputArguments( ); |
104 | 120 | |
121 | void verboseMessage( int level, std::string message ); | |
122 | ||
105 | 123 | private: |
106 | 124 | |
107 | 125 | size_t nlhs_, nrhs_; |
112 | 130 | eMultirateMode multirate_mode; |
113 | 131 | Interpolator *interpolator; |
114 | 132 | eDataOrientation data_orientation; |
133 | bool convert_events; | |
115 | 134 | |
116 | 135 | gdf::uint16 num_signals; |
117 | 136 | gdf::uint64 num_records; |
120 | 139 | |
121 | 140 | map< gdf::uint32, vector<gdf::uint16> > signals_by_samplerate; |
122 | 141 | vector<gdf::uint32> samples_per_record; |
142 | ||
143 | int verbose_level; | |
123 | 144 | }; |
124 | 145 | |
125 | 146 | // =========================================================================== |
135 | 156 | // =========================================================================== |
136 | 157 | |
137 | 158 | CmexObject::CmexObject( size_t nlhs, mxArray *plhs[], size_t nrhs, const mxArray *prhs[] ) |
159 | : verbose_level( V_NONE ) | |
138 | 160 | { |
139 | 161 | using boost::numeric_cast; |
162 | ||
163 | verboseMessage( V_CONSTRUCTOR_CALLS, "entering CmexObject::CmexObject( );"); | |
140 | 164 | |
141 | 165 | interpolator = NULL; |
142 | 166 | |
156 | 180 | multirate_mode = MR_SINGLE; |
157 | 181 | interpolator = new InterpolatorDummy( ); |
158 | 182 | data_orientation = DO_COL; |
183 | convert_events = false; | |
159 | 184 | |
160 | 185 | nlhs_ = nlhs; |
161 | 186 | plhs_ = plhs; |
163 | 188 | prhs_ = prhs; |
164 | 189 | |
165 | 190 | parseInputArguments( ); |
191 | verboseMessage( V_CONSTRUCTOR_CALLS, "leaving CmexObject::CmexObject( );"); | |
166 | 192 | } |
167 | 193 | |
168 | 194 | // =========================================================================== |
169 | 195 | |
170 | 196 | CmexObject::~CmexObject( ) |
171 | 197 | { |
198 | verboseMessage( V_CONSTRUCTOR_CALLS, "entering CmexObject::~CmexObject( );"); | |
172 | 199 | if( interpolator ) delete interpolator; |
200 | verboseMessage( V_CONSTRUCTOR_CALLS, "leaving CmexObject::~CmexObject( );"); | |
173 | 201 | } |
174 | 202 | |
175 | 203 | // =========================================================================== |
176 | 204 | |
177 | 205 | void CmexObject::execute( ) |
178 | 206 | { |
207 | verboseMessage( V_FUNCTION_CALLS, "entering CmexObject::execute( );"); | |
179 | 208 | gdf::Reader reader; |
180 | 209 | |
181 | 210 | reader.enableCache( false ); |
183 | 212 | |
184 | 213 | num_signals = reader.getMainHeader_readonly().get_num_signals(); |
185 | 214 | num_records = reader.getMainHeader_readonly().get_num_datarecords(); |
215 | ||
216 | verboseMessage( V_FUNCTION_DETAILS, "Number of data records: "+boost::lexical_cast<std::string>( num_records ) ); | |
186 | 217 | |
187 | 218 | if( num_signals > 0 ) |
188 | 219 | { |
236 | 267 | } |
237 | 268 | |
238 | 269 | reader.close( ); |
270 | ||
271 | verboseMessage( V_FUNCTION_CALLS, "leaving CmexObject::execute( );"); | |
239 | 272 | } |
240 | 273 | |
241 | 274 | // =========================================================================== |
242 | 275 | |
243 | 276 | void CmexObject::getUpsampleData( gdf::Reader &reader ) |
244 | 277 | { |
278 | verboseMessage( V_FUNCTION_CALLS, "entering CmexObject::getUpsampleData( );"); | |
245 | 279 | // construct output structure |
246 | 280 | if( data_orientation == DO_ROW ) |
247 | 281 | plhs_[0] = mxCreateNumericMatrix( num_signals, num_records*max_rate, mxDOUBLE_CLASS, mxREAL ); |
287 | 321 | interpolator->expand( &data[s*num_records*max_rate], 1, samples_per_record[s]*num_records, max_rate*num_records ); |
288 | 322 | } |
289 | 323 | } |
324 | verboseMessage( V_FUNCTION_CALLS, "leaving CmexObject::getUpsampleData( );"); | |
290 | 325 | } |
291 | 326 | |
292 | 327 | // =========================================================================== |
293 | 328 | |
294 | 329 | void CmexObject::getGroupData( gdf::Reader &reader ) |
295 | 330 | { |
331 | verboseMessage( V_FUNCTION_CALLS, "entering CmexObject::getGroupData( );"); | |
332 | ||
296 | 333 | // construct output structure |
334 | verboseMessage( V_FUNCTION_DETAILS, " constructing output structure."); | |
297 | 335 | |
298 | 336 | plhs_[0] = mxCreateStructMatrix( num_samplerates, 1, 0, NULL ); |
299 | 337 | mxAddField( plhs_[0], "channels" ); |
302 | 340 | map< gdf::uint32, vector<gdf::uint16> >::iterator it = signals_by_samplerate.begin( ); |
303 | 341 | for( gdf::uint16 g=0; g<num_samplerates; g++, it++ ) |
304 | 342 | { |
343 | verboseMessage( V_FUNCTION_LOOPS, " creating group." ); | |
305 | 344 | gdf::uint16 signal = it->second.front( ); // just one of the signals in this group |
306 | 345 | size_t num_samples = samples_per_record[signal] * num_records; |
307 | 346 | |
328 | 367 | } |
329 | 368 | |
330 | 369 | // fill output structure with data |
370 | verboseMessage( V_FUNCTION_DETAILS, " filling output structure." ); | |
371 | ||
331 | 372 | for( gdf::uint64 r=0; r<num_records; r++ ) |
332 | { | |
373 | //for( gdf::uint64 r=0; r<100; r++ ) | |
374 | { | |
375 | if( r==0 ) | |
376 | verboseMessage( V_FUNCTION_LOOPS, " 1st record" ); | |
377 | else if( r==num_records-1 ) | |
378 | verboseMessage( V_FUNCTION_LOOPS, " last record" ); | |
379 | ||
333 | 380 | gdf::Record *rec = reader.getRecordPtr( r ); |
334 | 381 | it = signals_by_samplerate.begin( ); |
335 | 382 | for( gdf::uint16 g=0; g<num_samplerates; g++, it++ ) |
337 | 384 | if( it->first == 0 ) |
338 | 385 | continue; |
339 | 386 | double *data = mxGetPr( mx::getField( plhs_[0], "data", g+1 ) ); |
340 | size_t rows = it->second.size( ); | |
341 | for( size_t s=0; s<rows; s++ ) | |
387 | size_t sing = it->second.size( ); // signals in group | |
388 | for( size_t s=0; s<sing; s++ ) | |
342 | 389 | { |
343 | 390 | gdf::uint16 signal = it->second[s]; |
344 | 391 | for( gdf::uint32 n=0; n<samples_per_record[signal]; n++ ) |
346 | 393 | if( data_orientation == DO_ROW ) |
347 | 394 | { |
348 | 395 | size_t column = n + r * samples_per_record[signal]; |
349 | data[s+column*rows] = rec->getChannel(signal)->getSamplePhys( n ); | |
396 | size_t row = s; | |
397 | size_t rows = sing; | |
398 | data[row+column*rows] = rec->getChannel(signal)->getSamplePhys( n ); | |
350 | 399 | } |
351 | 400 | else |
352 | 401 | { |
353 | size_t row = n + r * samples_per_record[s]; | |
354 | data[row+s*num_records*samples_per_record[signal]] = rec->getChannel( s )->getSamplePhys( n ); | |
402 | size_t column = s; | |
403 | size_t row = n + r * samples_per_record[signal]; | |
404 | size_t rows = num_records * samples_per_record[signal]; | |
405 | data[row+column*rows] = rec->getChannel(signal)->getSamplePhys( n ); | |
355 | 406 | } |
356 | 407 | } |
357 | 408 | } |
358 | 409 | } |
359 | 410 | } |
411 | verboseMessage( V_FUNCTION_CALLS, "leaving CmexObject::getGroupData( );"); | |
360 | 412 | } |
361 | 413 | |
362 | 414 | // =========================================================================== |
363 | 415 | |
364 | 416 | void CmexObject::getSingleData( gdf::Reader &reader ) |
365 | 417 | { |
418 | verboseMessage( V_FUNCTION_CALLS, "entering CmexObject::getSingleData( );"); | |
366 | 419 | // construct output structure |
367 | 420 | plhs_[0] = mxCreateCellMatrix( num_signals, 1 ); |
368 | 421 | for( gdf::uint16 s=0; s<num_signals; s++ ) |
392 | 445 | } |
393 | 446 | } |
394 | 447 | } |
448 | verboseMessage( V_FUNCTION_CALLS, "leaving CmexObject::getSingleData( );"); | |
395 | 449 | } |
396 | 450 | |
397 | 451 | // =========================================================================== |
398 | 452 | |
399 | 453 | void CmexObject::loadEvents( gdf::Reader &reader ) |
400 | 454 | { |
455 | verboseMessage( V_FUNCTION_CALLS, "entering CmexObject::loadEvents( );"); | |
401 | 456 | plhs_[2] = mxCreateStructMatrix( 1, 1, 0, NULL ); |
402 | 457 | gdf::EventHeader *evh = reader.getEventHeader( ); |
403 | 458 | gdf::uint32 num_ev = evh->getNumEvents( ); |
404 | 459 | |
405 | switch( evh->getMode() ) | |
460 | std::vector<gdf::Mode3Event> ev3; | |
461 | ||
462 | gdf::uint8 mode = evh->getMode( ); | |
463 | ||
464 | if( convert_events && mode == 1 ) | |
465 | { | |
466 | ev3 = gdf::convertMode1EventsIntoMode3Events( evh->getMode1Events() ); | |
467 | mode = 3; | |
468 | num_ev = ev3.size( ); | |
469 | } | |
470 | ||
471 | switch( mode ) | |
406 | 472 | { |
407 | 473 | default: throw invalid_argument( " Invalid Event Mode." ); |
408 | 474 | case 1: { |
412 | 478 | mx::setField( plhs_[2], NULL, GDFE_TYP ); |
413 | 479 | |
414 | 480 | mx::setFieldNumeric( plhs_[2], evh->getSamplingRate( ), GDFE_FS ); |
415 | mx::setFieldNumeric( plhs_[2], evh->getMode( ), GDFE_MODE ); | |
481 | mx::setFieldNumeric( plhs_[2], mode, GDFE_MODE ); | |
416 | 482 | |
417 | 483 | mxArray *mxpos = mxCreateNumericMatrix( 1, num_ev, mxUINT32_CLASS, mxREAL ); |
418 | 484 | mx::setField( plhs_[2], mxpos, GDFE_POS ); |
431 | 497 | } |
432 | 498 | } break; |
433 | 499 | case 3: { |
500 | ||
501 | if( !convert_events ) | |
502 | ev3 = evh->getMode3Events( ); | |
503 | ||
434 | 504 | mx::setField( plhs_[2], NULL, GDFE_MODE ); |
435 | 505 | mx::setField( plhs_[2], NULL, GDFE_FS ); |
436 | 506 | mx::setField( plhs_[2], NULL, GDFE_POS ); |
439 | 509 | mx::setField( plhs_[2], NULL, GDFE_3_DUR ); |
440 | 510 | |
441 | 511 | mx::setFieldNumeric( plhs_[2], evh->getSamplingRate( ), GDFE_FS ); |
442 | mx::setFieldNumeric( plhs_[2], evh->getMode( ), GDFE_MODE ); | |
512 | mx::setFieldNumeric( plhs_[2], mode, GDFE_MODE ); | |
443 | 513 | |
444 | 514 | mxArray *mxpos = mxCreateNumericMatrix( 1, num_ev, mxUINT32_CLASS, mxREAL ); |
445 | 515 | mx::setField( plhs_[2], mxpos, GDFE_POS ); |
460 | 530 | for( gdf::uint32 e=0; e<num_ev; e++ ) |
461 | 531 | { |
462 | 532 | gdf::Mode3Event event; |
463 | evh->getEvent( e, event ); | |
533 | //evh->getEvent( e, event ); | |
534 | event = ev3[e]; | |
464 | 535 | positions[e] = event.position; |
465 | 536 | types[e] = event.type; |
466 | 537 | channels[e] = event.channel; |
468 | 539 | } |
469 | 540 | } break; |
470 | 541 | } |
542 | verboseMessage( V_FUNCTION_CALLS, "leaving CmexObject::loadEvents( );"); | |
471 | 543 | } |
472 | 544 | |
473 | 545 | // =========================================================================== |
474 | 546 | |
475 | 547 | void CmexObject::constructHeader( gdf::Reader &reader ) |
476 | 548 | { |
549 | verboseMessage( V_FUNCTION_CALLS, "entering CmexObject::constructHeader( );"); | |
477 | 550 | plhs_[1] = constructHeaderStruct( num_signals ); |
478 | 551 | |
479 | 552 | Header2Struct( plhs_[1], &reader.getHeaderAccess_readonly() ); |
553 | verboseMessage( V_FUNCTION_CALLS, "leaving CmexObject::constructHeader( );"); | |
480 | 554 | } |
481 | 555 | |
482 | 556 | // =========================================================================== |
483 | 557 | |
484 | 558 | void CmexObject::parseInputArguments( ) |
485 | 559 | { |
560 | verboseMessage( V_FUNCTION_CALLS, "entering CmexObject::parseInputArguments( );"); | |
486 | 561 | using boost::lexical_cast; |
487 | 562 | |
488 | 563 | filename = mx::getString( prhs_[0] ); |
541 | 616 | else |
542 | 617 | throw invalid_argument( " Unknown Data Orientation: '"+arg+"'" ); |
543 | 618 | } |
619 | else if( opt == OPTION_CONVERTEVENTS ) | |
620 | { | |
621 | convert_events = true; | |
622 | } | |
544 | 623 | } catch( mx::Exception &e ) |
545 | 624 | { |
546 | 625 | throw invalid_argument( " While parsing argument "+lexical_cast<string>(n+1)+": "+e.what() ); |
547 | 626 | } |
548 | 627 | } |
628 | verboseMessage( V_FUNCTION_CALLS, "leaving CmexObject::parseInputArguments( );"); | |
629 | } | |
630 | ||
631 | // =========================================================================== | |
632 | ||
633 | void CmexObject::verboseMessage( int level, std::string message ) | |
634 | { | |
635 | #ifdef VERBOSE | |
636 | if( level <= verbose_level ) | |
637 | mexPrintf( ( "%d : " + message + "\n").c_str(), level ); | |
638 | #endif //VERBOSE | |
549 | 639 | } |
550 | 640 | |
551 | 641 | // =========================================================================== |
36 | 36 | % "DATAORIENTATION" wether channels should be arranged in rows or columns |
37 | 37 | % "COL" (default) each signal is a column vector. |
38 | 38 | % "ROW" each signal is a row vector. |
39 | % | |
40 | % "FORCEMODE3EVENTS" events are converted to mode 3. |
194 | 194 | w->createSignal( channel, true ); |
195 | 195 | plhs[0] = mxCreateNumericMatrix( 1, 1, mxUINT64_CLASS, mxREAL ); |
196 | 196 | *reinterpret_cast<size_t*>(mxGetData( plhs[0] )) = channel + 1; |
197 | ||
197 | ||
198 | 198 | w->getSignalHeader(channel).set_datatype( type ); |
199 | w->getSignalHeader(channel).set_samplerate( fs ); | |
199 | w->getSignalHeader(channel).set_samplerate( fs ); | |
200 | 200 | } |
201 | 201 | |
202 | 202 | void CMD_recduration::execute( mxArray ** /*plhs[]*/, const mxArray *prhs[] ) |
293 | 293 | gdf::uint16 type = mx::getNumeric<gdf::uint16>( prhs[2] ); |
294 | 294 | gdf::uint16 chan = mx::getNumeric<gdf::uint16>( prhs[3] ); |
295 | 295 | gdf::uint32 dur = mx::getNumeric<gdf::uint32>( prhs[4] ); |
296 | w->addEvent( pos, type, chan-1, dur ); | |
296 | w->addEvent( pos, type, chan, dur ); | |
297 | 297 | } |
298 | 298 | |
299 | 299 | void CMD_open::execute( mxArray ** /*plhs*/, const mxArray *prhs[] ) |
Binary diff not shown
35 | 35 | target_link_libraries( testRWConsistency ${Boost_LIBRARIES} GDF ) |
36 | 36 | add_test( NAME testRWConsistency COMMAND testRWConsistency ) |
37 | 37 | |
38 | add_executable( testDataTypes testDataTypes.cpp ) | |
39 | target_link_libraries( testDataTypes ${Boost_LIBRARIES} GDF ) | |
40 | add_test( NAME testDataTypes COMMAND testDataTypes ) | |
38 | 41 | |
39 | 42 | #add_custom_target( buildtests DEPENDS testCreateGDF testRWConsistency ) |
40 | 43 | #add_custom_target( check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS buildtests ) |
20 | 20 | ../../libgdf/src/EventHeader.cpp \ |
21 | 21 | ../../libgdf/src/Reader.cpp \ |
22 | 22 | ../../libgdf/src/Types.cpp \ |
23 | ../../libgdf/src/Modifier.cpp | |
23 | ../../libgdf/src/Modifier.cpp \ | |
24 | ../../libgdf/src/EventConverter.cpp | |
24 | 25 | HEADERS += ../../libgdf/include/GDF/Types.h \ |
25 | 26 | ../../libgdf/include/GDF/SignalHeader.h \ |
26 | 27 | ../../libgdf/include/GDF/Exceptions.h \ |
38 | 39 | ../../libgdf/include/GDF/EventHeader.h \ |
39 | 40 | ../../libgdf/include/GDF/Reader.h \ |
40 | 41 | ../../libgdf/include/GDF/Modifier.h \ |
41 | ../../libgdf/include/GDF/pointerpool.h | |
42 | ../../libgdf/include/GDF/pointerpool.h \ | |
43 | ../../libgdf/include/GDF/EventConverter.h |
0 | // | |
1 | // This file is part of libGDF. | |
2 | // | |
3 | // libGDF is free software: you can redistribute it and/or modify | |
4 | // it under the terms of the GNU Lesser General Public License as | |
5 | // published by the Free Software Foundation, either version 3 of | |
6 | // the License, or (at your option) any later version. | |
7 | // | |
8 | // libGDF is distributed in the hope that it will be useful, | |
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | // GNU Lesser General Public License for more details. | |
12 | // | |
13 | // You should have received a copy of the GNU Lesser General Public License | |
14 | // along with libGDF. If not, see <http://www.gnu.org/licenses/>. | |
15 | // | |
16 | // Copyright 2012 Martin Billinger | |
17 | ||
18 | #include "config-tests.h" | |
19 | ||
20 | #include <GDF/Reader.h> | |
21 | ||
22 | #include <iostream> | |
23 | #include <stdio.h> | |
24 | #include <sys/stat.h> | |
25 | ||
26 | #include <boost/numeric/conversion/cast.hpp> | |
27 | ||
28 | using namespace std; | |
29 | ||
30 | const string reffile = string(GDF_SOURCE_ROOT)+"/sampledata/alltypes.gdf"; | |
31 | ||
32 | // 512 Bytes of text which is coded in the file | |
33 | const string text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed elit massa, mattis vitae pretium a, congue et nisi. Duis quis sollicitudin turpis. Proin eget erat ac nulla adipiscing gravida. Proin eget pharetra felis. In posuere risus sed leo ultricies fermentum. Etiam eu justo elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque id erat diam, eget fermentum est. Etiam in nisl vel lectus ornare porta. Aenean quam est, rutrum ac sollicitudin eu, volutpat non enim. Morbi lacus lorem cras amet."; | |
34 | ||
35 | int main( ) | |
36 | { | |
37 | try | |
38 | { | |
39 | cout << "Creating Reader instance." << endl; | |
40 | gdf::Reader r; | |
41 | ||
42 | cout << "Opening '" << reffile << "' for reading." << endl; | |
43 | r.open( reffile ); | |
44 | ||
45 | size_t M = r.getMainHeader_readonly().get_num_signals(); | |
46 | if( M != 10 ) | |
47 | throw(std::invalid_argument("ERROR -- Wrong number of channels (expected 10).")); | |
48 | ||
49 | for( size_t i=0; i<M; i++ ) | |
50 | { | |
51 | for( size_t j=0; j<text.length(); j++ ) | |
52 | { | |
53 | double d = r.getSample( i, j ); | |
54 | char ch = boost::numeric_cast<char>( d ); | |
55 | cout << ch; | |
56 | if( ch != text[j] ) | |
57 | throw(std::invalid_argument("ERROR -- Wrong content.")); | |
58 | } | |
59 | cout << endl; | |
60 | cout << endl; | |
61 | } | |
62 | ||
63 | r.close( ); | |
64 | ||
65 | return 0; // test succeeded | |
66 | } | |
67 | catch( std::exception &e ) | |
68 | { | |
69 | std::cout << "Caught Exception: " << e.what( ) << endl; | |
70 | } | |
71 | catch( ... ) | |
72 | { | |
73 | std::cout << "Caught Unknown Exception." << endl; | |
74 | } | |
75 | ||
76 | return 1; // test failed | |
77 | } |