[med-svn] [SCM] aghermann branch, master, updated. c82713d122d2da093d06c17695194ca6240e923d

Andrei Zavada johnhommer at gmail.com
Fri Nov 30 01:26:16 UTC 2012


The following commit has been merged in the master branch:
commit c82713d122d2da093d06c17695194ca6240e923d
Author: Andrei Zavada <johnhommer at gmail.com>
Date:   Fri Nov 30 03:26:00 2012 +0200

    profile metrics overhaul part 2/2

diff --git a/data/dialogs.glade b/data/dialogs.glade
index 896e04b..9ca2873 100644
--- a/data/dialogs.glade
+++ b/data/dialogs.glade
@@ -377,7 +377,7 @@
                         <property name="ypad">10</property>
                         <property name="label" translatable="yes"><big><b>Aghermann</b> is a sleep-research experiment manager with capable scoring facility; PSD and EEG Microcontinuity sleep profiles; artifact detection; Independent Component Analysis; and Process S simulation following <a href="http://dx.doi.org/10.1016/0361-9230(93)90016-5">Achermann et al, 1993</a> (in <a href="http://dissertations.ub.rug.nl/faculties/science/2007/a.zavada/">this interpretation</a>).</big>
 
-Aghermann is developed by Andrei Zavada <a href="mailto:johnhommer at gmail.com">johnhommer at gmail.com</a> and distributed under GPL-2+.
+<big><b>Aghermann</b> is developed by Andrei Zavada <a href="mailto:johnhommer at gmail.com">johnhommer at gmail.com</a> and distributed under GPL-2+.</big>
 
 With bug reports, either send yours to <a href="mailto:aghermann-users at lists.sourceforge.net">aghermann-users at lists.sourceforge.net</a>, or open an issue on <a href="http://github.com/hmmr/aghermann/issues">http://github.com/hmmr/aghermann/issues</a>.</property>
                         <property name="use_markup">True</property>
@@ -594,7 +594,7 @@ With bug reports, either send yours to <a href="mailto:aghermann-users at lists.
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="xalign">1</property>
-                    <property name="label" translatable="yes">Freq. range:</property>
+                    <property name="label" translatable="yes">Freq:</property>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
diff --git a/data/main.glade b/data/main.glade
index 9b24e11..d00cbe4 100644
--- a/data/main.glade
+++ b/data/main.glade
@@ -348,6 +348,12 @@
     <property name="step_increment">0.10000000000000001</property>
     <property name="page_increment">0.5</property>
   </object>
+  <object class="GtkAdjustment" id="jMsmtProfileParamsMCF0">
+    <property name="upper">20</property>
+    <property name="value">0.5</property>
+    <property name="step_increment">0.5</property>
+    <property name="page_increment">1</property>
+  </object>
   <object class="GtkAdjustment" id="jMsmtProfileParamsPSDFreqFrom">
     <property name="upper">60</property>
     <property name="value">2</property>
@@ -361,6 +367,12 @@
     <property name="step_increment">0.25</property>
     <property name="page_increment">1</property>
   </object>
+  <object class="GtkAdjustment" id="jMsmtProfileParamsSWUF0">
+    <property name="upper">20</property>
+    <property name="value">0.5</property>
+    <property name="step_increment">0.5</property>
+    <property name="page_increment">1</property>
+  </object>
   <object class="GtkAdjustment" id="jMsmtProfileSmooth">
     <property name="upper">8</property>
     <property name="value">2</property>
@@ -840,7 +852,7 @@ rm */*/*/.*.{psd,mc}</property>
                                         <property name="can_focus">False</property>
                                         <property name="valign">center</property>
                                         <property name="xalign">1</property>
-                                        <property name="label" translatable="yes">@ </property>
+                                        <property name="label" translatable="yes">freq range: </property>
                                         <property name="use_underline">True</property>
                                       </object>
                                       <packing>
@@ -949,13 +961,56 @@ rm */*/*/.*.{psd,mc}</property>
                                     <property name="can_focus">False</property>
                                     <property name="valign">center</property>
                                     <child>
-                                      <placeholder/>
+                                      <object class="GtkLabel" id="label10">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="valign">center</property>
+                                        <property name="xalign">1</property>
+                                        <property name="label" translatable="yes"><i>f</i><sub>0</sub>: </property>
+                                        <property name="use_markup">True</property>
+                                        <property name="use_underline">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">0</property>
+                                      </packing>
                                     </child>
                                     <child>
-                                      <placeholder/>
+                                      <object class="GtkSpinButton" id="eMsmtProfileParamsMCF0">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="valign">center</property>
+                                        <property name="has_frame">False</property>
+                                        <property name="invisible_char">•</property>
+                                        <property name="width_chars">5</property>
+                                        <property name="xalign">1</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="adjustment">jMsmtProfileParamsMCF0</property>
+                                        <property name="digits">2</property>
+                                        <property name="numeric">True</property>
+                                        <property name="update_policy">if-valid</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">1</property>
+                                      </packing>
                                     </child>
                                     <child>
-                                      <placeholder/>
+                                      <object class="GtkLabel" id="label11">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="valign">center</property>
+                                        <property name="label" translatable="yes">Hz</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">2</property>
+                                      </packing>
                                     </child>
                                     <child>
                                       <placeholder/>
@@ -993,13 +1048,56 @@ rm */*/*/.*.{psd,mc}</property>
                                     <property name="can_focus">False</property>
                                     <property name="valign">center</property>
                                     <child>
-                                      <placeholder/>
+                                      <object class="GtkLabel" id="label12">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="valign">center</property>
+                                        <property name="xalign">1</property>
+                                        <property name="label" translatable="yes"><i>f</i><sub>0</sub>: </property>
+                                        <property name="use_markup">True</property>
+                                        <property name="use_underline">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">0</property>
+                                      </packing>
                                     </child>
                                     <child>
-                                      <placeholder/>
+                                      <object class="GtkSpinButton" id="eMsmtProfileParamsSWUF0">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="valign">center</property>
+                                        <property name="has_frame">False</property>
+                                        <property name="invisible_char">•</property>
+                                        <property name="width_chars">5</property>
+                                        <property name="xalign">1</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="adjustment">jMsmtProfileParamsSWUF0</property>
+                                        <property name="digits">2</property>
+                                        <property name="numeric">True</property>
+                                        <property name="update_policy">if-valid</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">1</property>
+                                      </packing>
                                     </child>
                                     <child>
-                                      <placeholder/>
+                                      <object class="GtkLabel" id="label13">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="valign">center</property>
+                                        <property name="label" translatable="yes">Hz</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">2</property>
+                                      </packing>
                                     </child>
                                     <child>
                                       <placeholder/>
@@ -1423,18 +1521,6 @@ rm */*/*/.*.{psd,mc}</property>
                                   <placeholder/>
                                 </child>
                                 <child>
-                                  <placeholder/>
-                                </child>
-                                <child>
-                                  <placeholder/>
-                                </child>
-                                <child>
-                                  <placeholder/>
-                                </child>
-                                <child>
-                                  <placeholder/>
-                                </child>
-                                <child>
                                   <object class="GtkFrame" id="fFreqConventionalRanges">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
@@ -6694,6 +6780,12 @@ dragging individual signals with <i>Alt</i>.</small></property
                                     <child>
                                       <placeholder/>
                                     </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
                                   </object>
                                 </child>
                                 <child>
diff --git a/src/Makefile.am b/src/Makefile.am
index 9aff71e..1a36f97 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
 SUBDIRS := \
 	common sigproc ica libsigfile \
-	metrics model \
-	expdesign \
+	metrics \
+	expdesign model \
 	ui \
 	tools
 
diff --git a/src/common/alg.hh b/src/common/alg.hh
index 7e494a7..d692698 100644
--- a/src/common/alg.hh
+++ b/src/common/alg.hh
@@ -141,6 +141,25 @@ value_within( const T& v, const T& l, const T& h)
 
 
 
+inline valarray<double>
+to_vad( valarray<double>&& rv)
+{
+	return move(rv);
+}
+
+inline valarray<double>
+to_vad( const valarray<float>& rv)
+{
+	valarray<double> ret;
+	ret.resize( rv.size());
+	for ( size_t i = 0; i < rv.size(); ++i )
+		ret[i] = rv[i];
+	return ret;
+}
+
+
+
+
 inline float
 __attribute__ ((pure))
 calibrate_display_scale( const valarray<TFloat>& signal,
diff --git a/src/common/lang.hh b/src/common/lang.hh
index eb0e204..23d5d50 100644
--- a/src/common/lang.hh
+++ b/src/common/lang.hh
@@ -18,6 +18,7 @@
 #endif
 
 #include <unistd.h>
+#include <cassert>
 #include <memory>
 
 using namespace std;
@@ -31,8 +32,8 @@ using namespace std;
 // # define __used		__attribute__ ((used))
 // # define __unused		__attribute__ ((unused))
 // # define __packed		__attribute__ ((packed))
-# define likely(x)	__builtin_expect (!!(x), 1)
-# define unlikely(x)	__builtin_expect (!!(x), 0)
+#define likely(x)	__builtin_expect (!!(x), 1)
+#define unlikely(x)	__builtin_expect (!!(x), 0)
 
 
 #define	DEF_UNIQUE_CHARP(p)				\
@@ -44,6 +45,9 @@ using namespace std;
 	T (const T&) = delete;			\
 	void operator=( const T&) = delete;
 
+#define ASPRINTF(...) \
+	assert (asprintf(__VA_ARGS__) > 0)
+
 typedef unsigned long hash_t;
 
 #endif
diff --git a/src/expdesign/Makefile.am b/src/expdesign/Makefile.am
index 0e42578..743de78 100644
--- a/src/expdesign/Makefile.am
+++ b/src/expdesign/Makefile.am
@@ -12,11 +12,13 @@ liba_a_SOURCES := \
 	primaries.cc \
 	primaries.hh \
 	recording.cc \
-	recording.hh
+	recording.hh \
+	profile.hh
 
 if DO_PCH
 BUILT_SOURCES := \
 	forward-decls.hh.gch \
+	profile.hh.gch \
 	recording.hh.gch \
 	primaries.hh.gch
 %.hh.gch: %.hh
diff --git a/src/expdesign/forward-decls.hh b/src/expdesign/forward-decls.hh
index 06b0f1e..7ce9fc9 100644
--- a/src/expdesign/forward-decls.hh
+++ b/src/expdesign/forward-decls.hh
@@ -21,8 +21,8 @@ class CJGroup;
 class CExpDesign;
 
 class CRecording;
-struct SSCourseParamSet;
-class CSCourse;
+struct SProfileParamSet;
+class CProfile;
 
 } // namespace agh
 
diff --git a/src/expdesign/loadsave.cc b/src/expdesign/loadsave.cc
index e297e8c..3df1e5b 100644
--- a/src/expdesign/loadsave.cc
+++ b/src/expdesign/loadsave.cc
@@ -15,10 +15,10 @@
 #include <fcntl.h>
 
 #include <memory>
-#include "primaries.hh"
-#include "../model/achermann.hh"
 
-#include "../common/config-validate.hh"
+#include "common/config-validate.hh"
+#include "primaries.hh"
+#include "model/achermann.hh"
 
 
 using namespace std;
