[med-svn] [SCM] aghermann branch, master, updated. c0bd21ca8eb529ade7e0c7aad22951a308a8dc8f
Andrei Zavada
johnhommer at gmail.com
Wed May 1 00:09:41 UTC 2013
The following commit has been merged in the master branch:
commit 9c29ce116297dfd1c3df27e380c76e99065dacae
Author: Andrei Zavada <johnhommer at gmail.com>
Date: Mon Apr 29 01:30:13 2013 +0300
libsigfile/channel overhaul
diff --git a/src/libsigfile/channel.cc b/src/libsigfile/channel.cc
index bad547c..c7c8e69 100644
--- a/src/libsigfile/channel.cc
+++ b/src/libsigfile/channel.cc
@@ -10,79 +10,115 @@
*/
+#include <map>
+#include <vector>
#include "channel.hh"
using namespace std;
+using sigfile::SChannel;
+const char* sigfile::edf_annotations_label =
+ "EDF Annotations";
-const char* sigfile::SChannel::system1020_channels[sigfile::SChannel::n_channels] = { // counted 'em all!
- "Nz",
- "Fp1", "Fpz", "Fp2",
- "AF7", "AF3", "AFz", "AF4", "AF8",
- "F9", "F7", "F5", "F3", "F1", "Fz", "F2", "F4", "F6", "F8", "F10",
- "FT9", "FT7", "FC5", "FC3", "FC1", "FCz", "FC2", "FC4", "FC6", "FCT8", "FT10",
- "A1", "T9", "T7", "C5", "C3", "C1", "Cz", "C2", "C4", "C6", "T8", "T10", "A2",
- "TP9", "TP7", "CP5", "CP3", "CP1", "CPz", "CP2", "CP4", "CP6", "TP8", "TP10",
- "P9", "P7", "P5", "P3", "P1", "Pz", "P2", "P4", "P6", "P8", "P10",
- "PO7", "PO3", "POz", "PO4", "PO8",
- "O1", "Oz", "O2",
- "Iz",
- // plus a few channels of other signal types
- "Left", "Right",
- "Chin",
+
+namespace {
+
+const map<SChannel::TType, vector<const char*>> _CT_ = {
+ {SChannel::TType::eeg,
+ {"(custom)", // counted 'em all!
+ "Nz",
+ "Fp1", "Fpz", "Fp2",
+ "AF7", "AF3", "AFz", "AF4", "AF8",
+ "F9", "F7", "F5", "F3", "F1", "Fz", "F2", "F4", "F6", "F8", "F10",
+ "FT9", "FT7", "FC5", "FC3", "FC1", "FCz", "FC2", "FC4", "FC6", "FCT8", "FT10",
+ "A1", "T9", "T7", "C5", "C3", "C1", "Cz", "C2", "C4", "C6", "T8", "T10", "A2",
+ "TP9", "TP7", "CP5", "CP3", "CP1", "CPz", "CP2", "CP4", "CP6", "TP8", "TP10",
+ "P9", "P7", "P5", "P3", "P1", "Pz", "P2", "P4", "P6", "P8", "P10",
+ "PO7", "PO3", "POz", "PO4", "PO8",
+ "O1", "Oz", "O2",
+ "Iz",}
+ },
+ {SChannel::TType::eog,
+ {"(invalid)",
+ "Left", "Right",}
+ },
+ {SChannel::TType::emg,
+ {"(invalid)",
+ "Chin",}
+ },
};
+const map<SChannel::TType, const char*> _ST_ = {
+ {SChannel::TType::embedded_annotation, sigfile::edf_annotations_label},
+ {SChannel::TType::eeg, "EEG"},
+ {SChannel::TType::eog, "EOG"},
+ {SChannel::TType::emg, "EMG"},
+ {SChannel::TType::ecg, "ECG"},
+ {SChannel::TType::erg, "ERG"},
+ {SChannel::TType::nc , "NC" },
+ {SChannel::TType::meg, "MEG"},
+ {SChannel::TType::mcg, "MCG"},
+ {SChannel::TType::ep , "EP" },
+ {SChannel::TType::temp, "Temp"},
+ {SChannel::TType::resp, "Resp"},
+ {SChannel::TType::sao2, "SaO2"},
+ {SChannel::TType::light, "Light"},
+ {SChannel::TType::sound, "Sound"},
+ {SChannel::TType::event, "Event"},
+ {SChannel::TType::freq, "Freq"},
+ {SChannel::TType::other, "(other)"},
+};
+} // anonymous namespace
-const char* sigfile::SChannel::kemp_signal_types[sigfile::SChannel::n_kemp_signal_types] = {
- "EDF Annotations",
- "EEG", "EOG", "EMG", "ECG", "ERG",
- "NC", "MEG", "MCG", "EP",
- "Temp", "Resp", "SaO2",
- "Light", "Sound", "Event", "Freq",
- "(unknown)"
-};
+const char*
+SChannel::
+type_s( SChannel::TType t)
+{
+ return _ST_.at(t);
+}
-sigfile::SChannel::TType
-sigfile::SChannel::
-signal_type_of_channel( const string& signal)
+template <SChannel::TType t>
+const char*
+SChannel::
+channel_s( int idx)
{
- size_t h = 0;
- for ( ; h <= last_eeg_no; ++h )
- if ( signal == system1020_channels[h] )
- return TType::eeg;
- for ( ; h <= last_eog_no; ++h )
- if ( signal == system1020_channels[h] )
- return TType::eog;
- for ( ; h <= last_emg_no; ++h )
- if ( signal == system1020_channels[h] )
- return TType::emg;
- return TType::other;
+ return _CT_.at(t)[idx];
}
+namespace sigfile {
+template <>
+const char*
+SChannel::
+channel_s<SChannel::TType::invalid>(int)
+{
+ return "(invalid)";
+}
+}
+
+template const char* SChannel::channel_s<SChannel::TType::eeg>( int);
+template const char* SChannel::channel_s<SChannel::TType::eog>( int);
+template const char* SChannel::channel_s<SChannel::TType::emg>( int);
+template const char* SChannel::channel_s<SChannel::TType::ecg>( int);
+template const char* SChannel::channel_s<SChannel::TType::erg>( int);
+
+
-bool
-__attribute__ ((pure))
-sigfile::
-SChannel::operator<( const SChannel& rv) const
+tuple<SChannel::TType, int>
+figure_type_and_name( const string& h)
{
- size_t ai = 0, bi = 0;
- while ( ai < n_channels && strcmp( c_str(), system1020_channels[ai]) )
- ++ai;
- while ( bi < n_channels && strcmp( rv.c_str(), system1020_channels[bi]) )
- ++bi;
- if ( ai < n_channels && bi < n_channels ) // both are vlaid 10-20 ones: compare by index
- return (ai < bi);
- else if ( ai < n_channels ) // whichever is good, wins
- return false;
- else if ( bi < n_channels )
- return true;
- else
- return strcmp( c_str(), rv.c_str()) < 0;
+ for ( auto& T : _CT_ )
+ for ( size_t i = 0; i < T.second.size(); ++i )
+ if ( 0 == strcasecmp( h.c_str(), T.second[i]) )
+ return make_tuple(T.first, (int)i);
+ return make_tuple(SChannel::TType::invalid, -1);
}
+
+
+
// Local Variables:
// Mode: c++
// indent-tabs-mode: 8
diff --git a/src/libsigfile/channel.hh b/src/libsigfile/channel.hh
index 41ffc08..9883cc4 100644
--- a/src/libsigfile/channel.hh
+++ b/src/libsigfile/channel.hh
@@ -4,7 +4,7 @@
* Author: Andrei Zavada <johnhommer at gmail.com>
* Initial version: 2011-11-10
*
- * Purpose: a string-based class representing a biosig channel
+ * Purpose: representation of a biosig channel
*
* License: GPL
*/
@@ -13,7 +13,7 @@
#define _SIGFILE_CHANNEL_H
#include <cstring>
-#include <array>
+#include <tuple>
#include <string>
#if HAVE_CONFIG_H && !defined(VERSION)
@@ -25,62 +25,158 @@ using namespace std;
namespace sigfile {
-struct SChannel
- : public string {
- template <typename T>
- SChannel (const T& h)
- : string (h)
- {}
- SChannel ()
- {}
- bool follows_system1020() const
- {
- return channel_follows_system1020( c_str());
- }
- bool operator<( const SChannel& rv) const;
+// we want scoped enums with basic arith support, so:
+namespace EEG {
+enum E : int {
+ invalid = -1,
+ custom = 0,
+ first,
+
+ Nz = first,
+ Fp1, Fpz, Fp2,
+ AF7, AF3, AFz, AF4, AF8,
+ F9, F7, F5, F3, F1, Fz, F2, F4, F6, F8, F10,
+ FT9, FT7, FC5, FC3, FC1, FCz, FC2, FC4, FC6, FCT8, FT10,
+ A1, T9, T7, C5, C3, C1, Cz, C2, C4, C6, T8, T10, A2,
+ TP9, TP7, CP5, CP3, CP1, CPz, CP2, CP4, CP6, TP8, TP10,
+ P9, P7, P5, P3, P1, Pz, P2, P4, P6, P8, P10,
+ PO7, PO3, POz, PO4, PO8,
+ O1, Oz, O2,
+ Iz,
+
+ last = Iz,
+ total
+};
+}
+
+namespace EOG {
+enum E : int {
+ invalid = -1,
+ custom = 0,
+ first,
+ left = first, right,
+ last = right,
+ total
+};
+}
+
+namespace EMG {
+enum E : int {
+ invalid = -1,
+ custom = 0,
+ first,
+ chin = first,
+ last = chin,
+ total
+};
+}
+
+namespace ECG {
+enum E : int {
+ invalid = -1,
+ custom = 0,
+ total
+};
+}
+
+namespace ERG {
+enum E : int {
+ invalid = -1,
+ custom = 0,
+ total
+};
+}
+// moar types ...
+
+
+extern const char* edf_annotations_label;
+
- // static members
- enum TType : int {
+struct SChannel {
+
+ enum class TType {
+ invalid,
embedded_annotation,
eeg, eog, emg, ecg, erg,
nc, meg, mcg, ep, temp, resp, sao2, light, sound, event, freq,
other
};
- static const size_t n_channels = 78;
- static const size_t last_eeg_no = 74;
- static const size_t last_eog_no = 76;
- static const size_t last_emg_no = 77;
- static const size_t n_kemp_signal_types = 18;
- static const char* system1020_channels[n_channels];
- static const char* kemp_signal_types[n_kemp_signal_types];
- static bool channel_follows_system1020( const char* channel)
+
+ static const char* type_s( TType t);
+
+ template <TType T>
+ static const char* channel_s( int);
+
+ static tuple<TType, int> figure_type_and_name( const string&);
+
+ static bool is_fftable( TType type)
{
- for ( auto &I : system1020_channels )
- if ( strcmp( channel, I) == 0 )
- return true;
- return false;
+ return type == TType::eeg;
+ }
+
+ // ctor
+ SChannel (const string& h)
+ {
+ tie(_type, _idx) = figure_type_and_name(h);
+ if ( _type == TType::invalid ) {
+ _type = TType::other;
+ _idx = 0; // custom
+ _custom_name = h;
+ }
}
- static TType figure_signal_type( const char* s)
+
+ template <TType T>
+ SChannel (int idx_)
+ : _type (T),
+ _idx (idx_)
+ {}
+
+ TType type() const
+ { return _type; }
+
+ const char* name() const
{
- for ( int i = 0; i < (int)n_kemp_signal_types; ++i )
- if ( strcasecmp( kemp_signal_types[i], s) == 0 )
- return (TType)i;
- return TType::other;
+ switch ( _type ) {
+ case TType::eeg: return channel_s<TType::eeg>( _idx);
+ case TType::eog: return channel_s<TType::eog>( _idx);
+ case TType::emg: return channel_s<TType::emg>( _idx);
+ case TType::ecg: return channel_s<TType::ecg>( _idx);
+ case TType::erg: return channel_s<TType::erg>( _idx);
+ default: return _custom_name.c_str();
+ }
}
- static TType signal_type_of_channel( const string&);
- static bool signal_type_is_fftable( const string& signal_type)
+
+ bool is_fftable()
{
- return signal_type == "EEG";
+ return is_fftable( _type);
+ }
+ private:
+ string _custom_name;
+ TType _type;
+ int _idx;
+
+ public:
+ // compares by channel actual locations, antero-posteriorly
+ bool operator<( const SChannel& rv) const
+ {
+ if ( _type == rv._type ) {
+ if ( _idx > 0 && rv._idx > 0 )
+ return _idx < rv._idx;
+ else if ( _idx > 0 )
+ return true;
+ else
+ return _custom_name < rv._custom_name;
+ } else
+ return _type < rv._type;
}
- static bool signal_type_is_fftable( TType signal_type)
+ bool operator==( const SChannel& rv) const
{
- return signal_type == TType::eeg;
+ return _type == rv._type && _idx == rv._idx;
}
- static bool channel_is_fftable( const string& H)
+ bool operator==( const char* rv) const
{
- return signal_type_is_fftable(
- signal_type_of_channel(H));
+ return 0 == strcasecmp( name(), rv);
}
};
--
Sleep experiment manager
More information about the debian-med-commit
mailing list