[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