diff --git a/src/expdesign/primaries.cc b/src/expdesign/primaries.cc
index 5f65150..4cdb220 100644
--- a/src/expdesign/primaries.cc
+++ b/src/expdesign/primaries.cc
@@ -39,36 +39,38 @@ CExpDesign (const string& session_dir_,
 	tunables0 (tstep, tlo, thi),
 	_id_pool (0),
 	config_keys_g ({
-		confval::SValidator<double>("ctlparam.StepSize",	&ctl_params0.siman_params.step_size),
-		confval::SValidator<double>("ctlparam.Boltzmannk",	&ctl_params0.siman_params.k,			confval::SValidator<double>::SVFRangeEx( DBL_MIN, 1e9)),
-		confval::SValidator<double>("ctlparam.TInitial",	&ctl_params0.siman_params.t_initial,		confval::SValidator<double>::SVFRangeEx( DBL_MIN, 1e9)),
-		confval::SValidator<double>("ctlparam.DampingMu",	&ctl_params0.siman_params.mu_t,			confval::SValidator<double>::SVFRangeEx( DBL_MIN, 1e9)),
-		confval::SValidator<double>("ctlparam.TMin",		&ctl_params0.siman_params.t_min,		confval::SValidator<double>::SVFRangeEx( DBL_MIN, 1e9)),
-		confval::SValidator<double>("ctlparam.ReqScoredPC",	&ctl_params0.req_percent_scored,		confval::SValidator<double>::SVFRangeIn( 80., 100.)),
-		confval::SValidator<double>("fftparam.BinSize",		&fft_params.binsize,				confval::SValidator<double>::SVFRangeIn( .125, 1.)),
+		confval::SValidator<double>("ctl_param.StepSize",	&ctl_params0.siman_params.step_size),
+		confval::SValidator<double>("ctl_param.Boltzmannk",	&ctl_params0.siman_params.k,			confval::SValidator<double>::SVFRangeEx( DBL_MIN, 1e9)),
+		confval::SValidator<double>("ctl_param.TInitial",	&ctl_params0.siman_params.t_initial,		confval::SValidator<double>::SVFRangeEx( DBL_MIN, 1e9)),
+		confval::SValidator<double>("ctl_param.DampingMu",	&ctl_params0.siman_params.mu_t,			confval::SValidator<double>::SVFRangeEx( DBL_MIN, 1e9)),
+		confval::SValidator<double>("ctl_param.TMin",		&ctl_params0.siman_params.t_min,		confval::SValidator<double>::SVFRangeEx( DBL_MIN, 1e9)),
+		confval::SValidator<double>("profile.ReqScoredPC",	&req_percent_scored,				confval::SValidator<double>::SVFRangeIn( 80., 100.)),
+		confval::SValidator<double>("fft_param.BinSize",	&fft_params.binsize,				confval::SValidator<double>::SVFRangeIn( .125, 1.)),
 		confval::SValidator<double>("artifacts.DampenFactor",	&af_dampen_factor,				confval::SValidator<double>::SVFRangeIn( 0., 1.)),
-		confval::SValidator<double>("mcparam.mc_gain",		&mc_params.mc_gain,				confval::SValidator<double>::SVFRangeIn( 0., 100.)),
-		confval::SValidator<double>("mcparam.f0fc",		&mc_params.f0fc,				confval::SValidator<double>::SVFRangeEx( 0., 80.)),
-		confval::SValidator<double>("mcparam.bandwidth",	&mc_params.bandwidth,				confval::SValidator<double>::SVFRangeIn( 0.125, 2.)),
-		confval::SValidator<double>("mcparam.iir_backpolate",	&mc_params.iir_backpolate,			confval::SValidator<double>::SVFRangeIn( 0., 1.)),
+		confval::SValidator<double>("mc_param.mc_gain",		&mc_params.mc_gain,				confval::SValidator<double>::SVFRangeIn( 0., 100.)),
+		confval::SValidator<double>("mc_param.f0fc",		&mc_params.f0fc,				confval::SValidator<double>::SVFRangeEx( 0., 80.)),
+		confval::SValidator<double>("mc_param.bandwidth",	&mc_params.bandwidth,				confval::SValidator<double>::SVFRangeIn( 0.125, 2.)),
+		confval::SValidator<double>("mc_param.iir_backpolate",	&mc_params.iir_backpolate,			confval::SValidator<double>::SVFRangeIn( 0., 1.)),
 	}),
 	config_keys_d ({
 		confval::SValidator<int>("smp.num_threads",		&num_threads,					confval::SValidator<int>::SVFRangeIn( 0, 20)),
-		confval::SValidator<int>("fftparam.WelchWindowType",	(int*)&fft_params.welch_window_type,		confval::SValidator<int>::SVFRangeIn( 0, (int)sigproc::TWinType::_total - 1)),
+		confval::SValidator<int>("fft_param.WelchWindowType",	(int*)&fft_params.welch_window_type,		confval::SValidator<int>::SVFRangeIn( 0, (int)sigproc::TWinType::_total - 1)),
 		confval::SValidator<int>("artifacts.DampenWindowType",	(int*)&af_dampen_window_type,			confval::SValidator<int>::SVFRangeIn( 0, (int)sigproc::TWinType::_total - 1)),
-		confval::SValidator<int>("ctlparam.ItersFixedT",	&ctl_params0.siman_params.iters_fixed_T,	confval::SValidator<int>::SVFRangeIn( 1, 1000000)),
-		confval::SValidator<int>("ctlparam.NTries",		&ctl_params0.siman_params.n_tries,		confval::SValidator<int>::SVFRangeIn( 1, 10000)),
-		confval::SValidator<int>("ctlparam.NSWALadenPagesBeforeSWA0",
-					 				(int*)&ctl_params0.swa_laden_pages_before_SWA_0,confval::SValidator<size_t>::SVFRangeIn( 1, 100)),
-		confval::SValidator<int>("fftparam.PageSize",		(int*)&fft_params.pagesize,		confval::SValidator<size_t>::SVFRangeIn( 4, 120)),
-		confval::SValidator<int>("mcparam.SmoothSide",		(int*)&mc_params.smooth_side,		confval::SValidator<size_t>::SVFRangeIn( 0, 5)),
+		confval::SValidator<int>("ctl_param.ItersFixedT",	&ctl_params0.siman_params.iters_fixed_T,	confval::SValidator<int>::SVFRangeIn( 1, 1000000)),
+		confval::SValidator<int>("ctl_param.NTries",		&ctl_params0.siman_params.n_tries,		confval::SValidator<int>::SVFRangeIn( 1, 10000)),
+		confval::SValidator<int>("profile.swa_laden_pages_before_SWA_0",
+					 				(int*)&swa_laden_pages_before_SWA_0,
+					 										confval::SValidator<size_t>::SVFRangeIn( 1, 100)),
+		confval::SValidator<int>("fftparam.PageSize",		(int*)&fft_params.pagesize,			confval::SValidator<size_t>::SVFRangeIn( 4, 120)),
+		confval::SValidator<int>("mcparam.SmoothSide",		(int*)&mc_params.smooth_side,			confval::SValidator<size_t>::SVFRangeIn( 0, 5)),
 	}),
 	config_keys_b ({
-		confval::SValidator<bool>("ctlparam.DBAmendment1",		&ctl_params0.DBAmendment1),
-		confval::SValidator<bool>("ctlparam.DBAmendment2",		&ctl_params0.DBAmendment2),
-		confval::SValidator<bool>("ctlparam.AZAmendment1",		&ctl_params0.AZAmendment1),
-		confval::SValidator<bool>("ctlparam.AZAmendment2",		&ctl_params0.AZAmendment2),
-		confval::SValidator<bool>("ctlparam.ScoreUnscoredAsWake",	&ctl_params0.ScoreUnscoredAsWake),
+		confval::SValidator<bool>("ctl_param.DBAmendment1",	&ctl_params0.DBAmendment1),
+		confval::SValidator<bool>("ctl_param.DBAmendment2",	&ctl_params0.DBAmendment2),
+		confval::SValidator<bool>("ctl_param.AZAmendment1",	&ctl_params0.AZAmendment1),
+		confval::SValidator<bool>("ctl_param.AZAmendment2",	&ctl_params0.AZAmendment2),
+		confval::SValidator<bool>("profile.score_unscored_as_wake",
+					  				&score_unscored_as_wake),
 	})
 {
 	char *tmp = canonicalize_file_name(session_dir_.c_str());
@@ -226,24 +228,21 @@ for_all_modruns( const TModelRunOpFun& F, const TModelRunReportFun& report, cons
 	vector<tuple<CJGroup*,
 		     CSubject*,
 		     const string*,
-		     const metrics::TType*,
+		     const SProfileParamSet*,
 		     const string*,
-		     const pair<float,float>*,
 		     ach::CModelRun*>> v;
 	for ( auto& G : groups )
 		for ( auto& J : G.second )
 			for ( auto& D : J.measurements )
 				for ( auto& T : D.second.modrun_sets )
 					for ( auto& H : T.second )
-						for ( auto& Q : H.second )
-							if ( filter(Q.second) )
-								v.emplace_back(
-									make_tuple (
-										&G.second, &J, &D.first,
-										&T.first,
-										&H.first,
-										&Q.first,
-										&Q.second));
+						if ( filter(H.second) )
+							v.emplace_back(
+								make_tuple (
+									&G.second, &J, &D.first,
+									&T.first,
+									&H.first,
+									&H.second));
 	size_t global_i = 0;
 #ifdef _OPENMP
 #pragma omp parallel for schedule(guided)
@@ -253,10 +252,10 @@ for_all_modruns( const TModelRunOpFun& F, const TModelRunReportFun& report, cons
 #pragma omp critical
 #endif
 		{
-			report( *get<0>(v[i]), *get<1>(v[i]), *get<2>(v[i]), *get<3>(v[i]), *get<4>(v[i]), *get<5>(v[i]), *get<6>(v[i]),
+			report( *get<0>(v[i]), *get<1>(v[i]), *get<2>(v[i]), *get<3>(v[i]), *get<4>(v[i]), *get<5>(v[i]),
 				++global_i, v.size());
 		}
-		F( *get<6>(v[i]));
+		F( *get<5>(v[i]));
 	}
 }
 
@@ -482,20 +481,13 @@ remove_untried_modruns()
 			for ( auto &D : J.measurements )
 			retry_modruns:
 				for ( auto RSt = D.second.modrun_sets.begin(); RSt != D.second.modrun_sets.end(); ++RSt )
-					for ( auto RSi = RSt->second.begin(); RSi != RSt->second.end(); ++RSi ) {
-					retry_this_modrun_set:
-						for ( auto Ri = RSi->second.begin(); Ri != RSi->second.end(); ++Ri ) {
-							// printf( "#----- check Subject: %s;  Session: %s;  Channel: %s;  Range: %g-%g Hz (%d)\n",
-							// 	Ri->second.subject(), Ri->second.session(), Ri->second.channel(),
-							// 	Ri->second.freq_from(), Ri->second.freq_upto(),
-							// 	Ri->second.status);
-							if ( !(Ri->second.status & ach::CModelRun::modrun_tried) ) {
-								RSi->second.erase( Ri);
-								goto retry_this_modrun_set;
-							}
-						}
-						if ( RSi->second.empty() ) {
-							D.second.modrun_sets.erase( RSt);
+					for ( auto Ri = RSt->second.begin(); Ri != RSt->second.end(); ++Ri ) {
+						// printf( "#----- check Subject: %s;  Session: %s;  Channel: %s;  Range: %g-%g Hz (%d)\n",
+						// 	Ri->second.subject(), Ri->second.session(), Ri->second.channel(),
+						// 	Ri->second.freq_from(), Ri->second.freq_upto(),
+						// 	Ri->second.status);
+						if ( !(Ri->second.status & ach::CModelRun::modrun_tried) ) {
+							RSt->second.erase( Ri);
 							goto retry_modruns;
 						}
 					}
@@ -530,18 +522,32 @@ export_all_modruns( const string& fname) const
 		for ( auto &J : G.second )
 			for ( auto &D : J.measurements )
 				for ( auto &RS : D.second.modrun_sets )
-					for ( auto &Q : RS.second )
-						for ( auto &R : Q.second )
-							if ( R.second.status & ach::CModelRun::modrun_tried ) {
-								fprintf( f, "# ----- Subject: %s;  Session: %s;  Channel: %s;  Range: %g-%g Hz\n",
-									 R.second.subject(), R.second.session(), R.second.channel(),
-									 R.second.freq_from(), R.second.freq_upto());
-								t = ach::TTunable::rs;
-								do {
-									fprintf( f, "%g%s", R.second.tx[t] * ach::stock[t].display_scale_factor,
-										 (t < R.second.tx.size()-1) ? "\t" : "\n");
-								} while ( t++ < R.second.tx.size()-1 );
+					for ( auto &R : RS.second )
+						if ( R.second.status & ach::CModelRun::modrun_tried ) {
+							auto& M = R.second;
+							DEF_UNIQUE_CHARP (extra);
+							switch ( M.P().metric ) {
+							case metrics::TType::psd:
+								ASPRINTF( &extra, "%g-%g Hz", M.P().P.psd.freq_from, M.P().P.psd.freq_upto);
+								break;
+							case metrics::TType::swu:
+								ASPRINTF( &extra, "%g Hz", M.P().P.swu.f0);
+								break;
+							case metrics::TType::mc:
+								ASPRINTF( &extra, "%g Hz", M.P().P.mc.f0);
+								break;
+							default:
+								throw runtime_error ("What metric?");
 							}
+							fprintf( f, "# ----- Subject: %s;  Session: %s;  Channel: %s;  Metric: %s (%s)\n",
+								 M.subject(), M.session(), M.channel(),
+								 M.P().metric_name(), extra);
+							t = ach::TTunable::rs;
+							do {
+								fprintf( f, "%g%s", M.tx[t] * ach::stock[t].display_scale_factor,
+									 (t < M.tx.size()-1) ? "\t" : "\n");
+							} while ( t++ < M.tx.size()-1 );
+						}
 
 	fclose( f);
 }
diff --git a/src/expdesign/primaries.hh b/src/expdesign/primaries.hh
index f4cba26..dd52f41 100644
--- a/src/expdesign/primaries.hh
+++ b/src/expdesign/primaries.hh
@@ -29,8 +29,6 @@
 #include "recording.hh"
 #include "forward-decls.hh"
 
-//#include "ui/forward-decls.hh"
-
 #if HAVE_CONFIG_H && !defined(VERSION)
 #  include "config.h"
 #endif
@@ -51,7 +49,7 @@ class CSubject {
 
     public:
 	enum class TGender : char {
-		neuter = 'o', male   = 'M', female = 'F'
+		neuter = 'o', male = 'M', female = 'F'
 	};
 	static const char* gender_sign( TGender g);
 
@@ -146,7 +144,7 @@ class CSubject {
 
 	class SEpisodeSequence {
 		friend class agh::CExpDesign;
-		friend class agh::CSCourse;
+		friend class agh::CProfile;
 	    public:
 		list<SEpisode> episodes;
 		size_t
@@ -196,10 +194,9 @@ class CSubject {
 			 float max_hours_apart = 7*24.);
 
 	      // simulations rather belong here
-		typedef map<metrics::TType,
+		typedef map<SProfileParamSet,
 			    map<string, // channel
-				map< pair<float, float>,  // frequency range
-				     ach::CModelRun>>>
+				ach::CModelRun>>
 			TModrunSetMap;
 		TModrunSetMap
 			modrun_sets;  // a bunch (from, to) per each fftable channel
@@ -312,16 +309,16 @@ class CExpDesign {
 	TJGroups
 		groups;
 	template <typename T>
-	bool have_group( const T& g) const;
+	bool have_group( const T&) const;
 
 	template <class T>
-	CSubject& subject_by_x( const T& jid);
+	CSubject& subject_by_x( const T&);
 
 	template <class T>
-	const CSubject& subject_by_x( const T& jid,
+	const CSubject& subject_by_x( const T&,
 				      TJGroups::const_iterator *Giter_p = nullptr) const;
 	template <class T>
-	const char* group_of( const T& jid);
+	const char* group_of( const T&);
 
       // add subject to group; if he exists in another group, remove him therefrom first;
       // if he is already there, update his record
@@ -345,13 +342,12 @@ class CExpDesign {
 
     public:
       // edf sources
-	int register_intree_source( sigfile::CSource &&F,
+	int register_intree_source( sigfile::CSource&&,
 				    const char **reason_if_failed_p = nullptr);
 
       // model runs
 	int setup_modrun( const char* j, const char* d, const char* h,
-			  metrics::TType,
-			  float freq_from, float freq_upto,
+			  const SProfileParamSet&,
 			  ach::CModelRun**);
 	void remove_all_modruns();
 	void remove_untried_modruns();
@@ -412,9 +408,8 @@ class CExpDesign {
 	typedef function<void(const CJGroup&,
 			      const CSubject&,
 			      const string&,
-			      const metrics::TType&,
+			      const SProfileParamSet&,
 			      const string&,
-			      const pair<float,float>&,
 			      const ach::CModelRun&,
 			      size_t, size_t)>
 		TModelRunReportFun;
@@ -442,6 +437,9 @@ class CExpDesign {
 
 	ach::SControlParamSet
 		ctl_params0;
+	double	req_percent_scored;
+	size_t	swa_laden_pages_before_SWA_0;
+	bool	score_unscored_as_wake;
 
 	int load_settings();
 	int save_settings();
diff --git a/src/expdesign/profile.hh b/src/expdesign/profile.hh
new file mode 100644
index 0000000..7294e7a
--- /dev/null
+++ b/src/expdesign/profile.hh
@@ -0,0 +1,173 @@
+// ;-*-C++-*-
+/*
+ *       File name:  expdesign/profile.hh
+ *         Project:  Aghermann
+ *          Author:  Andrei Zavada <johnhommer at gmail.com>
+ * Initial version:  2012-11-24
+ *
+ *         Purpose:  A list of CRecording's
+ *
+ *         License:  GPL
+ */
+
+
+#ifndef _AGH_EXPDESIGN_PROFILE_H
+#define _AGH_EXPDESIGN_PROFILE_H
+
+#include "recording.hh"
+
+namespace agh {
+
+using namespace std;
+
+
+
+
+class CProfile
+  : private SProfileParamSet {
+
+    public:
+	CProfile (CRecording&,
+		  const SProfileParamSet&);
+	CProfile (CSubject&, const string& d, const sigfile::SChannel& h,
+		  const SProfileParamSet&);
+	void create_timeline( const SProfileParamSet& params)
+		{
+			*(SProfileParamSet*)this = params;
+			create_timeline();
+		}
+	void create_timeline();
+
+	const SProfileParamSet& P() const
+					{ return *this; }
+	size_t sim_start() const	{ return _sim_start; }
+	size_t sim_end() const		{ return _sim_end; }
+	size_t baseline_end() const	{ return _baseline_end; }
+	size_t pages_with_swa() const	{ return _pages_with_SWA; }
+	size_t pages_non_wake() const	{ return _pages_non_wake; }
+	size_t pages_in_bed() const	{ return _pages_in_bed; }
+	double SWA_L() const		{ return _SWA_L; }
+	double SWA_0() const		{ return _SWA_0; }
+	double SWA_100() const		{ return _SWA_100; }
+	double metric_avg() const	{ return _metric_avg; }
+
+	const vector<sigfile::SPageSimulated>&
+	timeline() const		{ return _timeline; }
+
+	typedef pair<size_t, size_t> TBounds;
+	const vector<TBounds>&
+	mm_bounds() const		{ return _mm_bounds; }
+
+	const vector<CRecording*>&
+	mm_list() 			{ return _mm_list; }
+
+	const sigfile::SPageSimulated&
+	operator[]( size_t p) const
+		{
+			return _timeline[p];
+		}
+
+	time_t nth_episode_start_time( size_t n) const;
+	time_t nth_episode_end_time( size_t n) const;
+	size_t nth_episode_start_page( size_t n) const;
+	size_t nth_episode_end_page( size_t n) const;
+
+	size_t pagesize() const
+		{
+			return _pagesize;
+		}
+
+	const char* subject() const;
+	const char* session() const;
+	const char* channel() const;
+
+	enum TFlags {
+		ok			= 0,
+		enoscore		= 1,
+		efarapart		= 2,
+		esigtype		= 4,
+		etoomanymsmt		= 8,
+		enoswa			= 16,
+		eamendments_ineffective	= 32,
+		ers_nonsensical		= 64,
+		enegoffset		= 128,
+		euneq_pagesize		= 256
+	};
+
+	static string explain_status( int);
+
+    protected:
+	int	_status;
+
+	CProfile (const CProfile&) = delete;
+	CProfile ()
+		{
+			throw runtime_error ("nono");
+		}
+	CProfile (CProfile&& rv);
+
+	size_t	_sim_start,
+		_sim_end,
+		_baseline_end,
+		_pages_with_SWA,
+		_pages_non_wake,
+		_pages_in_bed;
+	double	_SWA_L,
+		_SWA_0,	_SWA_100,
+		_metric_avg;
+
+	time_t	_0at;
+	vector<sigfile::SPageSimulated>
+		_timeline;
+	vector<TBounds>  // in pages
+		_mm_bounds;
+
+	vector<CRecording*>
+		_mm_list;
+    private:
+	size_t	_pagesize;  // since power is binned each time it is
+			    // collected in layout_measurements() and
+			    // then detached, we keep it here
+			    // privately
+};
+
+
+
+
+inline const char* CProfile::subject() const { return _mm_list.front()->subject(); }
+inline const char* CProfile::session() const { return _mm_list.front()->session(); }
+inline const char* CProfile::channel() const { return _mm_list.front()->channel(); }
+
+
+inline time_t
+CProfile::nth_episode_start_time( size_t n) const
+{
+	return _0at + _mm_bounds[n].first * _pagesize;
+}
+
+inline time_t
+CProfile::nth_episode_end_time( size_t n) const
+{
+	return _0at + _mm_bounds[n].second * _pagesize;
+}
+
+inline size_t
+CProfile::nth_episode_start_page( size_t n) const
+{
+	return _mm_bounds[n].first;
+}
+
+inline size_t
+CProfile::nth_episode_end_page( size_t n) const
+{
+	return _mm_bounds[n].second;
+}
+
+
+
+
+} // namespace agh
+
+#endif
+
+// eof
diff --git a/src/expdesign/recording.cc b/src/expdesign/recording.cc
index fc9ff7c..c97cabb 100644
--- a/src/expdesign/recording.cc
+++ b/src/expdesign/recording.cc
@@ -15,6 +15,7 @@
 
 #include "recording.hh"
 #include "primaries.hh"
+#include "model/beersma.hh"
 
 using namespace std;
 
@@ -27,7 +28,7 @@ CRecording (sigfile::CSource& F, int sig_no,
       : psd_profile (F, sig_no, fft_params),
         swu_profile (F, sig_no, swu_params),
 	mc_profile  (F, sig_no, mc_params),
-	uc_params {NAN, NAN, NAN, NAN},
+	uc_params (nullptr),
 	_status (0), // not computed
 	_source (F), _sig_no (sig_no)
 {
@@ -38,9 +39,35 @@ CRecording (sigfile::CSource& F, int sig_no,
 }
 
 
+agh::CRecording::
+~CRecording ()
+{
+	if ( uc_params )
+		delete uc_params;
+}
+
+
+
+
+
+
+string
+agh::SProfileParamSet::
+display_name() const
+{
+	DEF_UNIQUE_CHARP (_);
+	switch ( metric ) {
+	case metrics::TType::psd: ASPRINTF( &_, "%s (%g-%g Hz)", metric_name(), P.psd.freq_from, P.psd.freq_upto); break;
+	case metrics::TType::swu: ASPRINTF( &_, "%s (%g Hz)",    metric_name(), P.swu.f0); break;
+	case metrics::TType::mc : ASPRINTF( &_, "%s (%g Hz)",    metric_name(), P.mc.f0); break;
+	default: ASPRINTF( &_, "(invalid metric: %d)", metric); break;
+	}
+	string ret {_};
+	return ret;
+}
 
 string
-agh::CSCourse::
+agh::CProfile::
 explain_status( int code)
 {
 	list<const char*> ss;
@@ -70,10 +97,10 @@ explain_status( int code)
 
 
 
-agh::CSCourse::
-CSCourse (CSubject& J, const string& d, const sigfile::SChannel& h,
-	  const SSCourseParamSet& params)
-      : SSCourseParamSet (params),
+agh::CProfile::
+CProfile (CSubject& J, const string& d, const sigfile::SChannel& h,
+	  const SProfileParamSet& params)
+      : SProfileParamSet (params),
 	_status (0),
 	_sim_start ((size_t)-1), _sim_end ((size_t)-1)
 {
@@ -102,12 +129,12 @@ CSCourse (CSubject& J, const string& d, const sigfile::SChannel& h,
 //			pz = (size_t)difftime( F.end_time(), _0at) / _pagesize;
 			pz = pa + F.length_in_seconds() / _pagesize;
 	      // anchor zero page, get pagesize from edf^W CBinnedPower^W either goes
-		printf( "CSCourse::CSCourse(): adding %s of [%s, %s, %s] %zu pages (%d indeed) recorded %s",
-			metrics::metric_method(params._profile_type), F.subject(), F.session(), F.episode(),
+		printf( "CProfile::CProfile(): adding %s of [%s, %s, %s] %zu pages (%d indeed) recorded %s",
+			metrics::name(params.metric), F.subject(), F.session(), F.episode(),
 			F.pages(), pz-pa, ctime( &F.start_time()));
 
 		if ( pz - pa != (int)F.pages() ) {
-			fprintf( stderr, "CSCourse::CSCourse(): correcting end page to match page count in EDF: %d->%zu\n",
+			fprintf( stderr, "CProfile::CProfile(): correcting end page to match page count in EDF: %d->%zu\n",
 				 pz, pa + F.pages());
 			pz = pa + F.pages();
 		}
@@ -130,21 +157,21 @@ CSCourse (CSubject& J, const string& d, const sigfile::SChannel& h,
 	create_timeline();
 
 	if ( _sim_start != (size_t)-1 )
-		printf( "CSCourse::CSCourse(): sim start-end: %zu-%zu; avg SWA = %.4g (over %zu pp, or %.3g%% of all time in bed); "
+		printf( "CProfile::CProfile(): sim start-end: %zu-%zu; avg SWA = %.4g (over %zu pp, or %.3g%% of all time in bed); "
 			" SWA_L = %g;  SWA[%zu] = %g\n",
 			_sim_start, _sim_end, _SWA_100, _pages_with_SWA, (double)_pages_with_SWA / _pages_in_bed * 100,
 			_SWA_L, _sim_start, _SWA_0);
 	else
-		printf( "CSCourse::CSCourse(): status %xd, %s\n", _status, CSCourse::explain_status( _status).c_str());
+		printf( "CProfile::CProfile(): status %xd, %s\n", _status, CProfile::explain_status( _status).c_str());
 }
 
 
 
 
-agh::CSCourse::
-CSCourse (CRecording& M,
-	  const SSCourseParamSet& params)
-      : SSCourseParamSet (params),
+agh::CProfile::
+CProfile (CRecording& M,
+	  const SProfileParamSet& params)
+      : SProfileParamSet (params),
 	_status (0),
 	_sim_start ((size_t)-1), _sim_end ((size_t)-1)
 {
@@ -156,12 +183,12 @@ CSCourse (CRecording& M,
 
 	int	pa = (size_t)difftime( M.F().start_time(), _0at) / _pagesize,
 		pz = (size_t)difftime( M.F().end_time(), _0at) / _pagesize;
-	printf( "CSCourse::CSCourse(): adding single recording %s of [%s, %s, %s] %zu pages (%d indeed) recorded %s",
-		metrics::metric_method(params._profile_type), M.F().subject(), M.F().session(), M.F().episode(),
+	printf( "CProfile::CProfile(): adding single recording %s of [%s, %s, %s] %zu pages (%d indeed) recorded %s",
+		metrics::name(params.metric), M.F().subject(), M.F().session(), M.F().episode(),
 		M.F().pages(), pz-pa, ctime( &M.F().start_time()));
 
 	if ( pz - pa != (int)M.F().pages() ) {
-		fprintf( stderr, "CSCourse::CSCourse(): correct end page to match page count in EDF: %d->%zu\n",
+		fprintf( stderr, "CProfile::CProfile(): correct end page to match page count in EDF: %d->%zu\n",
 			 pz, pa + M.F().pages());
 		pz = pa + M.F().pages();
 	}
@@ -183,20 +210,20 @@ CSCourse (CRecording& M,
 	create_timeline();
 
 	if ( _sim_start != (size_t)-1 )
-		printf( "CSCourse::CSCourse(): sim start-end: %zu-%zu; avg SWA = %.4g (over %zu pp, or %.3g%% of all time in bed); "
+		printf( "CProfile::CProfile(): sim start-end: %zu-%zu; avg SWA = %.4g (over %zu pp, or %.3g%% of all time in bed); "
 			" SWA_L = %g;  SWA[%zu] = %g\n",
 			_sim_start, _sim_end, _SWA_100, _pages_with_SWA, (double)_pages_with_SWA / _pages_in_bed * 100,
 			_SWA_L, _sim_start, _SWA_0);
 	else
-		printf( "CSCourse::CSCourse(): status %xd, %s\n", _status, CSCourse::explain_status( _status).c_str());
+		printf( "CProfile::CProfile(): status %xd, %s\n", _status, CProfile::explain_status( _status).c_str());
 }
 
 
 
 
-agh::CSCourse::
-CSCourse( CSCourse&& rv)
-      : SSCourseParamSet (rv),
+agh::CProfile::
+CProfile (CProfile&& rv)
+      : SProfileParamSet (rv),
 	_sim_start (rv._sim_start), _sim_end (rv._sim_end),
 	_baseline_end (rv._baseline_end),
 	_pages_with_SWA (rv._pages_with_SWA),
@@ -214,7 +241,7 @@ CSCourse( CSCourse&& rv)
 
 
 void
-agh::CSCourse::
+agh::CProfile::
 create_timeline()
 {
 	_metric_avg = 0.;
@@ -222,12 +249,12 @@ create_timeline()
 		auto& M = **Mi;
 		const auto& F = M.F();
 
-		if ( F.percent_scored() < _req_percent_scored )
+		if ( F.percent_scored() < req_percent_scored )
 			_status |= TFlags::enoscore;
 
 	      // collect M's power and scores
 		valarray<TFloat>
-			lumped_bins = M.course<TFloat>( _profile_type, _freq_from, _freq_upto);
+			lumped_bins = M.course( *(SProfileParamSet*)this);
 
 		size_t	pa = (size_t)difftime( F.start_time(), _0at) / _pagesize,
 			pz = (size_t)difftime( F.end_time(), _0at) / _pagesize;
@@ -235,7 +262,7 @@ create_timeline()
 			_timeline[p] = sigfile::SPageSimulated {F[p-pa]};
 		      // fill unscored/MVT per user setting
 			if ( !_timeline[p].is_scored() ) {
-				if ( _ScoreUnscoredAsWake )
+				if ( score_unscored_as_wake )
 					_timeline[p].mark( sigfile::SPage::TScore::wake);
 				else
 					if ( p > 0 )
@@ -257,7 +284,7 @@ create_timeline()
 						p = pp;
 						goto outer_continue;
 					}
-					if ( (pp-p) >= _swa_laden_pages_before_SWA_0 ) {
+					if ( (pp-p) >= swa_laden_pages_before_SWA_0 ) {
 						_sim_start = pp;
 						goto outer_break;
 					}
diff --git a/src/expdesign/recording.hh b/src/expdesign/recording.hh
index 9d1d1c1..ef01396 100644
--- a/src/expdesign/recording.hh
+++ b/src/expdesign/recording.hh
@@ -14,17 +14,125 @@
 #ifndef _AGH_EXPDESIGN_RECORDING_H
 #define _AGH_EXPDESIGN_RECORDING_H
 
+#include <cstdarg>
 #include "libsigfile/source.hh"
 #include "metrics/psd.hh"
 #include "metrics/swu.hh"
 #include "metrics/mc.hh"
-#include "model/beersma.hh"
-#include "expdesign/forward-decls.hh"
+#include "model/forward-decls.hh"
+#include "forward-decls.hh"
 
 namespace agh {
 
 using namespace std;
 
+
+struct SProfileParamSet {
+	metrics::TType
+		metric;
+	const char*
+	metric_name() const
+		{
+			return metrics::name(metric);
+		}
+
+	struct PSD {
+		double	freq_from,
+			freq_upto;
+	};
+	struct MC {
+		double	f0;
+	};
+	struct SWU {
+		double	f0;
+	};
+
+	union {
+		PSD psd;
+		MC  mc;
+		SWU swu;
+	} P;
+
+	double	req_percent_scored;
+	size_t	swa_laden_pages_before_SWA_0;
+	bool	score_unscored_as_wake;
+
+	SProfileParamSet (const SProfileParamSet::PSD& psd_,
+			  double req_percent_scored_ = 90.,
+			  size_t swa_laden_pages_before_SWA_0_ = 3,
+			  bool	score_unscored_as_wake_ = true)
+	      : metric (metrics::TType::psd),
+		req_percent_scored (req_percent_scored_),
+		swa_laden_pages_before_SWA_0 (swa_laden_pages_before_SWA_0_),
+		score_unscored_as_wake (score_unscored_as_wake_)
+		{
+			P.psd = psd_;
+		}
+	SProfileParamSet (const SProfileParamSet::SWU& swu_,
+			  double req_percent_scored_ = 90.,
+			  size_t swa_laden_pages_before_SWA_0_ = 3,
+			  bool	score_unscored_as_wake_ = true)
+	      : metric (metrics::TType::swu),
+		req_percent_scored (req_percent_scored_),
+		swa_laden_pages_before_SWA_0 (swa_laden_pages_before_SWA_0_),
+		score_unscored_as_wake (score_unscored_as_wake_)
+		{
+			P.swu = swu_;
+		}
+	SProfileParamSet (const SProfileParamSet::MC& mc_,
+			  double req_percent_scored_ = 90.,
+			  size_t swa_laden_pages_before_SWA_0_ = 3,
+			  bool	score_unscored_as_wake_ = true)
+	      : metric (metrics::TType::mc),
+		req_percent_scored (req_percent_scored_),
+		swa_laden_pages_before_SWA_0 (swa_laden_pages_before_SWA_0_),
+		score_unscored_as_wake (score_unscored_as_wake_)
+		{
+			P.mc = mc_;
+		}
+
+	string display_name() const;
+
+	// silly stl requirements
+	SProfileParamSet ()
+		{} // if initialised as part of a class with us as base, exception already thrown by those
+	bool operator<( const SProfileParamSet&) const
+		{
+			return false;
+		}
+};
+
+template<metrics::TType t>
+SProfileParamSet
+make_profile_paramset(double, ...);
+
+template<>
+inline SProfileParamSet
+make_profile_paramset<metrics::TType::psd>(double freq_from, ...)
+{
+	va_list ap;
+	va_start (ap, freq_from);
+	double freq_upto = va_arg (ap, double);
+	va_end (ap);
+	return SProfileParamSet (SProfileParamSet::PSD {freq_from, freq_upto});
+}
+
+template<>
+inline SProfileParamSet
+make_profile_paramset<metrics::TType::swu>(double f0, ...)
+{
+	return SProfileParamSet (SProfileParamSet::SWU {f0});
+}
+
+template<>
+inline SProfileParamSet
+make_profile_paramset<metrics::TType::mc>(double f0, ...)
+{
+	return SProfileParamSet (SProfileParamSet::MC {f0});
+}
+
+
+
 class CRecording {
 
 	CRecording () = delete;
@@ -35,8 +143,7 @@ class CRecording {
 	      : psd_profile (rv.psd_profile),
 		swu_profile (rv.swu_profile),
 		mc_profile  (rv.mc_profile),
-		uc_params (rv.uc_params),
-		uc_cf (rv.uc_cf),
+		uc_params (nullptr),
 		_status (rv._status),
 		_source (rv._source),
 		_sig_no (rv._sig_no)
@@ -45,11 +152,13 @@ class CRecording {
 		    const metrics::psd::SPPack&,
 		    const metrics::swu::SPPack&,
 		    const metrics::mc::SPPack&);
+       ~CRecording ();
 
 	const char* subject() const      {  return _source.subject(); }
 	const char* session() const      {  return _source.session(); }
 	const char* episode() const      {  return _source.episode(); }
 	const char* channel() const      {  return _source.channel_by_id(_sig_no); }
+
 	sigfile::SChannel::TType signal_type() const
 		{
 			return _source.signal_type(_sig_no);
@@ -101,10 +210,29 @@ class CRecording {
 			return _source.recording_time() * _source.samplerate(_sig_no);
 		}
 
-	template <typename T>
-	valarray<T>
-	course( metrics::TType metric,
-		double freq_from, double freq_upto);
+	valarray<TFloat>
+	course( const SProfileParamSet::PSD&);
+
+	valarray<TFloat>
+	course( const SProfileParamSet::SWU&);
+
+	valarray<TFloat>
+	course( const SProfileParamSet::MC&);
+
+	valarray<TFloat>
+	course( const SProfileParamSet& P)
+		{
+			switch ( P.metric ) {
+			case metrics::TType::psd:
+				return course( P.P.psd);
+			case metrics::TType::swu:
+				return course( P.P.swu);
+			case metrics::TType::mc:
+				return course( P.P.mc);
+			default:
+				throw runtime_error ("What metric?");
+			}
+		}
 
 	metrics::psd::CProfile psd_profile;
 	metrics::swu::CProfile swu_profile;
@@ -112,10 +240,10 @@ class CRecording {
 
 	bool have_uc_determined() const
 		{
-			return isfinite(uc_params.r);
+			return uc_params and isfinite(uc_cf);
 		}
 	agh::beersma::SUltradianCycle
-		uc_params;
+		*uc_params;
 	double	uc_cf;
 
     protected:
@@ -131,185 +259,31 @@ class CRecording {
 
 
 
-struct SSCourseParamSet {
-	metrics::TType
-		_profile_type;
-	double	_freq_from,
-		_freq_upto;
-	double	_req_percent_scored;
-	size_t	_swa_laden_pages_before_SWA_0;
-	bool	_ScoreUnscoredAsWake:1;
-};
-
-
-class CSCourse
-  : private SSCourseParamSet {
-
-    public:
-	CSCourse (CRecording&,
-		  const SSCourseParamSet& params);
-	CSCourse (CSubject&, const string& d, const sigfile::SChannel& h,
-		  const SSCourseParamSet& params);
-	void create_timeline( const SSCourseParamSet& params)
-		{
-			*(SSCourseParamSet*)this = params;
-			create_timeline();
-		}
-	void create_timeline();
-
-	metrics::TType profile_type() const
-					{ return _profile_type; }
-	double freq_from() const	{ return _freq_from; }
-	double freq_upto() const	{ return _freq_upto; }
-	size_t sim_start() const	{ return _sim_start; }
-	size_t sim_end() const		{ return _sim_end; }
-	size_t baseline_end() const	{ return _baseline_end; }
-	size_t pages_with_swa() const	{ return _pages_with_SWA; }
-	size_t pages_non_wake() const	{ return _pages_non_wake; }
-	size_t pages_in_bed() const	{ return _pages_in_bed; }
-	double SWA_L() const		{ return _SWA_L; }
-	double SWA_0() const		{ return _SWA_0; }
-	double SWA_100() const		{ return _SWA_100; }
-	double metric_avg() const	{ return _metric_avg; }
-
-	const vector<sigfile::SPageSimulated>&
-	timeline() const		{ return _timeline; }
-
-	typedef pair<size_t, size_t> TBounds;
-	const vector<TBounds>&
-	mm_bounds() const		{ return _mm_bounds; }
-
-	const vector<CRecording*>&
-	mm_list() 			{ return _mm_list; }
-
-	const sigfile::SPageSimulated&
-	operator[]( size_t p) const
-		{
-			return _timeline[p];
-		}
-
-	time_t nth_episode_start_time( size_t n) const;
-	time_t nth_episode_end_time( size_t n) const;
-	size_t nth_episode_start_page( size_t n) const;
-	size_t nth_episode_end_page( size_t n) const;
-
-	size_t pagesize() const
-		{
-			return _pagesize;
-		}
-	const char* subject() const;
-	const char* session() const;
-	const char* channel() const;
-
-	enum TFlags {
-		ok			= 0,
-		enoscore		= 1,
-		efarapart		= 2,
-		esigtype		= 4,
-		etoomanymsmt		= 8,
-		enoswa			= 16,
-		eamendments_ineffective	= 32,
-		ers_nonsensical		= 64,
-		enegoffset		= 128,
-		euneq_pagesize		= 256
-	};
-
-	static string explain_status( int);
-    protected:
-	int	_status;
-
-	CSCourse (const CSCourse&) = delete;
-	CSCourse ()
-		{} // easier than the default; not used anyway
-	CSCourse (CSCourse&& rv);
-
-	size_t	_sim_start,
-		_sim_end,
-		_baseline_end,
-		_pages_with_SWA,
-		_pages_non_wake,
-		_pages_in_bed;
-	double	_SWA_L,
-		_SWA_0,	_SWA_100,
-		_metric_avg;
-
-	time_t	_0at;
-	vector<sigfile::SPageSimulated>
-		_timeline;
-	vector<TBounds>  // in pages
-		_mm_bounds;
-
-	vector<CRecording*>
-		_mm_list;
-    private:
-	size_t	_pagesize;  // since power is binned each time it is
-			    // collected in layout_measurements() and
-			    // then detached, we keep it here
-			    // privately
-};
-
-
-
-
-
-template <typename T>
-valarray<T>
+inline valarray<TFloat>
 CRecording::
-course( metrics::TType metric,
-	double freq_from, double freq_upto)
+course( const SProfileParamSet::PSD& p)
 {
-	using namespace metrics;
-	switch ( metric ) {
-	case TType::psd:
-		return (psd_profile.compute(),
-			psd_profile.course<T>( freq_from, freq_upto));
-	case TType::swu:
-		return (swu_profile.compute(),
-			swu_profile.course<T>());
-	case TType::mc:
-		return (mc_profile.compute(),
-			mc_profile.course<T>(
-				min( (size_t)((freq_from) / mc_profile.Pp.bandwidth),
-				     mc_profile.bins()-1)));
-	default:
-		throw invalid_argument ("CRecording::course: bad metric");
-	}
+	return (psd_profile.compute(),
+		psd_profile.course( p.freq_from, p.freq_upto));
 }
 
-
-inline const char* CSCourse::subject() const { return _mm_list.front()->subject(); }
-inline const char* CSCourse::session() const { return _mm_list.front()->session(); }
-inline const char* CSCourse::channel() const { return _mm_list.front()->channel(); }
-
-
-
-inline time_t
-CSCourse::nth_episode_start_time( size_t n) const
-{
-	return _0at + _mm_bounds[n].first * _pagesize;
-}
-
-inline time_t
-CSCourse::nth_episode_end_time( size_t n) const
-{
-	return _0at + _mm_bounds[n].second * _pagesize;
-}
-
-inline size_t
-CSCourse::nth_episode_start_page( size_t n) const
+inline valarray<TFloat>
+CRecording::
+course( const SProfileParamSet::SWU& p)
 {
-	return _mm_bounds[n].first;
+	return (swu_profile.compute(),
+		swu_profile.course( p.f0));
 }
 
-inline size_t
-CSCourse::nth_episode_end_page( size_t n) const
+inline valarray<TFloat>
+CRecording::
+course( const SProfileParamSet::MC& p)
 {
-	return _mm_bounds[n].second;
+	return (mc_profile.compute(),
+		mc_profile.course( p.f0));
 }
 
 
-
-
 } // namespace agh
 
 #endif
diff --git a/src/expdesign/tree-scanner.cc b/src/expdesign/tree-scanner.cc
index 02f4446..3361c3a 100644
--- a/src/expdesign/tree-scanner.cc
+++ b/src/expdesign/tree-scanner.cc
@@ -15,7 +15,7 @@
 #include <cassert>
 #include <string>
 
-#include "../common/alg.hh"
+#include "common/alg.hh"
 #include "primaries.hh"
 
 
@@ -192,8 +192,8 @@ register_intree_source( sigfile::CSource&& F,
 			J = &*Ji;
 
 	      // insert/update episode observing start/end times
-		// printf( "\nCExpDesign::register_intree_source( file: \"%s\", J: \"%s\", E: \"%s\", D: \"%s\")\n",
-		// 	   F.filename(), F.subject(), F.episode(), F.session());
+		printf( "\nCExpDesign::register_intree_source( file: \"%s\", J: \"%s\", E: \"%s\", D: \"%s\")\n",
+			   F.filename(), F.subject(), F.episode(), F.session());
 		switch ( J->measurements[F.session()].add_one(
 				 move(F), fft_params, swu_params, mc_params) ) {  // this will do it
 		case AGH_EPSEQADD_OVERLAP:
diff --git a/src/metrics/Makefile.am b/src/metrics/Makefile.am
index ed22f0e..df45792 100644
--- a/src/metrics/Makefile.am
+++ b/src/metrics/Makefile.am
@@ -16,7 +16,8 @@ liba_a_SOURCES := \
 	mc.cc \
 	mc.hh \
 	mc-artifacts.cc \
-	mc-artifacts.hh
+	mc-artifacts.hh \
+	mc-artifacts.ii
 
 if DO_PCH
 BUILT_SOURCES := \
diff --git a/src/metrics/mc-artifacts.cc b/src/metrics/mc-artifacts.cc
index 29aaed0..4764625 100644
--- a/src/metrics/mc-artifacts.cc
+++ b/src/metrics/mc-artifacts.cc
@@ -14,6 +14,7 @@
 #include <gsl/gsl_histogram.h>
 
 #include "common/lang.hh"
+#include "common/alg.hh"
 #include "sigproc/sigproc.hh"
 #include "mc.hh"
 #include "mc-artifacts.hh"
@@ -24,55 +25,16 @@
 
 using namespace std;
 
+template vector<size_t> metrics::mc::detect_artifacts( const valarray<TFloat>&, size_t, const SArtifactDetectionPP&);
 
-vector<size_t>
-metrics::mc::
-detect_artifacts( const valarray<TFloat>& signal, size_t sr,
-		  const SArtifactDetectionPP& P)
-{
-	auto	sssu
-		= CProfile::do_sssu_reduction(
-			signal,
-			sr, P.scope,
-			P.mc_gain, P.iir_backpolate,
-			P.f0, P.fc, P.bandwidth);
-	valarray<TFloat>
-		sssu_diff = {sssu.first - sssu.second};
-
-	sigproc::smooth( sssu_diff, P.smooth_side);
-
-	double E;
-	if ( P.estimate_E )
-		E = P.use_range
-			? estimate_E(
-				sssu_diff,
-				P.sssu_hist_size,
-				P.dmin, P.dmax)
-			: estimate_E(
-				sssu_diff,
-				P.sssu_hist_size);
-	else
-		E = P.E;
-
-	vector<size_t>
-		marked;
-	for ( size_t p = 0; p < sssu_diff.size(); ++p )
-		if ( sssu_diff[p] < E + E * P.lower_thr ||
-		     sssu_diff[p] > E + E * P.upper_thr ) {
-			marked.push_back(p);
-		}
-
-	return marked;
-}
+namespace metrics {
+namespace mc {
 
-
-
-
-TFloat
-metrics::mc::
-estimate_E( const valarray<TFloat>& sssu_diff,
+template <>
+double
+estimate_E( const valarray<double>& sssu_diff,
 	    size_t sssu_hist_size,
-	    TFloat dmin, TFloat dmax)
+	    double dmin, double dmax)
 {
 	gsl_histogram *hist = gsl_histogram_alloc( sssu_hist_size);
 	gsl_histogram_set_ranges_uniform( hist, dmin, dmax);
@@ -84,6 +46,16 @@ estimate_E( const valarray<TFloat>& sssu_diff,
 		* ((dmax-dmin) / sssu_hist_size);
 }
 
+template <>
+double
+estimate_E( const valarray<float>& S,
+	    size_t bins,
+	    double dmin, double dmax)
+{
+	return estimate_E( agh::alg::to_vad(S), bins, dmin, dmax);
+}
 
+} // namespace mc
+} // namespace metrics
 
 // eof
diff --git a/src/metrics/mc-artifacts.hh b/src/metrics/mc-artifacts.hh
index d2e04c1..8228ae8 100644
--- a/src/metrics/mc-artifacts.hh
+++ b/src/metrics/mc-artifacts.hh
@@ -16,7 +16,7 @@
 
 #include <vector>
 #include <valarray>
-#include "forward-decls.hh"
+#include "sigproc/sigproc.hh"
 
 #if HAVE_CONFIG_H && !defined(VERSION)
 #  include "config.h"
@@ -48,17 +48,21 @@ struct SArtifactDetectionPP {
 		{}
 };
 
-// artifacts (having sssu_diff outside thresholds * E), see paper pp 1190-1)
+template <typename T>
 vector<size_t> // don't estimate, use pi*B*x^2 (E) as provided
-detect_artifacts( const valarray<TFloat>&, size_t sr,
-		  const SArtifactDetectionPP&);
-TFloat
-estimate_E( const valarray<TFloat>&,
+detect_artifacts( const valarray<T>& signal, size_t sr,
+		  const SArtifactDetectionPP& P);
+
+
+template <typename T>
+double
+estimate_E( const valarray<T>&,
 	    size_t bins,
-	    TFloat dmin, TFloat dmax);
+	    double dmin, double dmax);
 
-inline TFloat
-estimate_E( const valarray<TFloat>& sssu_diff,
+template <typename T>
+inline double
+estimate_E( const valarray<T>& sssu_diff,
 	    size_t sssu_hist_size)
 {
 	return estimate_E( sssu_diff, sssu_hist_size,
@@ -66,6 +70,9 @@ estimate_E( const valarray<TFloat>& sssu_diff,
 }
 
 
+#include "mc-artifacts.ii"
+
+
 } // namespace mc
 } // namespace metrics
 
diff --git a/src/metrics/mc-artifacts.ii b/src/metrics/mc-artifacts.ii
new file mode 100644
index 0000000..96c713f
--- /dev/null
+++ b/src/metrics/mc-artifacts.ii
@@ -0,0 +1,57 @@
+// ;-*-C++-*-
+/*
+ *       File name:  metrics/mc-artifacts.ii
+ *         Project:  Aghermann
+ *          Author:  Andrei Zavada <johnhommer at gmail.com>
+ *
+ * Initial version:  2012-11-28
+ *
+ *         Purpose:  artifacts, MC-based (templates)
+ *
+ *         License:  GPL
+ */
+
+
+extern template vector<size_t> detect_artifacts( const valarray<TFloat>&, size_t, const SArtifactDetectionPP&);
+
+template <typename T>
+vector<size_t> // don't estimate, use pi*B*x^2 (E) as provided
+detect_artifacts( const valarray<T>& signal, size_t sr,
+		  const SArtifactDetectionPP& P)
+{
+	auto	sssu
+		= do_sssu_reduction(
+			signal,
+			sr, P.scope,
+			P.mc_gain, P.iir_backpolate,
+			P.f0, P.fc, P.bandwidth);
+	valarray<T>
+		sssu_diff = {sssu.first - sssu.second};
+
+	sigproc::smooth( sssu_diff, P.smooth_side);
+
+	double E;
+	if ( P.estimate_E )
+		E = P.use_range
+			? estimate_E(
+				sssu_diff,
+				P.sssu_hist_size,
+				P.dmin, P.dmax)
+			: estimate_E(
+				sssu_diff,
+				P.sssu_hist_size);
+	else
+		E = P.E;
+
+	vector<size_t>
+		marked;
+	for ( size_t p = 0; p < sssu_diff.size(); ++p )
+		if ( sssu_diff[p] < E + E * P.lower_thr ||
+		     sssu_diff[p] > E + E * P.upper_thr ) {
+			marked.push_back(p);
+		}
+
+	return marked;
+}
+
+// eof
diff --git a/src/metrics/mc.cc b/src/metrics/mc.cc
index ef2bcf0..faee459 100644
--- a/src/metrics/mc.cc
+++ b/src/metrics/mc.cc
@@ -44,6 +44,8 @@ reset()
 	iir_backpolate		=     0.5;	// 0.0 < Backpolate < 1.0 on s: standard 0.5
 	mc_gain			=    10.0;	// Gain (DigiRange/PhysiRange) of MicroContinuity
 	smooth_side		=     0;
+	freq_from		=     0.5;
+	freq_inc		=      .5;
 }
 
 
@@ -71,17 +73,16 @@ metrics::mc::CProfile::
 fname_base() const
 {
 	DEF_UNIQUE_CHARP (_);
-	assert (asprintf( &_,
-			  "%s.%s-%zu"
-			  ":%zu-%g_%g" "_%g" "_%g_%g",
-			  _using_F.filename(), _using_F.channel_by_id(_using_sig_no),
-			  _using_F.dirty_signature( _using_sig_no),
-			  Pp.pagesize,
-			  Pp.scope,
-			  Pp.iir_backpolate,
-			  Pp.mc_gain,
-			  Pp.f0fc, Pp.bandwidth)
-		> 1);
+	ASPRINTF( &_,
+		  "%s.%s-%zu"
+		  ":%zu-%g_%g" "_%g" "_%g_%g",
+		  _using_F.filename(), _using_F.channel_by_id(_using_sig_no),
+		  _using_F.dirty_signature( _using_sig_no),
+		  Pp.pagesize,
+		  Pp.scope,
+		  Pp.iir_backpolate,
+		  Pp.mc_gain,
+		  Pp.f0fc, Pp.bandwidth);
 	string ret {_};
 	return ret;
 }
@@ -92,18 +93,19 @@ mirror_fname() const
 {
 	DEF_UNIQUE_CHARP (_);
 	string basename_dot = agh::fs::make_fname_base (_using_F.filename(), "", true);
-	assert (asprintf( &_,
-			  "%s-%s-%zu"
-			  ":%zu-%g_%g" "_%g" "_%g_%g"
-			  ".mc",
-			  basename_dot.c_str(), _using_F.channel_by_id(_using_sig_no),
-			  _using_F.dirty_signature( _using_sig_no),
-			  Pp.pagesize,
-			  Pp.scope,
-			  Pp.iir_backpolate,
-			  Pp.mc_gain,
-			  Pp.f0fc, Pp.bandwidth)
-		> 1);
+	ASPRINTF( &_,
+		  "%s-%s-%zu"
+		  ":%zu-%g_%g" "_%g" "_%g_%g" "_%g_%g@%zu"
+		  ".mc",
+		  basename_dot.c_str(), _using_F.channel_by_id(_using_sig_no),
+		  _using_F.dirty_signature( _using_sig_no),
+		  Pp.pagesize,
+		  Pp.scope,
+		  Pp.iir_backpolate,
+		  Pp.mc_gain,
+		  Pp.f0fc, Pp.bandwidth,
+		  Pp.freq_from, Pp.freq_inc,
+		  sizeof(TFloat));
 	string ret {_};
 	return ret;
 }
@@ -113,18 +115,23 @@ metrics::mc::CProfile::
 go_compute()
 {
 	_data.resize( pages() * _bins);
-
 	auto S = _using_F.get_signal_filtered( _using_sig_no);
 	for ( size_t b = 0; b < bins(); ++b ) {
-		auto suss = do_sssu_reduction(
+		auto su_ss = metrics::mc::do_sssu_reduction(
 			S, samplerate(),
 			Pp.scope,
 			Pp.mc_gain, Pp.iir_backpolate,
-			Pp.freq_from + b * Pp.bandwidth,
-			Pp.freq_from + b * Pp.bandwidth + Pp.f0fc,
+			Pp.freq_from + b * Pp.freq_inc,
+			Pp.freq_from + b * Pp.freq_inc + Pp.f0fc,
 			Pp.bandwidth);
-		for ( size_t p = 0; p < pages(); ++p )
-			nmth_bin(p, b) = (suss.first[p] - suss.second[p]); // make it positive
+		auto suss = su_ss.second - su_ss.first;  // make it positive
+		printf( "pppp %zu %zu\n", pages(), suss.size());
+		// collapse into our pages
+		for ( size_t p = 0; p < pages(); ++p ) {
+			auto range = slice (p * Pp.scope, Pp.pagesize/Pp.scope, 1);
+			nmth_bin(p, b) =
+				suss[range].sum();
+		}
 	}
 
 	return 0;
@@ -135,54 +142,6 @@ go_compute()
 
 
 
-metrics::mc::CProfile::TSSSU
-metrics::mc::CProfile::
-do_sssu_reduction( const valarray<TFloat>& S,
-		   size_t samplerate, double scope,
-		   double mc_gain, double iir_backpolate,
-		   double f0, double fc,
-		   double bandwidth)
-{
-	sigproc::CFilterDUE
-		due_filter (samplerate, sigproc::CFilterIIR::TFilterDirection::forward,
-			    mc_gain, iir_backpolate,
-			    fc);
-	sigproc::CFilterSE
-		se_filter (samplerate, sigproc::CFilterIIR::TFilterDirection::forward,
-			   mc_gain, iir_backpolate,
-			   f0, fc,
-			   bandwidth);
-
-	size_t	integrate_samples = scope * samplerate,
-		pages = S.size() / integrate_samples;
-	valarray<TFloat>
-		due_filtered = due_filter.apply( S, false),
-		se_filtered  =  se_filter.apply( S, false);
-
-	valarray<TFloat>
-		ss (pages),
-		su (pages);
-	for ( size_t p = 0; p < pages; ++p ) {
-		auto range = slice (p * integrate_samples, integrate_samples, 1);
-		su[p] =
-			(valarray<TFloat> {due_filtered[range]} * valarray<TFloat> {se_filtered[range]})
-			.sum()
-			/ integrate_samples;
-		ss[p] =
-			pow(valarray<TFloat> {se_filtered[range]}, (TFloat)2.)
-			.sum() / samplerate
-			/ integrate_samples;
-	}
-
-	return TSSSU {su, ss};
-}
-
-
-
-
-
-
-
 
 
 
@@ -251,4 +210,15 @@ export_tsv( size_t bin,
 }
 
 
+
+template
+pair<valarray<TFloat>, valarray<TFloat>>
+metrics::mc::
+do_sssu_reduction( const valarray<TFloat>&,
+		   size_t, double, double, double,
+		   double, double, double);
+
+const size_t sssu_hist_size = 100;
+
+
 // eof
diff --git a/src/metrics/mc.hh b/src/metrics/mc.hh
index b29a4b6..690ebc7 100644
--- a/src/metrics/mc.hh
+++ b/src/metrics/mc.hh
@@ -37,7 +37,8 @@ struct SPPack
 		iir_backpolate,			// = 0.5;	// 0.0 < Backpolate < 1.0 on s: standard 0.5
 		mc_gain;			// = 10.0;	// Gain (DigiRange/PhysiRange) of MicroContinuity
 	size_t	smooth_side;
-	static constexpr double freq_from = .5;
+	double	freq_from,
+		freq_inc;
 
 	SPPack (const SPPack&) = default;
 	SPPack ()
@@ -53,7 +54,9 @@ struct SPPack
 				mc_gain == rv.mc_gain &&
 				f0fc == rv.f0fc &&
 				bandwidth == rv.bandwidth &&
-				smooth_side == rv.smooth_side;
+				smooth_side == rv.smooth_side &&
+				freq_from == rv.freq_from &&
+				freq_inc == rv.freq_inc;
 		}
 	void make_same( const SPPack& rv)
 		{
@@ -64,6 +67,8 @@ struct SPPack
 			f0fc = rv.f0fc;
 			bandwidth = rv.bandwidth;
 			smooth_side = rv.smooth_side;
+			freq_from = rv.freq_from;
+			freq_inc = rv.freq_inc;
 		}
 
 	void check() const; // throws
@@ -88,9 +93,17 @@ class CProfile
 
 	SPPack Pp;
 
-	const char* method() const
+	const char* metric_name() const
 		{
-			return metric_method( TType::mc);
+			return metrics::name( TType::mc);
+		}
+
+	valarray<TFloat> course( double binf) const
+		{
+			size_t	bin = agh::alg::value_within(
+				(int)((binf - Pp.freq_from) / Pp.freq_inc),
+				0, (int)bins()-1);
+			return metrics::CProfile::course(bin);
 		}
 
 	int go_compute();
@@ -101,18 +114,6 @@ class CProfile
 	int export_tsv( size_t bin,
 			const string& fname) const;
 
-      // computation stages
-	typedef pair<valarray<TFloat>, valarray<TFloat>> TSSSU;
-
-	static TSSSU
-	do_sssu_reduction( const valarray<TFloat>& signal,
-			   size_t samplerate, double scope,
-			   double mc_gain, double iir_backpolate,
-			   double f0, double fc,
-			   double bandwidth);
-
-	static const size_t sssu_hist_size = 100;
-
 	// to enable use as mapped type
 	CProfile (const CProfile& rv)
 	      : metrics::CProfile (rv)
@@ -120,6 +121,66 @@ class CProfile
 };
 
 
+
+// mc.ii
+// computation stages
+
+template <typename T>
+pair<valarray<T>, valarray<T>>
+do_sssu_reduction( const valarray<T>&,
+		   size_t, double, double, double,
+		   double, double, double);
+
+extern const size_t sssu_hist_size;
+
+extern template
+pair<valarray<TFloat>, valarray<TFloat>>
+do_sssu_reduction( const valarray<TFloat>&,
+		   size_t, double, double, double,
+		   double, double, double);
+
+template <typename T>
+pair<valarray<T>, valarray<T>>
+do_sssu_reduction( const valarray<T>& S,
+		   size_t samplerate, double scope,
+		   double mc_gain, double iir_backpolate,
+		   double f0, double fc,
+		   double bandwidth)
+{
+	sigproc::CFilterDUE<T>
+		due_filter (samplerate, sigproc::TFilterDirection::forward,
+			    mc_gain, iir_backpolate,
+			    fc);
+	sigproc::CFilterSE<T>
+		se_filter (samplerate, sigproc::TFilterDirection::forward,
+			   mc_gain, iir_backpolate,
+			   f0, fc,
+			   bandwidth);
+
+	size_t	integrate_samples = scope * samplerate,
+		lpages = S.size() / integrate_samples;
+	valarray<T>
+		due_filtered = due_filter.apply( S, false),
+		se_filtered  =  se_filter.apply( S, false);
+
+	valarray<T>
+		ss (lpages),
+		su (lpages);
+	for ( size_t p = 0; p < lpages; ++p ) {
+		auto range = slice (p * integrate_samples, integrate_samples, 1);
+		su[p] =
+			(valarray<T> {due_filtered[range]} * valarray<T> {se_filtered[range]})
+			.sum() / integrate_samples;
+		ss[p] =
+			pow(valarray<T> {se_filtered[range]}, (T)2.)
+			.sum() / samplerate / integrate_samples;
+	}
+
+	return {su, ss};
+}
+
+
+
 } // namespace mc
 } // namespace metrics
 
diff --git a/src/metrics/page-metrics-base.cc b/src/metrics/page-metrics-base.cc
index 98b39b9..a47d32f 100644
--- a/src/metrics/page-metrics-base.cc
+++ b/src/metrics/page-metrics-base.cc
@@ -146,7 +146,7 @@ mirror_enable( const string& fname)
 {
 	int fd, retval = 0;
 	if ( (fd = open( fname.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644)) == -1 ||
-	     write( fd, &_data[0], _data.size() * sizeof(double)) == -1 )
+	     write( fd, &_data[0], _data.size() * sizeof(TFloat)) == -1 )
 	     retval = -1;
 	close( fd);
 	return retval;
@@ -162,8 +162,8 @@ mirror_back( const string& fname)
 		if ( (fd = open( fname.c_str(), O_RDONLY)) == -1 )
 			throw -1;
 		_data.resize( pages() * _bins);
-		if ( read( fd, &_data[0], _data.size() * sizeof(double))
-		     != (ssize_t)(_data.size() * sizeof(double)) )
+		if ( read( fd, &_data[0], _data.size() * sizeof(TFloat))
+		     != (ssize_t)(_data.size() * sizeof(TFloat)) )
 			throw -2;
 		close(fd);
 		return 0;
diff --git a/src/metrics/page-metrics-base.hh b/src/metrics/page-metrics-base.hh
index 07f21aa..492eba6 100644
--- a/src/metrics/page-metrics-base.hh
+++ b/src/metrics/page-metrics-base.hh
@@ -34,7 +34,7 @@ enum class TType { invalid, psd, mc, swu };
 
 inline const char*
 __attribute__ ((pure))
-metric_method( TType t)
+name( TType t)
 {
 	switch ( t ) {
 	case TType::psd:
@@ -85,7 +85,7 @@ class CProfile {
     public:
 	SPPack	Pp;
 
-	virtual const char* method() const = 0;
+	virtual const char* metric_name() const = 0;
 
 	const sigfile::CSource& source() const
 		{
@@ -110,7 +110,7 @@ class CProfile {
 	size_t samplerate() const;
 
       // accessors
-	double&
+	TFloat&
 	nmth_bin( size_t p, size_t b)
 		{
 			// if ( unlikely (b >= n_bins()) )
@@ -119,23 +119,30 @@ class CProfile {
 			// 	throw out_of_range("CPageMetrics_base::nmth_bin(): page out of range");
 			return _data[p * _bins + b];
 		}
-	const double&
+	const TFloat&
 	nmth_bin( size_t p, size_t b) const
 		{
 			return _data[p * _bins + b];
 		}
 
-	template <class T>
-	valarray<T> spectrum( size_t p) const;
-
       // power course
 	// full (note the returned array size is length * n_bins)
-	template <class T>
-	valarray<T> course() const;
+	valarray<TFloat> course() const
+		{
+			return _data;
+		}
 
 	// in a bin
-	template <class T>
-	valarray<T> course( size_t m) const;
+	valarray<TFloat> course( size_t m) const
+		{
+			return _data[ slice(m, pages(), _bins) ];
+		}
+
+	valarray<TFloat> spectrum( size_t p) const
+		{
+			return _data[ slice(p * _bins, _bins, 1) ];
+		}
+
 
     public:
       // artifacts
@@ -161,7 +168,7 @@ class CProfile {
 	};
 	int	_status;
 
-	valarray<double>  // arrays in a given bin extracted by slices
+	valarray<TFloat>  // arrays in a given bin extracted by slices
 		_data;    // it is always double because it is saved/loaded in this form
 	size_t	_bins;
 
@@ -176,80 +183,6 @@ class CProfile {
 
 
 
-template <>
-inline valarray<double>
-CProfile::course() const
-{
-	return _data;
-}
-
-
-template <>
-inline valarray<float>
-CProfile::course() const
-{
-	valarray<float> coursef (_data.size());
-	for ( size_t i = 0; i < _data.size(); ++i )
-		coursef[i] = _data[i];
-	return coursef;
-}
-
-
-template <>
-inline valarray<double>
-CProfile::course( size_t m) const
-{
-	return _data[ slice(m, pages(), _bins) ];
-}
-
-
-template <>
-inline valarray<float>
-CProfile::course( size_t m) const
-{
-	valarray<double> course = _data[ slice(m, pages(), _bins) ];
-	valarray<float> coursef (0., course.size());
-	for ( size_t i = 0; i < course.size(); ++i )
-		coursef[i] = (float)course[i];
-	return coursef;
-}
-
-
-template <>
-inline valarray<double>
-CProfile::spectrum( size_t p) const
-{
-	return _data[ slice(p * _bins, _bins, 1) ];
-}
-
-template <>
-inline valarray<float>
-CProfile::spectrum( size_t p) const
-{
-	valarray<double> dps = spectrum<double>(p);
-	valarray<float> ps (dps.size());
-	for ( size_t i = 0; i < ps.size(); ++i )
-		ps[i] = dps[i];
-	return ps;
-}
-
-inline valarray<double>
-to_vad( valarray<double>&& rv)
-{
-	return move(rv);
-}
-
-inline valarray<double>
-to_vad( const valarray<float>& rv)
-{
-	valarray<double> ret;
-	ret.resize( rv.size());
-	for ( size_t i = 0; i < rv.size(); ++i )
-		ret[i] = rv[i];
-	return ret;
-}
-
-
 } // namespace metrics
 
 #endif // _SIGFILE_PAGE_METRICS_BASE_H
diff --git a/src/metrics/psd.cc b/src/metrics/psd.cc
index 32e6ec9..9b8b53c 100644
--- a/src/metrics/psd.cc
+++ b/src/metrics/psd.cc
@@ -82,14 +82,13 @@ metrics::psd::CProfile::
 fname_base() const
 {
 	DEF_UNIQUE_CHARP (_);
-	assert (asprintf( &_,
-			  "%s.%s-%zu"
-			  ":%zu-%g-%c",
-			  _using_F.filename(), _using_F.channel_by_id(_using_sig_no),
-			  _using_F.dirty_signature( _using_sig_no),
-			  Pp.pagesize, Pp.binsize,
-			  'a'+(char)Pp.welch_window_type)
-		> 1);
+	ASPRINTF( &_,
+		  "%s.%s-%zu"
+		  ":%zu-%g-%c",
+		  _using_F.filename(), _using_F.channel_by_id(_using_sig_no),
+		  _using_F.dirty_signature( _using_sig_no),
+		  Pp.pagesize, Pp.binsize,
+		  'a'+(char)Pp.welch_window_type);
 	string ret {_};
 	return ret;
 }
@@ -102,15 +101,15 @@ mirror_fname() const
 {
 	DEF_UNIQUE_CHARP (_);
 	string basename_dot = agh::fs::make_fname_base (_using_F.filename(), "", true);
-	assert (asprintf( &_,
-			  "%s.%s-%zu"
-			  ":%zu-%g-%c"
-			  ".psd",
-			  basename_dot.c_str(), _using_F.channel_by_id(_using_sig_no),
-			  _using_F.dirty_signature( _using_sig_no),
-			  Pp.pagesize, Pp.binsize,
-			  'a'+(char)Pp.welch_window_type)
-		> 1);
+	ASPRINTF( &_,
+		  "%s.%s-%zu"
+		  ":%zu-%g-%c@%zu"
+		  ".psd",
+		  basename_dot.c_str(), _using_F.channel_by_id(_using_sig_no),
+		  _using_F.dirty_signature( _using_sig_no),
+		  Pp.pagesize, Pp.binsize,
+		  'a'+(char)Pp.welch_window_type,
+		  sizeof(double));
 	string ret {_};
 	return ret;
 }
@@ -130,7 +129,7 @@ go_compute()
 
       // 0. get signal sample; always use double not TFloat
       // so that saved power is usable irrespective of what TFloat is today
-	valarray<double> S = to_vad( _using_F.get_signal_filtered( _using_sig_no));
+	valarray<double> S = agh::alg::to_vad( _using_F.get_signal_filtered( _using_sig_no));
 
       // 1. dampen samples marked as artifacts
 	// already done in get_signal_filtered()
@@ -213,7 +212,7 @@ go_compute()
 		///printf( "n_bins = %zu, max_freq = %g\n", n_bins(), max_freq);
 		for ( f = 0., b = 0; b < _bins; (f += Pp.binsize), ++b ) {
 			//printf( "b = %zu, f = %g\n", b, f);
-			nmth_bin(p, b) =
+			nmth_bin(p, b) = (TFloat) // brilliant!
 				valarray<double>
 				(P[ slice( f*sr, (f + Pp.binsize)*sr, 1) ]) . sum();
 		}
@@ -291,7 +290,7 @@ export_tsv( float from, float upto,
 		 _using_F.channel_by_id(_using_sig_no),
 		 pages(), Pp.pagesize, from, upto);
 
-	valarray<TFloat> crs = course<TFloat>( from, upto);
+	valarray<TFloat> crs = course( from, upto);
 	for ( size_t p = 0; p < pages(); ++p )
 		fprintf( f, "%zu\t%g\n", p, crs[p]);
 
diff --git a/src/metrics/psd.hh b/src/metrics/psd.hh
index 68887d6..b9c29b4 100644
--- a/src/metrics/psd.hh
+++ b/src/metrics/psd.hh
@@ -89,20 +89,19 @@ class CProfile
 
 	SPPack Pp;
 
-	const char* method() const
+	const char* metric_name() const
 		{
-			return metric_method( TType::psd);
+			return metrics::name( TType::psd);
 		}
 
 	// in a frequency range
-	template <class T>
-	valarray<T> course( float from, float upto) const
+	valarray<TFloat> course( double from, double upto) const
 		{
-			valarray<T> acc (0., pages());
+			valarray<TFloat> acc (0., pages());
 			size_t	bin_a = min( (size_t)(from / Pp.binsize), _bins),
 				bin_z = min( (size_t)(upto / Pp.binsize), _bins);
 			for ( size_t b = bin_a; b < bin_z; ++b )
-				acc += metrics::CProfile::course<T>(b);
+				acc += metrics::CProfile::course(b);
 			return acc;
 		}
 
diff --git a/src/metrics/swu.cc b/src/metrics/swu.cc
index 51257db..af8f183 100644
--- a/src/metrics/swu.cc
+++ b/src/metrics/swu.cc
@@ -63,13 +63,12 @@ metrics::swu::CProfile::
 fname_base() const
 {
 	DEF_UNIQUE_CHARP (_);
-	assert (asprintf( &_,
-			  "%s.%s-%zu"
-			  ":%zu",
-			  _using_F.filename(), _using_F.channel_by_id(_using_sig_no),
-			  _using_F.dirty_signature( _using_sig_no),
-			  Pp.pagesize)
-		> 1);
+	ASPRINTF( &_,
+		  "%s.%s-%zu"
+		  ":%zu",
+		  _using_F.filename(), _using_F.channel_by_id(_using_sig_no),
+		  _using_F.dirty_signature( _using_sig_no),
+		  Pp.pagesize);
 	string ret {_};
 	return ret;
 }
@@ -81,14 +80,14 @@ mirror_fname() const
 {
 	DEF_UNIQUE_CHARP (_);
 	string basename_dot = agh::fs::make_fname_base (_using_F.filename(), "", true);
-	assert (asprintf( &_,
-			  "%s.%s-%zu"
-			  ":%zu"
-			  ".swu",
-			  basename_dot.c_str(), _using_F.channel_by_id(_using_sig_no),
-			  _using_F.dirty_signature( _using_sig_no),
-			  Pp.pagesize)
-		> 1);
+	ASPRINTF( &_,
+		  "%s.%s-%zu"
+		  ":%zu@%zu"
+		  ".swu",
+		  basename_dot.c_str(), _using_F.channel_by_id(_using_sig_no),
+		  _using_F.dirty_signature( _using_sig_no),
+		  Pp.pagesize,
+		  sizeof(TFloat));
 	string ret {_};
 	return ret;
 }
@@ -100,8 +99,6 @@ go_compute()
 {
 	_data.resize( pages() * _bins);
 
-      // 0. get signal sample; always use double not TFloat
-      // so that saved power is usable irrespective of what TFloat is today
 	auto S = _using_F.get_signal_filtered( _using_sig_no);
 
 	for ( size_t p = 0; p < pages(); ++p ) {
diff --git a/src/metrics/swu.hh b/src/metrics/swu.hh
index 67ab9fd..57a5bd6 100644
--- a/src/metrics/swu.hh
+++ b/src/metrics/swu.hh
@@ -55,9 +55,15 @@ class CProfile
 
 	SPPack Pp;
 
-	const char* method() const
+	const char* metric_name() const
 		{
-			return metric_method( TType::swu);
+			return metrics::name( TType::swu);
+		}
+
+	valarray<TFloat> course( double) const
+		{
+			size_t	bin = 0; // (size_t)(binf - freq_from / Pp.freq_inc);
+			return metrics::CProfile::course(bin);
 		}
 
 	int go_compute();
diff --git a/src/model/achermann.cc b/src/model/achermann.cc
index 290d6ab..585a425 100644
--- a/src/model/achermann.cc
+++ b/src/model/achermann.cc
@@ -12,7 +12,7 @@
 
 #include <list>
 
-#include "expdesign/recording.hh"
+#include "expdesign/profile.hh"
 #include "expdesign/primaries.hh"
 #include "achermann-tunable.hh"
 #include "achermann.hh"
@@ -32,8 +32,7 @@ check() const
 	     siman_params.t_initial <= 0. ||
 	     siman_params.t_min <= 0. ||
 	     siman_params.t_min >= siman_params.t_initial ||
-	     siman_params.mu_t <= 0 ||
-	     (req_percent_scored < 50. || req_percent_scored > 100. ) )
+	     siman_params.mu_t <= 0 )
 		throw invalid_argument("Bad SControlParamSet");
 }
 
@@ -53,11 +52,6 @@ reset()
 	DBAmendment2		= false;
 	AZAmendment1		= false;
 	AZAmendment2		= false;
-
-	ScoreUnscoredAsWake	= true;
-
-	req_percent_scored = 90.;
-	swa_laden_pages_before_SWA_0 = 3;
 }
 
 
@@ -71,10 +65,7 @@ operator==( const SControlParamSet &rv) const
 		DBAmendment1 == rv.DBAmendment1 &&
 		DBAmendment2 == rv.DBAmendment2 &&
 		AZAmendment1 == rv.AZAmendment1 &&
-		AZAmendment2 == rv.AZAmendment2 &&
-		ScoreUnscoredAsWake == rv.ScoreUnscoredAsWake &&
-		req_percent_scored == rv.req_percent_scored &&
-		swa_laden_pages_before_SWA_0 == rv.swa_laden_pages_before_SWA_0;
+		AZAmendment2 == rv.AZAmendment2;
 }
 
 
@@ -83,35 +74,36 @@ operator==( const SControlParamSet &rv) const
 int
 agh::CExpDesign::
 setup_modrun( const char* j, const char* d, const char* h,
-	      metrics::TType metric_type,
-	      float freq_from, float freq_upto,
+	      const SProfileParamSet& profile_params0,
 	      agh::ach::CModelRun** Rpp)
 {
 	try {
 		CSubject& J = subject_by_x(j);
 
 		if ( J.measurements[d].size() == 1 && ctl_params0.DBAmendment2 )
-			return CSCourse::TFlags::eamendments_ineffective;
+			return CProfile::TFlags::eamendments_ineffective;
 
 		if ( J.measurements[d].size() == 1 && tstep[ach::TTunable::rs] > 0. )
-			return CSCourse::TFlags::ers_nonsensical;
-
-		auto freq_idx = pair<float,float> (freq_from, freq_upto);
-		J.measurements[d]
-			. modrun_sets[metric_type][h].insert(
-				pair<pair<float, float>, ach::CModelRun>
-				(freq_idx, agh::ach::CModelRun (J, d, h,
-							   metric_type, freq_from, freq_upto,
-							   ctl_params0, tunables0)));
+			return CProfile::TFlags::ers_nonsensical;
+
+		J.measurements[d].modrun_sets[profile_params0].insert(
+			pair<string, ach::CModelRun> (
+				h,
+				ach::CModelRun (
+					J, d, h,
+					profile_params0,
+					ctl_params0,
+					tunables0))
+			);
 		if ( Rpp )
 			*Rpp = &J.measurements[d]
-				. modrun_sets[metric_type][h][freq_idx];
+				. modrun_sets[profile_params0][h];
 
-	} catch (invalid_argument ex) { // thrown by CSCourse ctor
+	} catch (invalid_argument ex) { // thrown by CProfile ctor
 		fprintf( stderr, "CExpDesign::setup_modrun( %s, %s, %s): %s\n", j, d, h, ex.what());
 		return -1;
 	} catch (int ex) { // thrown by CModelRun ctor
-		log_message( "CExpDesign::setup_modrun( %s, %s, %s): %s\n", j, d, h, CSCourse::explain_status(ex).c_str());
+		log_message( "CExpDesign::setup_modrun( %s, %s, %s): %s\n", j, d, h, CProfile::explain_status(ex).c_str());
 		return ex;
 	}
 
@@ -123,15 +115,11 @@ setup_modrun( const char* j, const char* d, const char* h,
 
 agh::ach::CModelRun::
 CModelRun (CSubject& subject, const string& session, const sigfile::SChannel& channel,
-	   metrics::TType metric_type,
-	   double freq_from, double freq_upto,
+	   const agh::SProfileParamSet& _scourse_params,
 	   const SControlParamSet& _ctl_params,
 	   const STunableSetWithState& t0)
-      : CSCourse (subject, session, channel,
-		  agh::SSCourseParamSet {metric_type,
-				  freq_from, freq_upto, _ctl_params.req_percent_scored,
-				  _ctl_params.swa_laden_pages_before_SWA_0,
-				  _ctl_params.ScoreUnscoredAsWake}),
+      : CProfile (subject, session, channel,
+		  _scourse_params),
 	status (0),
 	ctl_params (_ctl_params),
 	tstep (ctl_params.AZAmendment1 ? _mm_list.size()-1 : 0),
@@ -141,14 +129,14 @@ CModelRun (CSubject& subject, const string& session, const sigfile::SChannel& ch
 	tx (t0, tstep, tlo, thi),
 	cf (NAN)
 {
-	if ( CSCourse::_status )
-		throw CSCourse::_status;
+	if ( CProfile::_status )
+		throw CProfile::_status;
 	_prepare_scores2();
 }
 
 agh::ach::CModelRun::
 CModelRun (CModelRun&& rv)
-      : CSCourse (move(rv)),
+      : CProfile (move(rv)),
 	status (rv.status),
 	ctl_params (rv.ctl_params),
 	tstep (rv.tstep),
diff --git a/src/model/achermann.hh b/src/model/achermann.hh
index 9209b4a..55f4255 100644
--- a/src/model/achermann.hh
+++ b/src/model/achermann.hh
@@ -22,7 +22,7 @@
 #include "libsigfile/forward-decls.hh"
 #include "libsigfile/page.hh"
 #include "metrics/page-metrics-base.hh"
-#include "expdesign/recording.hh"
+#include "expdesign/profile.hh"
 #include "achermann-tunable.hh"
 
 
@@ -45,9 +45,6 @@ struct SControlParamSet {
 		AZAmendment2,
 		ScoreUnscoredAsWake;
 
-	double	req_percent_scored;
-	size_t	swa_laden_pages_before_SWA_0;
-
 	gsl_siman_params_t
 		siman_params;
 		    // int n_tries
@@ -74,7 +71,7 @@ struct SControlParamSet {
 
 
 class CModelRun
-  : public agh::CSCourse {
+  : public agh::CProfile {
 
     public:
 	CModelRun (const CModelRun&)
@@ -89,8 +86,7 @@ class CModelRun
 		}
 	CModelRun (CModelRun&&);
 	CModelRun (CSubject&, const string& session, const sigfile::SChannel&,
-		   metrics::TType,
-		   double freq_from, double freq_upto,
+		   const agh::SProfileParamSet&,
 		   const SControlParamSet&, const STunableSetWithState&);
 
 	enum TModrunFlags { modrun_tried = 1 };
@@ -123,7 +119,6 @@ class CModelRun
 
 
 
-
 inline const double&
 CModelRun::
 _which_gc( size_t p) const // selects episode egc by page, or returns &gc if !AZAmendment
@@ -137,8 +132,6 @@ _which_gc( size_t p) const // selects episode egc by page, or returns &gc if !AZ
 
 
 
-
-
 } // namespace ach
 } // namespace agh
 
diff --git a/src/model/assisted-score.cc b/src/model/assisted-score.cc
index 112fe6a..48f1fd9 100644
--- a/src/model/assisted-score.cc
+++ b/src/model/assisted-score.cc
@@ -35,8 +35,8 @@ assisted_score( agh::CSubject::SEpisode& E)
 		courses_delta,
 		courses_theta;
 	for ( auto &H : HH ) {
-		courses_delta.emplace_front( H->psd_profile.course<TFloat>( 2., 3.));
-		courses_theta.emplace_front( H->psd_profile.course<TFloat>( 5., 8.));
+		courses_delta.emplace_front( H->psd_profile.course( 2., 3.));
+		courses_theta.emplace_front( H->psd_profile.course( 5., 8.));
 	}
 
 	auto& firstsource = E.sources.front();
diff --git a/src/model/beersma.hh b/src/model/beersma.hh
index 94ca165..4839f94 100644
--- a/src/model/beersma.hh
+++ b/src/model/beersma.hh
@@ -17,7 +17,7 @@
 #include <gsl/gsl_math.h>
 #include <gsl/gsl_siman.h>
 #include "metrics/page-metrics-base.hh"
-#include "expdesign/forward-decls.hh"
+#include "expdesign/profile.hh"
 
 
 #if HAVE_CONFIG_H && !defined(VERSION)
@@ -45,10 +45,8 @@ struct SClassicFit {
 };
 
 struct SClassicFitCtl {
-	metrics::TType
-		metric;
-	double	freq_from,
-		freq_upto;
+	SProfileParamSet
+		P;
 	double	sigma;
 	size_t	iterations;
 };
@@ -83,6 +81,7 @@ struct SUltradianCycle {
 		ir = 0.0001,  iT =   1., id =  .1, ib = .1, // the last one is a normalized value of metric
 		ur = 0.010,   uT = 130., ud =  60., ub = .01,
 		lr = 0.001,   lT =  60., ld = -60., lb = .1;
+	double	cf;
 };
 
 inline double
@@ -103,12 +102,10 @@ struct SUltradianCycleDetails {
 
 
 struct SUltradianCycleCtl {
-	metrics::TType
-		metric;
-	double	freq_from,
-		freq_upto;
-	double	sigma;
+	agh::SProfileParamSet
+		profile_params;
 
+	double	sigma;
 	gsl_siman_params_t
 		siman_params;
 		    // int n_tries
@@ -168,13 +165,6 @@ analyse_deeper( const SUltradianCycle&,
 		agh::CRecording&,
 		const SUltradianCycleCtl&);
 
-
-
-
-
-
-
-
 } // namespace beersma
 } // namespace agh
 
diff --git a/src/model/borbely.cc b/src/model/borbely.cc
index 67d9c4c..73bd6f4 100644
--- a/src/model/borbely.cc
+++ b/src/model/borbely.cc
@@ -15,6 +15,7 @@
 #include <gsl/gsl_multifit_nlin.h>
 #include <gsl/gsl_blas.h>
 
+#include "common/alg.hh"
 #include "metrics/psd.hh"
 #include "metrics/mc.hh"
 #include "expdesign/recording.hh"
@@ -103,7 +104,7 @@ classic_fit( agh::CRecording& M,
 	     const agh::beersma::SClassicFitCtl& P)
 {
       // set up
-	auto	course = M.course<double>( P.metric, P.freq_from, P.freq_upto);
+	auto	course = agh::alg::to_vad( M.course( P.P));
 	auto	pp = course.size(),
 		pagesize = M.pagesize();
 
@@ -112,10 +113,7 @@ classic_fit( agh::CRecording& M,
 	double	SWA_0, SWA_L;
 	{
 		// this one doesn't throw
-		agh::CSCourse tmp (M, { P.metric, P.freq_from, P.freq_upto,
-					0., // _req_percent_scored;
-					5, // _swa_laden_pages_before_SWA_0;
-					true }); // _ScoreUnscoredAsWake:1;
+		agh::CProfile tmp (M, P.P);
 		SWA_0 = tmp.SWA_0();
 		SWA_L = tmp.SWA_L();
 	}
diff --git a/src/model/ultradian-cycle.cc b/src/model/ultradian-cycle.cc
index 10b15a5..42316aa 100644
--- a/src/model/ultradian-cycle.cc
+++ b/src/model/ultradian-cycle.cc
@@ -161,7 +161,7 @@ ultradian_cycles( agh::CRecording& M,
 		  list<agh::beersma::SUltradianCycleDetails> *extra)
 {
 	// normalize please
-	auto course = M.course<TFloat>( C.metric, C.freq_from, C.freq_upto);
+	auto course = M.course( C.profile_params);
 	sigproc::smooth( course, 5u);
 	//auto avg = course.sum()/course.size();
 	course /= course.max() / 2; // because ultradian cycle function has a range of 2
@@ -186,18 +186,18 @@ ultradian_cycles( agh::CRecording& M,
 
 	{
 		FUltradianCycle F (X);
-		M.uc_cf = 0.;
+		X.cf = 0.;
 		for ( size_t p = 0; p < course.size(); ++p ) {
-			M.uc_cf += gsl_pow_2( F(p*M.pagesize()/60.) - course[p]);
+			X.cf += gsl_pow_2( F(p*M.pagesize()/60.) - course[p]);
 		}
-		M.uc_cf = sqrt(M.uc_cf);
+		X.cf = sqrt(X.cf);
 	}
 
 
 	if ( extra )
 		*extra = analyse_deeper( X, M, C);
 
-	return M.uc_params = X;
+	return X;
 }
 
 
diff --git a/src/sigproc/Makefile.am b/src/sigproc/Makefile.am
index a718648..5c037bb 100644
--- a/src/sigproc/Makefile.am
+++ b/src/sigproc/Makefile.am
@@ -6,8 +6,8 @@ noinst_LIBRARIES := liba.a
 
 liba_a_SOURCES := \
 	exstrom.cc exstrom.hh \
-	ext-filters.cc ext-filters.hh \
-	sigproc.cc sigproc.hh \
+	ext-filters.cc ext-filters.hh ext-filters.ii \
+	sigproc.cc sigproc.hh sigproc.ii \
 	winfun.cc winfun.hh
 
 if DO_PCH
diff --git a/src/sigproc/ext-filters.cc b/src/sigproc/ext-filters.cc
index 30781de..3e6c525 100644
--- a/src/sigproc/ext-filters.cc
+++ b/src/sigproc/ext-filters.cc
@@ -5,157 +5,21 @@
  *          Author:  Andrei Zavada <johnhommer at gmail.com>
  * Initial version:  2012-03-11
  *
- *         Purpose:  some filters directly for use in microcontinuity code
+ *         Purpose:  some filters used in microcontinuity code (template instantiations)
  *
  *         License:  GPL
  */
 
 
-#include <gsl/gsl_math.h>
-
-#include "common/lang.hh"
 #include "ext-filters.hh"
 
 #if HAVE_CONFIG_H && !defined(VERSION)
 #  include "config.h"
 #endif
 
+using namespace std;
 
-
-void
-sigproc::CFilterIIR::
-reset()
-{
-	CFilter_base::reset();
-
-	calculate_iir_coefficients();
-
-	filter_state_z = 0.;
-	filter_state_p = 0.;
-}
-
-
-void
-sigproc::CFilterIIR::
-reset( double xn)
-{
-	calculate_iir_coefficients();
-
-	filter_state_z = xn;
-	filter_state_p = xn * zeros.sum() / (1. - poles.sum());
-}
-
-
-
-
-
-void
-sigproc::CFilterDUE::
-calculate_iir_coefficients()
-{
-	CFilterIIR::calculate_iir_coefficients();
-
-	double	ts = 1. / samplerate,
-		fprewarp = tan( M_PI * minus_3db_frequency * ts) / (M_PI * ts),
-		r = 1. / (2. * M_PI * fprewarp),
-		s = ts / 2.;
-	zeros = {(gain * (s + r)),
-		 (gain * (s - r)),
-		 1.};
-}
-
-void
-sigproc::CFilterSE::
-calculate_iir_coefficients()
-{
-	CFilterIIR::calculate_iir_coefficients();
-
-	double	ts = 1.0 / samplerate,
-		fprewarp, r, s, t;
-
-	fprewarp = tan(f0 * M_PI * ts) / (M_PI * ts);
-	r = gsl_pow_2(2. * M_PI * fprewarp * ts);
-	// From November 1992 prewarping applied because of Arends results !
-	// r:=sqr(2.0*pi*f0*Ts);                         No prewarping
-	s = 2. * M_PI * bandwidth * ts * 2.;
-	t = 4. + r + s;
-	poles = {1.,
-		 ((8.0 - 2.0 * r) / t),
-		 ((-4.0 + s - r) / t)};
-
-	fprewarp = tan(fc * M_PI * ts) / (M_PI * ts);
-	r = 2.0 / (2. * M_PI * fprewarp);
-	s = gain * 2. * M_PI * bandwidth * 2.;
-	zeros = {(s * (r + ts)   / t),
-		 (s * (-2.0 * r) / t),
-		 (s * (r - ts)   / t)};
-}
-
-
-
-
-valarray<TFloat>
-sigproc::CFilterIIR::
-apply( const valarray<TFloat>& in, bool use_first_sample_to_reset)
-{
-	if ( unlikely (poles.size() == 0) )
-		throw runtime_error ("Unitialized CFilterIIR");
-
-	valarray<TFloat> out (in.size());
-
-	size_t i, l;
-
-	int d;
-	switch ( direction ) {
-	case forward:
-		i = 0;
-		l = in.size();
-		d = 1;
-	    break;
-	case back:
-		i = in.size()-1;
-		l = 0-1;
-		d = -1;
-	    break;
-	default:
-		throw invalid_argument ("sigproc::CFilterIIR::apply(): direction?");
-	}
-
-	for ( ; i != l; i += d ) {
-		filter_state_z[0] = in[i];
-		if ( unlikely (use_first_sample_to_reset) ) {
-			reset( filter_state_z[0]);
-			use_first_sample_to_reset = false;
-		}
-		// Compute new output sample
-		double r = 0.;
-		// Add past output-values
-		size_t j;
-		for ( j = 1; j < poles.size(); ++j )
-			r += poles[j] * filter_state_p[j];
-		// Not anticipate = do not include current input sample in output value
-		if ( not anticipate)
-			out[i] = r;
-		// Add past input-values
-		for ( j = 0; j < zeros.size(); ++j )
-			r += zeros[j] * filter_state_z[j];
-		// Anticipate = include current input sample in output value
-		if ( anticipate )
-			out[i] = r;
-		// Do backpolation (FilterStateP[1] = Last out-sample)
-		out[i] = back_polate * filter_state_p[1] + (1.0 - back_polate) * out[i];
-		// Scale result
-		// TODO: Check if removing extra checks was ok
-		// Update filter state
-		for ( j = poles.size()-1; j >= 2; --j )
-			filter_state_p[j] = filter_state_p[j-1];
-		filter_state_p[1] = r;
-		for ( j = zeros.size()-1; j >= 1; --j )
-			filter_state_z[j] = filter_state_z[j-1];
-	}
-
-	return out;
-}
-
+template valarray<float>   sigproc::CFilterIIR<float>::apply( const valarray<float>&, bool);
+template valarray<double>  sigproc::CFilterIIR<double>::apply( const valarray<double>&, bool);
 
 // eof
diff --git a/src/sigproc/ext-filters.hh b/src/sigproc/ext-filters.hh
index 410d32b..825fa36 100644
--- a/src/sigproc/ext-filters.hh
+++ b/src/sigproc/ext-filters.hh
@@ -15,6 +15,7 @@
 
 #include <valarray>
 #include <stdexcept>
+#include <gsl/gsl_math.h>
 #include "common/lang.hh"
 
 #if HAVE_CONFIG_H && !defined(VERSION)
@@ -25,11 +26,11 @@ using namespace std;
 
 namespace sigproc {
 
-class CFilter_base {
-	DELETE_DEFAULT_METHODS (CFilter_base);
+enum TFilterDirection { forward, back };
 
-    public:
-	enum TFilterDirection { forward, back };
+template <typename T>
+class CFilter_base {
+	DELETE_DEFAULT_METHODS (CFilter_base<T>);
 
     protected:
 	size_t samplerate;
@@ -44,96 +45,158 @@ class CFilter_base {
 				throw invalid_argument ("CFilter_base(): samplerate is 0");
 		}
 
-	virtual valarray<TFloat>
-	apply( const valarray<TFloat>& in, bool) = 0;
+	virtual valarray<T>
+	apply( const valarray<T>& in, bool) = 0;
 	void reset()
 		{}
 };
 
 
+template <typename T>
 class CFilterIIR
-  : public CFilter_base {
-	DELETE_DEFAULT_METHODS (CFilterIIR);
+  : public CFilter_base<T> {
+	DELETE_DEFAULT_METHODS (CFilterIIR<T>);
 
     protected:
-	CFilterIIR (size_t samplerate_,
-		    TFilterDirection direction_,
-		    double gain_, double back_polate_)
-	      : CFilter_base (samplerate_, direction_),
+	CFilterIIR<T> (size_t samplerate_,
+		       TFilterDirection direction_,
+		       T gain_, T back_polate_)
+	      : CFilter_base<T> (samplerate_, direction_),
 		anticipate (true),
 		gain (gain_),
 		back_polate (back_polate_)
 		{
 			calculate_iir_coefficients();
 		}
-	virtual void reset();
-	virtual void reset( double use_this);
+	virtual void reset()
+		{
+			CFilter_base<T>::reset();
+
+			calculate_iir_coefficients();
+
+			filter_state_z = 0.;
+			filter_state_p = 0.;
+		}
+
+	virtual void reset( T xn)
+		{
+			calculate_iir_coefficients();
+
+			zeros = 0.;
+			filter_state_z = xn;
+			filter_state_p = xn * zeros.sum() / (1. - poles.sum());
+		}
+
 
-	bool anticipate;
-	valarray<double>
+	bool	anticipate;
+	valarray<T>
 		filter_state_p,
 		filter_state_z,
 		poles,
 		zeros;
-	double	gain,
+	T	gain,
 		back_polate;
 
     public:
 	void calculate_iir_coefficients()
 		{}
-	virtual valarray<TFloat>
-	apply( const valarray<TFloat>& in, bool);
+	virtual valarray<T>
+	apply( const valarray<T>& in, bool);
 };
 
 
+template <typename T>
 class CFilterSE
-  : public CFilterIIR {
-	DELETE_DEFAULT_METHODS (CFilterSE);
+  : public CFilterIIR<T> {
+	DELETE_DEFAULT_METHODS (CFilterSE<T>);
 
     public:
-	CFilterSE (size_t samplerate_, TFilterDirection direction_,
-		   double gain_, double back_polate_,
-		   double f0_, double fc_, double bandwidth_)
-	      : CFilterIIR (samplerate_, direction_, gain_, back_polate_),
+	CFilterSE<T> (size_t samplerate_, TFilterDirection direction_,
+		      T gain_, T back_polate_,
+		      T f0_, T fc_, T bandwidth_)
+	      : CFilterIIR<T> (samplerate_, direction_, gain_, back_polate_),
 		f0 (f0_),
 		fc (fc_),
 		bandwidth (bandwidth_)
 		{
-			zeros.resize(3); filter_state_z.resize(3);
-			poles.resize(3); filter_state_p.resize(4);    // NrPoles+1 !!!!!111адинадин
+			CFilterIIR<T>::zeros.resize(3); CFilterIIR<T>::filter_state_z.resize(3);
+			CFilterIIR<T>::poles.resize(3); CFilterIIR<T>::filter_state_p.resize(4);    // NrPoles+1 !!!!!111адинадин
 			calculate_iir_coefficients();
 		}
 
-	void calculate_iir_coefficients();
+	void calculate_iir_coefficients()
+		{
+			CFilterIIR<T>::calculate_iir_coefficients();
+
+			T	ts = 1.0 / CFilterIIR<T>::samplerate,
+				fprewarp, r, s, t;
+
+			fprewarp = tan(f0 * M_PI * ts) / (M_PI * ts);
+			r = gsl_pow_2(2. * M_PI * fprewarp * ts);
+			// From November 1992 prewarping applied because of Arends results !
+			// r:=sqr(2.0*pi*f0*Ts);                         No prewarping
+			s = 2. * M_PI * bandwidth * ts * 2.;
+			t = 4. + r + s;
+			CFilterIIR<T>::poles =
+				{ (T)1.,
+				  (T)((8.0 - 2.0 * r) / t),
+				  (T)((-4.0 + s - r) / t) };
+
+			fprewarp = tan(fc * M_PI * ts) / (M_PI * ts);
+			r = 2.0 / (2. * M_PI * fprewarp);
+			s = CFilterIIR<T>::gain * 2. * M_PI * bandwidth * 2.;
+			CFilterIIR<T>::zeros =
+				{ (T)(s * (r + ts)   / t),
+				  (T)(s * (-2.0 * r) / t),
+				  (T)(s * (r - ts)   / t) };
+		}
+
 
     private:
-	double	f0,
+	T	f0,
 		fc,
 		bandwidth;
 };
 
+template <typename T>
 class CFilterDUE
-  : public CFilterIIR {
-	DELETE_DEFAULT_METHODS (CFilterDUE);
+  : public CFilterIIR<T> {
+	DELETE_DEFAULT_METHODS (CFilterDUE<T>);
 
     public:
-	CFilterDUE (size_t samplerate_, TFilterDirection direction_,
-		    double gain_, double back_polate_,
-		    double minus_3db_frequency_)
-	      : CFilterIIR (samplerate_, direction_, gain_, back_polate_),
+	CFilterDUE<T> (size_t samplerate_, TFilterDirection direction_,
+		       T gain_, T back_polate_,
+		       T minus_3db_frequency_)
+	      : CFilterIIR<T> (samplerate_, direction_, gain_, back_polate_),
 		minus_3db_frequency (minus_3db_frequency_)
 		{
-			zeros.resize(2); filter_state_z.resize(2);
-			poles.resize(1); filter_state_p.resize(2);    // NrPoles+1 !!!!!
+			CFilterIIR<T>::zeros.resize(2); CFilterIIR<T>::filter_state_z.resize(2);
+			CFilterIIR<T>::poles.resize(1); CFilterIIR<T>::filter_state_p.resize(2);    // NrPoles+1 !!!!!
 			calculate_iir_coefficients();
 		}
 
-	void calculate_iir_coefficients();
+	void calculate_iir_coefficients()
+		{
+			CFilterIIR<T>::calculate_iir_coefficients();
+
+			T	ts = 1. / CFilterIIR<T>::samplerate,
+				fprewarp = tan( M_PI * minus_3db_frequency * ts) / (M_PI * ts),
+				r = 1. / (2. * M_PI * fprewarp),
+				s = ts / 2.;
+			CFilterIIR<T>::zeros = {
+				(CFilterIIR<T>::gain * (s + r)),
+				(CFilterIIR<T>::gain * (s - r)),
+				1.};
+		}
+
 
     private:
-	double	minus_3db_frequency;
+	T	minus_3db_frequency;
 };
 
+
+#include "ext-filters.ii"
+
 } // namespace sigproc
 
 #endif // _EXT_FILTERS_HH
diff --git a/src/sigproc/ext-filters.ii b/src/sigproc/ext-filters.ii
new file mode 100644
index 0000000..931d289
--- /dev/null
+++ b/src/sigproc/ext-filters.ii
@@ -0,0 +1,82 @@
+// ;-*-C++-*-
+/*
+ *       File name:  sigproc/ext-filters.ii
+ *         Project:  Aghermann
+ *          Author:  Andrei Zavada <johnhommer at gmail.com>
+ * Initial version:  2012-11-28
+ *
+ *         Purpose:  some filters used in microcontinuity code (templates)
+ *
+ *         License:  GPL
+ */
+
+
+extern template valarray<float>  CFilterIIR<float>::apply( const valarray<float>&, bool);
+extern template valarray<double> CFilterIIR<double>::apply( const valarray<double>&, bool);
+
+
+template <typename T>
+valarray<T>
+sigproc::CFilterIIR<T>::
+apply( const valarray<T>& in, bool use_first_sample_to_reset)
+{
+	if ( unlikely (poles.size() == 0) )
+		throw runtime_error ("Unitialized CFilterIIR");
+
+	valarray<T> out (in.size());
+
+	size_t i, l;
+
+	int d;
+	switch ( CFilter_base<T>::direction ) {
+	case sigproc::forward:
+		i = 0;
+		l = in.size();
+		d = 1;
+	    break;
+	case sigproc::back:
+		i = in.size()-1;
+		l = 0-1;
+		d = -1;
+	    break;
+	default:
+		throw invalid_argument ("sigproc::CFilterIIR::apply(): direction?");
+	}
+
+	for ( ; i != l; i += d ) {
+		filter_state_z[0] = in[i];
+		if ( unlikely (use_first_sample_to_reset) ) {
+			reset( filter_state_z[0]);
+			use_first_sample_to_reset = false;
+		}
+		// Compute new output sample
+		double r = 0.;
+		// Add past output-values
+		size_t j;
+		for ( j = 1; j < poles.size(); ++j )
+			r += poles[j] * filter_state_p[j];
+		// Not anticipate = do not include current input sample in output value
+		if ( not anticipate)
+			out[i] = r;
+		// Add past input-values
+		for ( j = 0; j < zeros.size(); ++j )
+			r += zeros[j] * filter_state_z[j];
+		// Anticipate = include current input sample in output value
+		if ( anticipate )
+			out[i] = r;
+		// Do backpolation (FilterStateP[1] = Last out-sample)
+		out[i] = back_polate * filter_state_p[1] + (1.0 - back_polate) * out[i];
+		// Scale result
+		// TODO: Check if removing extra checks was ok
+		// Update filter state
+		for ( j = poles.size()-1; j >= 2; --j )
+			filter_state_p[j] = filter_state_p[j-1];
+		filter_state_p[1] = r;
+		for ( j = zeros.size()-1; j >= 1; --j )
+			filter_state_z[j] = filter_state_z[j-1];
+	}
+
+	return out;
+}
+
+// eof
diff --git a/src/sigproc/winfun.hh b/src/sigproc/winfun.hh
index 920c4be..c19388f 100644
--- a/src/sigproc/winfun.hh
+++ b/src/sigproc/winfun.hh
@@ -13,6 +13,8 @@
 #ifndef _SIGPROC_WINFUN_H
 #define _SIGPROC_WINFUN_H
 
+#include <stddef.h>
+
 #if HAVE_CONFIG_H && !defined(VERSION)
 #  include "config.h"
 #endif
diff --git a/src/ui/mf/mf.cc b/src/ui/mf/mf.cc
index 74ac642..f8a035a 100644
--- a/src/ui/mf/mf.cc
+++ b/src/ui/mf/mf.cc
@@ -33,17 +33,17 @@ unsigned short __score_hypn_depth[8] = {
 
 aghui::SModelrunFacility::
 SModelrunFacility (agh::ach::CModelRun& csim, SExpDesignUI& parent)
-  : csimulation (csim),
+      : csimulation (csim),
 // subject is known only by name, so look up his full object now
-    csubject (parent.ED->subject_by_x( csim.subject())),
-    // not sure we need this though
-    display_factor (1.),
-    zoomed_episode (-1),
-    _tunables_header_printed (false),
-    highlight_nrem (true),
-    highlight_rem (false),
-    highlight_wake (false),
-    _p (parent)
+	csubject (parent.ED->subject_by_x( csim.subject())),
+	// not sure we need this though
+	display_factor (1.),
+	zoomed_episode (-1),
+	_tunables_header_printed (false),
+	highlight_nrem (true),
+	highlight_rem (false),
+	highlight_wake (false),
+	_p (parent)
 {
 	builder = gtk_builder_new();
 	if ( !gtk_builder_add_from_resource( builder, "/org/gtk/aghermann/mf.glade", NULL) ) {
@@ -64,9 +64,9 @@ SModelrunFacility (agh::ach::CModelRun& csim, SExpDesignUI& parent)
 		if ( csim[p].metric > SWA_max )
 			SWA_max = csim[p].metric;
 
-	snprintf_buf( "Simulation: %s (%s) in %s, %g-%g Hz",
+	snprintf_buf( "Simulation: %s (%s) in %s (%s)",
 		      csim.subject(), csim.session(), csim.channel(),
-		      csim.freq_from(), csim.freq_upto());
+		      csim.P().display_name().c_str());
 	gtk_window_set_title(
 		wModelrunFacility,
 		__buf__);
@@ -82,12 +82,12 @@ SModelrunFacility (agh::ach::CModelRun& csim, SExpDesignUI& parent)
 	gtk_scale_button_set_value( eMFSmooth, swa_smoothover);
 	update_infobar();
 
-	snprintf_buf( "### Simulation: %s (%s) in %s, %g-%g Hz\n"
+	snprintf_buf( "### Simulation: %s (%s) in %s (%s)\n"
 		      "# sim start at p. %zu, end at p. %zu, baseline end at p. %zu,\n"
 		      "# %zu pp with SWA, %zu pp in bed;\n"
 		      "# SWA_L = %g, SWA[0] = %g, 100%% SWA = %g\n",
 		      csim.subject(),
-		      _p.AghD(), _p.AghH(), csim.freq_from(), csim.freq_upto(),
+		      _p.AghD(), _p.AghH(), csim.P().display_name().c_str(),
 		      csim.sim_start(), csim.sim_end(), csim.baseline_end(),
 		      csim.pages_with_swa(), csim.pages_in_bed(),
 		      csim.SWA_L(), csim.SWA_0(), csim.SWA_100());
diff --git a/src/ui/mf/mf_cb.cc b/src/ui/mf/mf_cb.cc
index e8873f6..4249259 100644
--- a/src/ui/mf/mf_cb.cc
+++ b/src/ui/mf/mf_cb.cc
@@ -282,11 +282,7 @@ eMFClassicFit_toggled_cb( GtkCheckButton *b, gpointer userdata)
 		for ( auto& M : MF.csimulation.mm_list() ) {
 			agh::beersma::SClassicFit borbely =
 				agh::beersma::classic_fit(
-					*M,
-					{ MF.csimulation.profile_type(),
-					  MF.csimulation.freq_from(), MF.csimulation.freq_upto(),
-					  .1,
-					  40 });
+					*M, { MF.csimulation.P(), .1, 40 });
 			rr[i] = borbely.r;
 
 			++i;
diff --git a/src/ui/mw/mw-construct.cc b/src/ui/mw/mw-construct.cc
index 0e96aed..f33d1da 100644
--- a/src/ui/mw/mw-construct.cc
+++ b/src/ui/mw/mw-construct.cc
@@ -169,6 +169,12 @@ SExpDesignUIWidgets ()
 	     !AGH_GBGETOBJ (GtkAdjustment,	jMsmtProfileParamsPSDFreqFrom)  ||
 	     !AGH_GBGETOBJ (GtkAdjustment,	jMsmtProfileParamsPSDFreqWidth) ||
 
+	     !AGH_GBGETOBJ (GtkSpinButton,	eMsmtProfileParamsSWUF0)  ||
+	     !AGH_GBGETOBJ (GtkAdjustment,	jMsmtProfileParamsSWUF0)  ||
+
+	     !AGH_GBGETOBJ (GtkSpinButton,	eMsmtProfileParamsMCF0)  ||
+	     !AGH_GBGETOBJ (GtkAdjustment,	jMsmtProfileParamsMCF0)  ||
+
 	     !AGH_GBGETOBJ (GtkLabel,		lMsmtProfilePSDExtra) ||
 	     !AGH_GBGETOBJ (GtkLabel,		lMsmtProfileSWUExtra) ||
 	     !AGH_GBGETOBJ (GtkLabel,		lMsmtProfileMCExtra) ||
@@ -189,6 +195,8 @@ SExpDesignUIWidgets ()
 
 	G_CONNECT_2 (eMsmtProfileParamsPSDFreqFrom, value, changed);
 	G_CONNECT_2 (eMsmtProfileParamsPSDFreqWidth, value, changed);
+	G_CONNECT_2 (eMsmtProfileParamsSWUF0, value, changed);
+	G_CONNECT_2 (eMsmtProfileParamsMCF0, value, changed);
 
       // ------------ menus
 	if ( !(AGH_GBGETOBJ (GtkMenu,		iiSubjectTimeline)) ||
diff --git a/src/ui/mw/mw-loadsave.cc b/src/ui/mw/mw-loadsave.cc
index fcb5577..132420d 100644
--- a/src/ui/mw/mw-loadsave.cc
+++ b/src/ui/mw/mw-loadsave.cc
@@ -132,8 +132,8 @@ load_settings()
 			geometry.h = h;
 		}
 	}
-	if ( operating_range_upto <= operating_range_from || operating_range_from <= 0. )
-		operating_range_from = 2., operating_range_upto = 3.;
+	if ( active_profile_psd_freq_upto <= active_profile_psd_freq_from )
+		active_profile_psd_freq_from = 2., active_profile_psd_freq_upto = 3.;
 
       // make sure ED has been created
 	_AghDi = find( AghDD.begin(), AghDD.end(), _aghdd_placeholder);
diff --git a/src/ui/mw/mw-measurements.cc b/src/ui/mw/mw-measurements.cc
index 75a03c5..d3eadab 100644
--- a/src/ui/mw/mw-measurements.cc
+++ b/src/ui/mw/mw-measurements.cc
@@ -78,7 +78,7 @@ draw_timeline( cairo_t *cr) const
 	cairo_show_text( cr, csubject.name());
 	cairo_stroke( cr);
 
-	if ( cscourse == nullptr || cscourse->mm_list().empty() ) {
+	if ( cprofile == nullptr || cprofile->mm_list().empty() ) {
 		cairo_move_to( cr, 50, timeline_height()/2+9);
 		cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
 		cairo_set_font_size( cr, 18);
@@ -138,9 +138,9 @@ draw_timeline( cairo_t *cr) const
 	cairo_move_to( cr, tl_left_margin() + j_tl_pixel_start, timeline_height()-12);
 	{
 		valarray<TFloat>
-			tmp (cscourse->timeline().size());
+			tmp (cprofile->timeline().size());
 		for ( size_t i = 0; i < tmp.size(); ++i )
-			tmp[i] = (*cscourse)[i].metric;
+			tmp[i] = (*cprofile)[i].metric;
 		sigproc::smooth( tmp, _p._p.smooth_profile);
 		for ( size_t i = 0; i < tmp.size(); ++i )
 			cairo_line_to( cr,
@@ -227,7 +227,7 @@ draw_timeline( cairo_t *cr) const
 		if ( _p._p.draw_nremrem_cycles ) {
 			auto& M = E.recordings.at(_p._p.AghH());
 			if ( M.have_uc_determined() ) {
-				agh::beersma::FUltradianCycle F (M.uc_params);
+				agh::beersma::FUltradianCycle F (*M.uc_params);
 				snprintf_buf( "T: %g  r: %g", F.T, F.r);
 				_p._p.CwB[TColour::power_mt].set_source_rgba_contrasting( cr);
 				cairo_move_to( cr, tl_left_margin() + e_pixel_start + 2, timeline_height() - 22);
diff --git a/src/ui/mw/mw-populate.cc b/src/ui/mw/mw-populate.cc
index fdc6e2e..eb98260 100644
--- a/src/ui/mw/mw-populate.cc
+++ b/src/ui/mw/mw-populate.cc
@@ -364,8 +364,10 @@ populate_1()
 
       // touch toolbar controls
 	suppress_redraw = true;
-	gtk_spin_button_set_value( eMsmtProfileParamsPSDFreqFrom, operating_range_from);
-	gtk_spin_button_set_value( eMsmtProfileParamsPSDFreqWidth, operating_range_upto - operating_range_from);
+	gtk_spin_button_set_value( eMsmtProfileParamsPSDFreqFrom, active_profile_psd_freq_from);
+	gtk_spin_button_set_value( eMsmtProfileParamsPSDFreqWidth, active_profile_psd_freq_upto - active_profile_psd_freq_from);
+	gtk_spin_button_set_value( eMsmtProfileParamsSWUF0, active_profile_swu_f0);
+	gtk_spin_button_set_value( eMsmtProfileParamsMCF0, active_profile_mc_f0);
 
       // deal with the main drawing area
 	groups.clear();
@@ -385,7 +387,7 @@ populate_1()
 		for ( auto &J : Gi->second ) {
 			Gp.emplace_back( J, Gp);
 			const SSubjectPresentation& j = Gp.back();
-			if ( j.cscourse && J.have_session(*_AghDi) ) {
+			if ( j.cprofile && J.have_session(*_AghDi) ) {
 				auto& ee = J.measurements[*_AghDi].episodes;
 				if ( not ee.empty() ) {
 					// (2)
diff --git a/src/ui/mw/mw-simulations.cc b/src/ui/mw/mw-simulations.cc
index 7df4c6b..6d94a50 100644
--- a/src/ui/mw/mw-simulations.cc
+++ b/src/ui/mw/mw-simulations.cc
@@ -24,7 +24,7 @@ populate_2()
 
       // clean up
 	ED->remove_untried_modruns();
-	GtkTreeIter iter_g, iter_j, iter_h, iter_m, iter_q;
+	GtkTreeIter iter_g, iter_j, iter_m, iter_h;
 
 	for ( auto &G : ED->groups ) {
 
@@ -35,8 +35,9 @@ populate_2()
 				    -1);
 
 		for ( auto &J : G.second ) {
+			auto& EE = J.measurements[*_AghDi];
 			if ( not J.have_session(*_AghDi) or
-			     J.measurements[*_AghDi].episodes.empty() ) // subject lacking one
+			     EE.episodes.empty() ) // subject lacking one
 				continue;
 
 			gtk_tree_store_append( mSimulations, &iter_j, &iter_g);
@@ -46,17 +47,17 @@ populate_2()
 					    -1);
 
 		      // collect previously obtained modruns
-			for ( auto &Q : J.measurements[*_AghDi].modrun_sets ) {
-				auto MT = Q.first;
-
+			for ( auto &MS : EE.modrun_sets ) {
+				const agh::SProfileParamSet& P = MS.first;
 				gtk_tree_store_append( mSimulations, &iter_m, &iter_j);
 				gtk_tree_store_set( mSimulations, &iter_m,
-						    0, metrics::metric_method(MT),
+						    0, P.display_name().c_str(),
 						    msimulations_visibility_switch_col, TRUE,
 						    -1);
 
-				for ( auto &RS : Q.second ) {
-					const string& H = RS.first;
+				for ( auto &HS : MS.second ) {
+					const string& H = HS.first;
+					const agh::ach::CModelRun& M = HS.second;
 
 					gtk_tree_store_append( mSimulations, &iter_h, &iter_m);
 					gtk_tree_store_set( mSimulations, &iter_h,
@@ -64,69 +65,49 @@ populate_2()
 							    msimulations_visibility_switch_col, TRUE,
 							    -1);
 
-					for ( auto &R : RS.second ) {
-						float	from = R.first.first,
-							upto = R.first.second;
-						auto&	M = R.second;
-
-						snprintf_buf( "%g\342\200\223%g", from, upto);
-						gtk_tree_store_append( mSimulations, &iter_q, &iter_h);
-						gtk_tree_store_set( mSimulations, &iter_q,
-								    0, __buf__,
-								    msimulations_modref_col, (gpointer)&M,
-								    msimulations_visibility_switch_col, TRUE,
-								    -1);
-						// status (put CF here)
-						snprintf_buf( "CF = %g", M.cf);
-						gtk_tree_store_set( mSimulations, &iter_q,
-								    1, __buf__,
-								    -1);
-
-						// tunable columns
-						for ( size_t t = 0; t < M.tx.size(); ++t ) {
-							auto tg = min(t, (size_t)agh::ach::TTunable::_basic_tunables - 1);
-							const auto& td = agh::ach::stock[tg];
-							snprintf_buf( td.fmt,
-								      M.tx[t] * td.display_scale_factor);
-							gtk_tree_store_set( mSimulations, &iter_q,
-									    2+t, __buf__, -1);
-						}
+					// status (put CF here)
+					snprintf_buf( "CF = %g", M.cf);
+					gtk_tree_store_set( mSimulations, &iter_h,
+							    1, __buf__,
+							    -1);
 
+					// tunable columns
+					for ( size_t t = 0; t < M.tx.size(); ++t ) {
+						auto tg = min(t, (size_t)agh::ach::TTunable::_basic_tunables - 1);
+						const auto& td = agh::ach::stock[tg];
+						snprintf_buf( td.fmt,
+							      M.tx[t] * td.display_scale_factor);
+						gtk_tree_store_set( mSimulations, &iter_h,
+								    2+t, __buf__, -1);
 					}
 				}
 			}
 		      // and a virgin offering
-			auto &lo = J.measurements[*_AghDi].modrun_sets[display_profile_type][AghT()];
-			if ( lo.find( pair<float,float> ({operating_range_from, operating_range_upto})) == lo.end() ) {
+			auto P_new = make_active_profile_paramset();
+			if ( EE.modrun_sets.find( P_new) == EE.modrun_sets.end() ) {
 
 				gtk_tree_store_append( mSimulations, &iter_m, &iter_j);
 				gtk_tree_store_set( mSimulations, &iter_m,
-						    0, metrics::metric_method(display_profile_type),
+						    0, P_new.display_name().c_str(),
 						    -1);
 				gtk_tree_store_append( mSimulations, &iter_h, &iter_m);
 				gtk_tree_store_set( mSimulations, &iter_h,
 						    0, AghT(),
 						    -1);
-				snprintf_buf( "%g\342\200\223%g *", operating_range_from, operating_range_upto);
-				gtk_tree_store_append( mSimulations, &iter_q, &iter_h);
-				gtk_tree_store_set( mSimulations, &iter_q,
-						    0, __buf__,
-						    -1);
 
 				agh::ach::CModelRun *virgin;
 				int retval =
 					ED->setup_modrun( J.name(), AghD(), AghT(),
-							  display_profile_type,
-							  operating_range_from, operating_range_upto,
+							  P_new,
 							  &virgin);
 				if ( retval ) {
-					gtk_tree_store_set( mSimulations, &iter_q,
-							    1, agh::CSCourse::explain_status( retval).c_str(),
+					gtk_tree_store_set( mSimulations, &iter_m,
+							    1, agh::CProfile::explain_status( retval).c_str(),
 							    msimulations_modref_col, NULL,
 							    -1);
 				} else {
-					gtk_tree_store_set( mSimulations, &iter_q,
-							    1, "untried",
+					gtk_tree_store_set( mSimulations, &iter_h,
+							    1, "(untried)",
 							    msimulations_modref_col, virgin,
 							    -1);
 				}
diff --git a/src/ui/mw/mw-simulations_cb.cc b/src/ui/mw/mw-simulations_cb.cc
index f711d9f..1083933 100644
--- a/src/ui/mw/mw-simulations_cb.cc
+++ b/src/ui/mw/mw-simulations_cb.cc
@@ -53,30 +53,30 @@ iSimulationsRunBatch_activate_cb( GtkMenuItem*, gpointer userdata)
       // prevent inapplicable inputs when type == mc
 	switch ( ED.display_profile_type ) {
 	case metrics::TType::psd:
-	{	auto bw = ED.operating_range_upto - ED.operating_range_from;
+	{	auto bw = ED.active_profile_psd_freq_upto - ED.active_profile_psd_freq_from;
 		gtk_spin_button_set_value( ED.eBatchSetupRangeWidth, bw);
 		gtk_spin_button_set_value( ED.eBatchSetupRangeInc, bw);
-	}	gtk_widget_set_sensitive( (GtkWidget*)ED.eBatchSetupRangeWidth, TRUE);
-		gtk_widget_set_sensitive( (GtkWidget*)ED.eBatchSetupRangeInc, TRUE);
+	}
+		for( auto& W : {ED.eBatchSetupRangeWidth, ED.eBatchSetupRangeInc, ED.eBatchSetupRangeSteps})
+			gtk_widget_set_visible( (GtkWidget*)W, TRUE);
 	    break;
 	case metrics::TType::swu:
-	{	auto bw = ED.operating_range_upto - ED.operating_range_from;
-		gtk_spin_button_set_value( ED.eBatchSetupRangeWidth, bw);
-		gtk_spin_button_set_value( ED.eBatchSetupRangeInc, bw);
-	}	gtk_widget_set_sensitive( (GtkWidget*)ED.eBatchSetupRangeWidth, TRUE);
-		gtk_widget_set_sensitive( (GtkWidget*)ED.eBatchSetupRangeInc, TRUE);
+		gtk_spin_button_set_value( ED.eBatchSetupRangeFrom, ED.active_profile_swu_f0);
+		for( auto& W : {ED.eBatchSetupRangeWidth, ED.eBatchSetupRangeInc, ED.eBatchSetupRangeSteps})
+			gtk_widget_set_visible( (GtkWidget*)W, FALSE);
 	    break;
 	case metrics::TType::mc:
-		gtk_spin_button_set_value( ED.eBatchSetupRangeWidth, ED.ED->mc_params.bandwidth);
-		gtk_spin_button_set_value( ED.eBatchSetupRangeInc, ED.ED->mc_params.bandwidth);
-		gtk_widget_set_sensitive( (GtkWidget*)ED.eBatchSetupRangeWidth, FALSE);
-		gtk_widget_set_sensitive( (GtkWidget*)ED.eBatchSetupRangeInc, FALSE);
+		gtk_spin_button_set_value( ED.eBatchSetupRangeFrom, ED.active_profile_mc_f0);
+		for( auto& W : {ED.eBatchSetupRangeWidth, ED.eBatchSetupRangeInc, ED.eBatchSetupRangeSteps})
+			gtk_widget_set_visible( (GtkWidget*)W, FALSE);
 	    break;
 	default:
 	    break;
 	}
 
 	if ( gtk_dialog_run( ED.wBatchSetup) == GTK_RESPONSE_OK ) {
+		aghui::SBusyBlock bb (ED.wMainWindow);
+
 		ED.ED->remove_untried_modruns();
 		ED.populate_2();
 
@@ -84,23 +84,45 @@ iSimulationsRunBatch_activate_cb( GtkMenuItem*, gpointer userdata)
 			use_subjects = agh::str::tokens( gtk_entry_get_text( ED.eBatchSetupSubjects), ";"),
 			use_sessions = agh::str::tokens( gtk_entry_get_text( ED.eBatchSetupSessions), ";"),
 			use_channels = agh::str::tokens( gtk_entry_get_text( ED.eBatchSetupChannels), ";");
-		float	freq_from  = gtk_spin_button_get_value( ED.eBatchSetupRangeFrom),
+		double	freq_from  = gtk_spin_button_get_value( ED.eBatchSetupRangeFrom),
 			freq_width = gtk_spin_button_get_value( ED.eBatchSetupRangeWidth),
 			freq_inc   = gtk_spin_button_get_value( ED.eBatchSetupRangeInc);
 		size_t	freq_steps = gtk_spin_button_get_value( ED.eBatchSetupRangeSteps);
 
-		aghui::SBusyBlock bb (ED.wMainWindow);
 		for ( auto& J : use_subjects )
 			for ( auto& D : use_sessions )
 				for ( auto& H : use_channels ) {
-					float	range_from = freq_from,
-						range_upto = freq_from + freq_width;
-					for ( size_t step = 0; step < freq_steps;
-					      ++step, range_from += freq_inc, range_upto += freq_inc ) {
+					switch ( ED.display_profile_type ) {
+					case metrics::TType::psd:
+					{	auto	this_freq_from = freq_from,
+							this_freq_upto = freq_from + freq_width;
+						for ( size_t step = 0; step < freq_steps;
+						      ++step, this_freq_from += freq_inc, this_freq_upto += freq_inc ) {
+							ED.ED->setup_modrun( J.c_str(), D.c_str(), H.c_str(),
+									     agh::SProfileParamSet (
+										     agh::SProfileParamSet::PSD {
+											     this_freq_from, this_freq_upto
+										     }
+									     ),
+									     nullptr);
+						}
+					}   break;
+					case metrics::TType::swu:
+						ED.ED->setup_modrun( J.c_str(), D.c_str(), H.c_str(),
+								     agh::SProfileParamSet (
+									     agh::SProfileParamSet::SWU {freq_from}
+								     ),
+								     nullptr);
+					    break;
+					case metrics::TType::mc:
 						ED.ED->setup_modrun( J.c_str(), D.c_str(), H.c_str(),
-								     ED.display_profile_type,
-								     range_from, range_upto,
+								     agh::SProfileParamSet (
+									     agh::SProfileParamSet::MC {freq_from}
+								     ),
 								     nullptr);
+					    break;
+					default:
+						throw runtime_error ("What metric is this?");
 					}
 				}
 		using namespace agh;
@@ -113,14 +135,13 @@ iSimulationsRunBatch_activate_cb( GtkMenuItem*, gpointer userdata)
 			[&ED]( const CJGroup&,
 			       const CSubject& J,
 			       const string& D,
-			       const metrics::TType& T,
+			       const agh::SProfileParamSet& T,
 			       const string& H,
-			       const pair<float,float>& Q,
 			       const ach::CModelRun&,
 			       size_t i, size_t n)
 			{
-				snprintf_buf( "(%zu of %zu) Running simulation in channel %s (%g-%g Hz) for %s (session %s) ...",
-					      i, n, H.c_str(), Q.first, Q.second,
+				snprintf_buf( "(%zu of %zu) Running simulation in channel %s (%s) for %s (session %s) ...",
+					      i, n, H.c_str(), T.display_name().c_str(),
 					      J.name(), D.c_str());
 				ED.buf_on_main_status_bar();
 				gtk_flush();
diff --git a/src/ui/mw/mw-widgets.hh b/src/ui/mw/mw-widgets.hh
index f4c902f..c9cd327 100644
--- a/src/ui/mw/mw-widgets.hh
+++ b/src/ui/mw/mw-widgets.hh
@@ -112,10 +112,14 @@ struct SExpDesignUIWidgets {
 		*cMsmtProfileParamsMC;
 	GtkSpinButton
 		*eMsmtProfileParamsPSDFreqFrom,
-		*eMsmtProfileParamsPSDFreqWidth;
+		*eMsmtProfileParamsPSDFreqWidth,
+		*eMsmtProfileParamsSWUF0,
+		*eMsmtProfileParamsMCF0;
 	GtkAdjustment
 		*jMsmtProfileParamsPSDFreqFrom,
-		*jMsmtProfileParamsPSDFreqWidth;
+		*jMsmtProfileParamsPSDFreqWidth,
+		*jMsmtProfileParamsSWUF0,
+		*jMsmtProfileParamsMCF0;
 
 	GtkLabel
 		*lMsmtProfilePSDExtra,
diff --git a/src/ui/mw/mw.cc b/src/ui/mw/mw.cc
index 41e117b..2800f69 100644
--- a/src/ui/mw/mw.cc
+++ b/src/ui/mw/mw.cc
@@ -41,28 +41,49 @@ SSubjectPresentation (agh::CSubject& _j,
 	_p (parent),
 	da (nullptr)
 {
-	cscourse = nullptr;
-	create_cscourse();
+	cprofile = nullptr;
+	create_cprofile();
+}
+
+
+agh::SProfileParamSet
+aghui::SExpDesignUI::
+make_active_profile_paramset() const
+{
+	switch ( display_profile_type ) {
+	case metrics::TType::psd:
+		return agh::SProfileParamSet (
+			agh::SProfileParamSet::PSD {active_profile_psd_freq_from, active_profile_psd_freq_upto}
+			);
+	case metrics::TType::swu:
+		return agh::SProfileParamSet (
+			agh::SProfileParamSet::SWU {active_profile_swu_f0}
+			);
+	case metrics::TType::mc:
+		return agh::SProfileParamSet (
+			agh::SProfileParamSet::MC {active_profile_mc_f0}
+			);
+	default:
+		throw runtime_error ("Which profile is this?");
+	}
 }
 
 
 void
 aghui::SExpDesignUI::SSubjectPresentation::
-create_cscourse()
+create_cprofile()
 {
-	if ( cscourse )
-		delete cscourse;
+	if ( cprofile )
+		delete cprofile;
 	try {
-		cscourse =
-			new agh::CSCourse (
+		agh::SProfileParamSet Pp;
+		cprofile =
+			new agh::CProfile (
 				csubject, *_p._p._AghDi, *_p._p._AghTi,
-				agh::SSCourseParamSet {
-					_p._p.display_profile_type,
-					_p._p.operating_range_from, _p._p.operating_range_upto,
-					0., 0, false});
+				_p._p.make_active_profile_paramset());
 		tl_start = csubject.measurements[*_p._p._AghDi].episodes.front().start_rel;
 	} catch (...) {  // can be invalid_argument (no recording in such session/channel) or some TSimPrepError
-		cscourse = nullptr;
+		cprofile = nullptr;
 		fprintf( stderr, "SSubjectPresentation::SSubjectPresentation(): subject %s has no recordings in session %s channel %s\n",
 			 csubject.name(), _p._p.AghD(), _p._p.AghT());
 	}
@@ -71,8 +92,8 @@ create_cscourse()
 aghui::SExpDesignUI::SSubjectPresentation::
 ~SSubjectPresentation ()
 {
-	if ( cscourse )
-		delete cscourse;
+	if ( cprofile )
+		delete cprofile;
 }
 
 
@@ -120,8 +141,10 @@ SExpDesignUI (aghui::SSessionChooser *parent,
 	dl_pid (-1),
 	close_this_SF_now (nullptr),
 	display_profile_type (metrics::TType::psd),
-	operating_range_from (2.),
-	operating_range_upto (3.),
+	active_profile_psd_freq_from (2.),
+	active_profile_psd_freq_upto (3.),
+	active_profile_swu_f0 (.5),
+	active_profile_mc_f0 (.5),
 	uc_accuracy_factor (1.),
 	pagesize_item (2),
 	binsize_item (1),
@@ -159,11 +182,13 @@ SExpDesignUI (aghui::SSessionChooser *parent,
 		confval::SValidator<int>("ModelRun.SWASmoothOver",		(int*)&SModelrunFacility::swa_smoothover,	confval::SValidator<int>::SVFRangeIn ( 1,   5)),
 	}),
 	config_keys_g ({
-		confval::SValidator<double>("UltradianCycleDetectionAccuracy",	&uc_accuracy_factor,			confval::SValidator<double>::SVFRangeIn (0.5, 20.)),
-		confval::SValidator<double>("Measurements.ProfileScalePSD",	&profile_scale_psd,			confval::SValidator<double>::SVFRangeIn (0., 1e10)), // can be 0, will trigger autoscale
-		confval::SValidator<double>("Measurements.ProfileScaleMC",	&profile_scale_mc,			confval::SValidator<double>::SVFRangeIn (0., 1e10)),
-		confval::SValidator<double>("Common.OperatingRangeFrom",	&operating_range_from,			confval::SValidator<double>::SVFRangeIn (0., 20.)),
-		confval::SValidator<double>("Common.OperatingRangeUpto",	&operating_range_upto,			confval::SValidator<double>::SVFRangeIn (0., 20.)),
+		confval::SValidator<double>("UltradianCycleDetectionAccuracy",	&uc_accuracy_factor,				confval::SValidator<double>::SVFRangeIn (0.5, 20.)),
+		confval::SValidator<double>("Measurements.ProfileScalePSD",	&profile_scale_psd,				confval::SValidator<double>::SVFRangeIn (0., 1e10)), // can be 0, will trigger autoscale
+		confval::SValidator<double>("Measurements.ProfileScaleMC",	&profile_scale_mc,				confval::SValidator<double>::SVFRangeIn (0., 1e10)),
+		confval::SValidator<double>("Profiles.PSD.FreqFrom",		&active_profile_psd_freq_from,			confval::SValidator<double>::SVFRangeIn (0., 20.)),
+		confval::SValidator<double>("Profiles.PSD.FreqUpto",		&active_profile_psd_freq_upto,			confval::SValidator<double>::SVFRangeIn (0., 20.)),
+		confval::SValidator<double>("Profiles.SWU.F0",			&active_profile_swu_f0,				confval::SValidator<double>::SVFRangeIn (0., 20.)),
+		confval::SValidator<double>("Profiles.MC.F0",			&active_profile_mc_f0,				confval::SValidator<double>::SVFRangeIn (0., 20.)),
 	})
 {
 	nodestroy_by_cb = true;
@@ -240,9 +265,9 @@ SExpDesignUI (aghui::SSessionChooser *parent,
 	W_V2.reg( eCtlParamDBAmendment1, &ED->ctl_params0.DBAmendment1);
 	W_V2.reg( eCtlParamDBAmendment2, &ED->ctl_params0.DBAmendment2);
 	W_V2.reg( eCtlParamAZAmendment1, &ED->ctl_params0.AZAmendment1);
-	W_V2.reg( eCtlParamNSWAPpBeforeSimStart, (int*)&ED->ctl_params0.swa_laden_pages_before_SWA_0);
-	W_V2.reg( eCtlParamReqScoredPercent, &ED->ctl_params0.req_percent_scored);
-	W_V2.reg( eCtlParamScoreUnscoredAsWake, &ED->ctl_params0.ScoreUnscoredAsWake);
+	W_V2.reg( eCtlParamNSWAPpBeforeSimStart, (int*)&ED->swa_laden_pages_before_SWA_0);
+	W_V2.reg( eCtlParamReqScoredPercent,           &ED->req_percent_scored);
+	W_V2.reg( eCtlParamScoreUnscoredAsWake,        &ED->score_unscored_as_wake);
 
 	// tunables are isolated so they can be reset separately
 	for ( size_t t = 0; t < agh::ach::TTunable::_basic_tunables; ++t ) {
@@ -420,9 +445,7 @@ do_detect_ultradian_cycle( agh::CRecording& M)
 	siman_params.t_min		=    5e-2;
 	agh::beersma::ultradian_cycles(
 		M,
-		{ display_profile_type,
-		  operating_range_from, operating_range_upto,
-		  .1, siman_params});
+		{make_active_profile_paramset(), .1, siman_params});
 }
 
 
@@ -464,8 +487,8 @@ calculate_profile_scale()
 	size_t	valid_episodes = 0;
 	for ( auto& G : groups )
 		for ( auto &J : G )
-			if ( J.cscourse && !J.cscourse->mm_list().empty() ) {
-				avg_profile_height += J.cscourse->metric_avg();
+			if ( J.cprofile && !J.cprofile->mm_list().empty() ) {
+				avg_profile_height += J.cprofile->metric_avg();
 				++valid_episodes;
 			}
 	avg_profile_height /= valid_episodes;
diff --git a/src/ui/mw/mw.hh b/src/ui/mw/mw.hh
index c8b0aaa..2a3a8fb 100644
--- a/src/ui/mw/mw.hh
+++ b/src/ui/mw/mw.hh
@@ -42,8 +42,7 @@ namespace aghui {
 
 class SExpDesignUI
   : public SExpDesignUIWidgets {
-
-	DELETE_DEFAULT_METHODS(SExpDesignUI);
+	DELETE_DEFAULT_METHODS (SExpDesignUI);
 
     public:
 	agh::CExpDesign
@@ -61,9 +60,9 @@ class SExpDesignUI
 	    public:
 		agh::CSubject&  // can't have it declared const due to CMSessionSet operator[] not permitting
 			csubject;
-		agh::CSCourse // a shortcut
-			*cscourse;
-		void create_cscourse();
+		agh::CProfile // a shortcut
+			*cprofile;
+		void create_cprofile();
 
 		list<agh::CSubject::SEpisode>&
 		sepisodesequence() const
@@ -90,11 +89,11 @@ class SExpDesignUI
 		size_t tl_left_margin() const	{ return _p._p.tl_left_margin; }
 		size_t tl_right_margin() const	{ return _p._p.tl_right_margin; }
 
-		void draw_timeline( cairo_t *cr) const;
+		void draw_timeline( cairo_t*) const;
 		void draw_timeline( const char *fname) const;
 
 		SGroupPresentation& _p;
-		SSubjectPresentation (agh::CSubject& _j, SGroupPresentation& parent);
+		SSubjectPresentation (agh::CSubject&, SGroupPresentation& parent);
 	       ~SSubjectPresentation ();
 
 		GtkWidget
@@ -217,12 +216,21 @@ class SExpDesignUI
 	void load_artifact_detection_profiles();
 	void save_artifact_detection_profiles() const;
 
-      // own variables aka saved settings
+      // displayed profile selector
 	metrics::TType
 		display_profile_type;
-	double	operating_range_from,
-		operating_range_upto;
+	// profile-specific variable parameter(s) exposed on main toolbar
+	// 1. PSD
+	double	active_profile_psd_freq_from,
+		active_profile_psd_freq_upto;
+	// 2. SWU
+	double	active_profile_swu_f0; // has to be a frequency, no doubt
+	// 3. MC
+	double	active_profile_mc_f0;
 
+	agh::SProfileParamSet make_active_profile_paramset() const;
+
+      // own variables aka saved settings
 	double	uc_accuracy_factor;
 	static const array<unsigned, 4>
 		FFTPageSizeValues;
diff --git a/src/ui/mw/mw_cb.cc b/src/ui/mw/mw_cb.cc
index 18868f7..b5494b7 100644
--- a/src/ui/mw/mw_cb.cc
+++ b/src/ui/mw/mw_cb.cc
@@ -62,7 +62,7 @@ tTaskSelector_switch_page_cb( GtkNotebook*, gpointer, guint page_num, gpointer u
 		gtk_label_set_markup( ED.lSimulationsSession, __buf__);
 		snprintf_buf( "Channel: <b>%s</b>", ED.AghT());
 		gtk_label_set_markup( ED.lSimulationsChannel, __buf__);
-		snprintf_buf( "Metric: <b>%s</b>", metrics::metric_method(ED.display_profile_type));
+		snprintf_buf( "Metric: <b>%s</b>", metrics::name( ED.display_profile_type));
 		gtk_label_set_markup( ED.lSimulationsProfile, __buf__);
 		gtk_widget_set_sensitive( (GtkWidget*)ED.iExpClose, FALSE);
 		ED.populate_2();
@@ -102,6 +102,7 @@ void
 eMsmtProfileType_changed_cb( GtkComboBox* b, gpointer userdata)
 {
 	auto& ED = *(SExpDesignUI*)userdata;
+
 	switch ( gtk_combo_box_get_active( b) ) {
 	case 0:
 		gtk_widget_set_visible( (GtkWidget*)ED.cMsmtProfileParamsPSD, TRUE);
@@ -123,15 +124,16 @@ eMsmtProfileType_changed_cb( GtkComboBox* b, gpointer userdata)
 	    break;
 	}
 
-	agh::SSCourseParamSet params {
-		ED.display_profile_type,
-		ED.operating_range_from, ED.operating_range_upto,
-		0., 0, false
-	};
+//	aghui::SBusyBlock bb (ED.wMainWindow);
+	auto params = ED.make_active_profile_paramset();
+	// don't let it throw on insufficiently scored recordings
+	params.req_percent_scored	= 0.;
+	params.swa_laden_pages_before_SWA_0 = 0u;
+
 	for ( auto &G : ED.groups )
 		for ( auto &J : G )
-			if ( J.cscourse )
-				J.cscourse->create_timeline( params);
+			if ( J.cprofile )
+				J.cprofile->create_timeline( params);
 
 	if ( ED.profile_scale_psd == 0. || ED.profile_scale_mc == 0. ||  // don't know which
 		ED.autoscale )
@@ -144,61 +146,86 @@ eMsmtProfileType_changed_cb( GtkComboBox* b, gpointer userdata)
 
 
 
-
-
+inline namespace {
 void
-eMsmtProfileParamsPSDFreqFrom_value_changed_cb( GtkSpinButton *spinbutton, gpointer userdata)
+mike_dewhirst_is_not_real( SExpDesignUI& ED)
 {
-	auto& ED = *(SExpDesignUI*)userdata;
-	ED.operating_range_from = gtk_spin_button_get_value( spinbutton);
-	ED.operating_range_upto = ED.operating_range_from + gtk_spin_button_get_value( ED.eMsmtProfileParamsPSDFreqWidth);
 	if ( ED.suppress_redraw )
 		return;
 
-	agh::SSCourseParamSet params {
-		ED.display_profile_type,
-		ED.operating_range_from, ED.operating_range_upto,
-		0., 0, false
-	};
-	params._freq_from = ED.operating_range_from;
-	params._freq_upto = ED.operating_range_upto;
+	auto params = ED.make_active_profile_paramset();
+	params.req_percent_scored	    = 0.;
+	params.swa_laden_pages_before_SWA_0 = 0u;
+	params.score_unscored_as_wake	    = false;
+
 	for ( auto &G : ED.groups )
 		for ( auto &J : G )
-			if ( J.cscourse )
-				J.cscourse->create_timeline( params);
+			if ( J.cprofile )
+				J.cprofile->create_timeline( params);
 	if ( ED.autoscale )
 		ED.calculate_profile_scale();
 
 	gtk_widget_queue_draw( (GtkWidget*)ED.cMeasurements);
 }
 
+}; // inline namespace
+
+void
+eMsmtProfileParamsPSDFreqFrom_value_changed_cb( GtkSpinButton *spinbutton, gpointer userdata)
+{
+	auto& ED = *(SExpDesignUI*)userdata;
+	ED.active_profile_psd_freq_from = gtk_spin_button_get_value( spinbutton);
+	ED.active_profile_psd_freq_upto =
+		ED.active_profile_psd_freq_from + gtk_spin_button_get_value( ED.eMsmtProfileParamsPSDFreqWidth);
+	if ( ED.suppress_redraw )
+		return;
+
+	mike_dewhirst_is_not_real(ED);
+}
+
 void
 eMsmtProfileParamsPSDFreqWidth_value_changed_cb( GtkSpinButton *spinbutton, gpointer userdata)
 {
 	auto& ED = *(SExpDesignUI*)userdata;
-	ED.operating_range_upto = ED.operating_range_from + gtk_spin_button_get_value( spinbutton);
+	ED.active_profile_psd_freq_upto =
+		ED.active_profile_psd_freq_from + gtk_spin_button_get_value( spinbutton);
 	if ( ED.suppress_redraw )
 		return;
 
-	agh::SSCourseParamSet params {
-		ED.display_profile_type,
-		ED.operating_range_from, ED.operating_range_upto,
-		0., 0, false
-	};
-	params._freq_from = ED.operating_range_from;
-	params._freq_upto = ED.operating_range_upto;
-	for ( auto &G : ED.groups )
-		for ( auto &J : G )
-			if ( J.cscourse )
-				J.cscourse->create_timeline( params);
-	if ( ED.autoscale )
-		ED.calculate_profile_scale();
-	gtk_widget_queue_draw( (GtkWidget*)ED.cMeasurements);
+	mike_dewhirst_is_not_real(ED);
 }
 
 
 
 
+void
+eMsmtProfileParamsSWUF0_value_changed_cb( GtkSpinButton *spinbutton, gpointer userdata)
+{
+	auto& ED = *(SExpDesignUI*)userdata;
+	ED.active_profile_swu_f0 = gtk_spin_button_get_value( spinbutton);
+
+	mike_dewhirst_is_not_real(ED);
+}
+
+
+
+
+void
+eMsmtProfileParamsMCF0_value_changed_cb( GtkSpinButton *spinbutton, gpointer userdata)
+{
+	auto& ED = *(SExpDesignUI*)userdata;
+	ED.active_profile_mc_f0 = gtk_spin_button_get_value( spinbutton);
+
+	mike_dewhirst_is_not_real(ED);
+}
+
+
+
+
+
+
+
+// session and channel selection
 
 void
 eMsmtSession_changed_cb( GtkComboBox *combobox, gpointer userdata)
diff --git a/src/ui/mw/mw_cb.hh b/src/ui/mw/mw_cb.hh
index 94bed66..b334216 100644
--- a/src/ui/mw/mw_cb.hh
+++ b/src/ui/mw/mw_cb.hh
@@ -49,7 +49,8 @@ void eMsmtSession_changed_cb( GtkComboBox*, gpointer);
 void eMsmtChannel_changed_cb( GtkComboBox*, gpointer);
 void eMsmtProfileParamsPSDFreqFrom_value_changed_cb( GtkSpinButton*, gpointer);
 void eMsmtProfileParamsPSDFreqWidth_value_changed_cb( GtkSpinButton*, gpointer);
-void eMsmtMCF0_value_changed_cb( GtkSpinButton*, gpointer);
+void eMsmtProfileParamsSWUF0_value_changed_cb( GtkSpinButton*, gpointer);
+void eMsmtProfileParamsMCF0_value_changed_cb( GtkSpinButton*, gpointer);
 
 void tvGlobalAnnotations_row_activated_cb( GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, gpointer);
 
diff --git a/src/ui/sf/sf-channel.cc b/src/ui/sf/sf-channel.cc
index 28efc40..28e0bb8 100644
--- a/src/ui/sf/sf-channel.cc
+++ b/src/ui/sf/sf-channel.cc
@@ -94,8 +94,8 @@ SChannel( agh::CRecording& r,
       // psd power and spectrum, mc
 	if ( sigfile::SChannel::signal_type_is_fftable( type) ) {
 	      // power in a single bin
-		psd.from = _p._p.operating_range_from;
-		psd.upto = _p._p.operating_range_upto;
+		psd.from = _p._p.active_profile_psd_freq_from;
+		psd.upto = _p._p.active_profile_psd_freq_upto;
 		get_psd_course();
 	      // power spectrum (for the first page)
 		spectrum_bins = last_spectrum_bin = crecording.psd_profile.bins();
@@ -114,13 +114,11 @@ SChannel( agh::CRecording& r,
 		get_psd_in_bands();
 
 	      // swu profile
-		swu.from = _p._p.operating_range_from;
-		swu.upto = _p._p.operating_range_upto;
+		swu.f0 = _p._p.active_profile_swu_f0;
 		get_swu_course();
 
 	      // mc profile
-		mc.from = _p._p.operating_range_from;
-		mc.upto = _p._p.operating_range_from + crecording.mc_profile.Pp.bandwidth;
+		mc.f0 = _p._p.active_profile_mc_f0;
 		get_mc_course();
 
 	      // delta comes first, calibrate display scale against it
@@ -238,7 +236,8 @@ aghui::SScoringFacility::SChannel::
 get_psd_course()
 {
 	//psd_profile.compute();
-	auto tmp = crecording.course<TFloat>( metrics::TType::psd, psd.from, psd.upto);
+	auto tmp = crecording.course(
+		agh::make_profile_paramset<metrics::TType::psd>( psd.from, psd.upto));
 	if ( resample_power ) {
 		auto xi = vector<size_t> (tmp.size());
 		for ( size_t i = 0; i < tmp.size(); ++i )
@@ -260,7 +259,7 @@ get_psd_in_bands()
 		for ( size_t b = 0; b <= psd.uppermost_band; ++b ) {
 			auto	_from = _p._p.freq_bands[b][0],
 				_upto = _p._p.freq_bands[b][1];
-			auto tmp = crecording.psd_profile.course<TFloat>( _from, _upto);
+			auto tmp = crecording.psd_profile.course( _from, _upto);
 			psd.course_in_bands[b] =
 				sigproc::interpolate( xi, 3600/_p.pagesize(),
 						      tmp,
@@ -271,7 +270,7 @@ get_psd_in_bands()
 			auto	_from = _p._p.freq_bands[b][0],
 				_upto = _p._p.freq_bands[b][1];
 			psd.course_in_bands[b] =
-				crecording.psd_profile.course<TFloat>( _from, _upto);
+				crecording.psd_profile.course( _from, _upto);
 		}
 }
 
@@ -281,7 +280,8 @@ aghui::SScoringFacility::SChannel::
 get_swu_course()
 {
 	//swu_profile.compute();
-	auto tmp = crecording.course<TFloat>( metrics::TType::swu, swu.from, swu.upto);
+	auto tmp = crecording.course(
+		agh::make_profile_paramset<metrics::TType::swu>( swu.f0));
 	if ( resample_power ) {
 		auto xi = vector<size_t> (tmp.size());
 		for ( size_t i = 0; i < tmp.size(); ++i )
@@ -297,7 +297,8 @@ aghui::SScoringFacility::SChannel::
 get_mc_course()
 {
 	//mc_profile.compute();
-	auto tmp = crecording.course<TFloat>( metrics::TType::mc, mc.from, mc.upto);
+	auto tmp = crecording.course(
+		agh::make_profile_paramset<metrics::TType::mc>( mc.f0));
 	if ( resample_power ) {
 		auto xi = vector<size_t> (tmp.size());
 		for ( size_t i = 0; i < tmp.size(); ++i )
@@ -314,13 +315,13 @@ void
 aghui::SScoringFacility::SChannel::
 get_spectrum( size_t p)
 {
-	spectrum = crecording.psd_profile.spectrum<TFloat>( p);
+	spectrum = crecording.psd_profile.spectrum( p);
 }
 void
 aghui::SScoringFacility::SChannel::
 get_spectrum()
 {
-	spectrum = crecording.psd_profile.spectrum<TFloat>( _p.cur_page());
+	spectrum = crecording.psd_profile.spectrum( _p.cur_page());
 }
 
 
@@ -527,8 +528,8 @@ _put_selection()
 		_p.artifact_detection_dialog.W_V.down();
 		auto& P = _p.artifact_detection_dialog.P;
 		auto sssu =
-			metrics::mc::CProfile::do_sssu_reduction(
-				signal_filtered[ slice (selection_start, (selection_end - selection_start), 1) ],
+			metrics::mc::do_sssu_reduction(
+				valarray<TFloat> {signal_filtered[ slice (selection_start, (selection_end - selection_start), 1) ]},
 				samplerate(), (selection_end - selection_start) / samplerate(),
 				P.mc_gain, P.iir_backpolate,
 				P.f0, P.fc, P.bandwidth);
diff --git a/src/ui/sf/sf-phasediff.cc b/src/ui/sf/sf-phasediff.cc
index 4f81529..454af52 100644
--- a/src/ui/sf/sf-phasediff.cc
+++ b/src/ui/sf/sf-phasediff.cc
@@ -151,8 +151,8 @@ draw( cairo_t* cr, int wd, int ht)
 
       // psd course in selected freq range
 	{
-		auto	C1 = channel1->crecording.psd_profile.course<TFloat>( from, upto);
-//			C2 = channel2->crecording.psd_profile.course<TFloat>( from, upto) * display_scale + ht/2;
+		auto	C1 = channel1->crecording.psd_profile.course( from, upto);
+//			C2 = channel2->crecording.psd_profile.course( from, upto) * display_scale + ht/2;
 
 		ED.CwB[SExpDesignUI::TColour::profile_psd_sf].set_source_rgba( cr, .5);
 		auto	scale =
diff --git a/src/ui/sf/sf.cc b/src/ui/sf/sf.cc
index 47b01b8..d1583dd 100644
--- a/src/ui/sf/sf.cc
+++ b/src/ui/sf/sf.cc
@@ -285,7 +285,7 @@ redraw_ssubject_timeline() const
 {
 	auto j = _p.subject_presentation_by_csubject( _csubject);
 	if ( j ) {
-		j->create_cscourse();
+		j->create_cprofile();
 		gtk_widget_queue_draw( (GtkWidget*)j->da);
 	}
 }
diff --git a/src/ui/sf/sf.hh b/src/ui/sf/sf.hh
index ec36fac..347c4cf 100644
--- a/src/ui/sf/sf.hh
+++ b/src/ui/sf/sf.hh
@@ -170,7 +170,7 @@ class SScoringFacility
 		struct SProfileSWU {
 			valarray<TFloat>
 				course;
-			double	from, upto;
+			double	f0;
 			double	display_scale;
 		};
 		void get_swu_course();
@@ -181,7 +181,7 @@ class SScoringFacility
 			valarray<TFloat>
 				course;
 			double	display_scale;
-			double	from, upto; // approximate
+			double	f0;
 		};
 		SProfileMC
 			mc;
diff --git a/src/ui/sf/sf_cb.cc b/src/ui/sf/sf_cb.cc
index 449a37e..41a68de 100644
--- a/src/ui/sf/sf_cb.cc
+++ b/src/ui/sf/sf_cb.cc
@@ -234,7 +234,7 @@ iSFAcceptAndTakeNext_activate_cb( GtkMenuItem *menuitem, gpointer userdata)
 	auto& SF = *(SScoringFacility*)userdata;
 	auto& ED = SF._p; // keep same parent
 
-	ED.using_subject->create_cscourse();
+	ED.using_subject->create_cprofile();
 	gtk_widget_queue_draw( (GtkWidget*)ED.using_subject->da);
 
 	SBusyBlock bb (SF.wScoringFacility);

-- 
Sleep experiment manager



More information about the debian-med-commit mailing list