Skip to content

Commit

Permalink
espan opts
Browse files Browse the repository at this point in the history
  • Loading branch information
remnrem committed Nov 1, 2024
1 parent e9d19da commit f78d4e1
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 32 deletions.
41 changes: 36 additions & 5 deletions annot/annot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5908,6 +5908,12 @@ void annotation_set_t::espan( edf_t & edf , param_t & param )

// verbose mode: list all individual annots (original and curtailed)
const bool verbose = param.has( "verbose" );

// outputs: sec pct has (bool,0/1) cnt (of unflattened)
const bool show_sec = param.has( "sec" ) ? param.yesno( "sec" ) : true ;
const bool show_pct = param.has( "pct" ) ? param.yesno( "pct" ) : false ;
const bool show_cnt = param.has( "cnt" ) ? param.yesno( "cnt" ) : false ;
const bool show_has = param.has( "has" ) ? param.yesno( "has" ) : false ;

// iterate over epochs
int ne = edf.timeline.first_epoch();
Expand Down Expand Up @@ -5963,6 +5969,7 @@ void annotation_set_t::espan( edf_t & edf , param_t & param )
if ( verbose )
{
writer.level( ++ac , globals::annot_instance_strat );

writer.value( "START" , ii->first.interval.start_sec() );
writer.value( "STOP" , ii->first.interval.stop_sec() );
writer.value( "DUR" , ii->first.interval.duration_sec() );
Expand All @@ -5987,22 +5994,46 @@ void annotation_set_t::espan( edf_t & edf , param_t & param )
evs = annotate_t::flatten( evs );

uint64_t span_tp = interval_t::sum( evs );
writer.value( "PCT" , span_tp / (double)epoch_tp );
writer.value( "SEC" , span_tp * globals::tp_duration );

// epoch data

if ( show_pct )
writer.value( "PCT" , span_tp / (double)epoch_tp );

if ( show_sec )
writer.value( "SEC" , span_tp * globals::tp_duration );

if ( show_has )
writer.value( "HAS" , (int)( span_tp != 0 ) ) ;

if ( show_cnt )
writer.value( "CNT" , (int)events.size() );

// next annot class
++aa;
}

writer.unlevel( globals::annot_strat );

// flatten global tracker
const int n0 = allevs.size();

// flatten global tracker
allevs = annotate_t::flatten( allevs );

uint64_t span_tp = interval_t::sum( allevs );
writer.value( "PCT" , span_tp / (double)epoch_tp );
writer.value( "SEC" , span_tp * globals::tp_duration );

if ( show_pct )
writer.value( "PCT" , span_tp / (double)epoch_tp );

if ( show_sec )
writer.value( "SEC" , span_tp * globals::tp_duration );

if ( show_has )
writer.value( "HAS" , (int)( span_tp != 0 ));

if ( show_cnt )
writer.value( "CNT" , n0 );

// next epoch
}

Expand Down
2 changes: 1 addition & 1 deletion dsp/lat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ lat_t::lat_t( edf_t & edf , param_t & param )
if ( nreps )
{
trans_level_output = true;
logger << " applying " << nreps << " shuffles to derive empirical expecations for TR_NR2R and TR_R2NR\n";
logger << " applying " << nreps << " shuffles to derive empirical expectations for TR_NR2R and TR_R2NR\n";
}


Expand Down
5 changes: 5 additions & 0 deletions edf/masks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@ void proc_mask( edf_t & edf , param_t & param )
edf.timeline.trim_epochs( label , n );
}

if ( param.has( "retain" ) )
{
edf.timeline.retain_epochs( param.strset( "retain" ) );
}

if ( param.has( "epoch" ) || param.has( "mask-epoch" ) )
{
// epoch --> 'force' mode (i.e. set all)
Expand Down
4 changes: 2 additions & 2 deletions helper/helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1394,7 +1394,7 @@ void clocktime_t::advance_seconds( double secs )
double t_sec = seconds( d );

t_sec += secs;

// need to wrap? (86400 seconds in a day)
// (adjusting 'd' if appropriate)
while ( 1 )
Expand All @@ -1414,7 +1414,7 @@ void clocktime_t::advance_seconds( double secs )
if ( d ) ++d;
}
}

// update this time back to usual format
convert_seconds( t_sec );
}
Expand Down
49 changes: 35 additions & 14 deletions suds/features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,16 +253,23 @@ int suds_indiv_t::proc_extract_observed_stages( suds_helper_t * helper )
if ( has_staging && helper->edf.timeline.hypnogram.empty() )
has_staging = false;

// exclude gaps from stages epoch count
int ne_ss = 0;
for (int i=0; i<helper->edf.timeline.hypnogram.stages.size(); i++)
if ( helper->edf.timeline.hypnogram.stages[i] != GAP ) ++ne_ss;

if ( ! has_staging )
{
if ( suds_t::soap_mode ) return 0; // okay to skip for SOAP
// but flag as major prob if a trainer
Helper::halt( "problem extracting stage information for trainer" );
Helper::halt( "problem extracting stage information for trainer: no staging info" );
}

// total number of epochs does not match?
if ( helper->ne != helper->edf.timeline.hypnogram.stages.size() )
Helper::halt( "problem extracting stage information for trainer" );
if ( helper->ne != ne_ss )
Helper::halt( "problem extracting stage information for trainer: have "
+ Helper::int2str( helper->ne ) + " epochs but found stage info for "
+ Helper::int2str( ne_ss ) );

helper->has_prior_staging = true;

Expand All @@ -279,8 +286,14 @@ int suds_indiv_t::proc_extract_observed_stages( suds_helper_t * helper )

if ( helper->has_prior_staging )
{

// exclude gaps from stages epoch count
int ne_ss = 0;
for (int i=0; i<helper->edf.timeline.hypnogram.stages.size(); i++)
if ( helper->edf.timeline.hypnogram.stages[i] != GAP ) ++ne_ss;

// total number of epochs does not match?
if ( helper->ne != helper->edf.timeline.hypnogram.stages.size() )
if ( helper->ne != ne_ss )
Helper::halt( "problem extracting stage information for trainer" );
}

Expand All @@ -289,6 +302,14 @@ int suds_indiv_t::proc_extract_observed_stages( suds_helper_t * helper )
// nb. overkill to have two staging classifications, but keep for now,
// i.e. we may want to extend one type only

// drop any gaps
// exclude gaps from stages epoch count
std::vector<sleep_stage_t> stages;
for (int i=0; i<helper->edf.timeline.hypnogram.stages.size(); i++)
if ( helper->edf.timeline.hypnogram.stages[i] != GAP )
stages.push_back( helper->edf.timeline.hypnogram.stages[i] );


//
// number of good (retained) epochs
//
Expand All @@ -302,28 +323,28 @@ int suds_indiv_t::proc_extract_observed_stages( suds_helper_t * helper )

for (int ss=0; ss < helper->ne ; ss++ )
{
if ( helper->edf.timeline.hypnogram.stages[ ss ] == UNSCORED
|| helper->edf.timeline.hypnogram.stages[ ss ] == MOVEMENT
|| helper->edf.timeline.hypnogram.stages[ ss ] == UNKNOWN )
if ( stages[ ss ] == UNSCORED
|| stages[ ss ] == MOVEMENT
|| stages[ ss ] == UNKNOWN )
obs_stage[ss] = SUDS_UNKNOWN;

else if ( helper->edf.timeline.hypnogram.stages[ ss ] == LIGHTS_ON )
else if ( stages[ ss ] == LIGHTS_ON )
obs_stage[ss] = SUDS_LIGHTS;

else if ( helper->edf.timeline.hypnogram.stages[ ss ] == WAKE )
else if ( stages[ ss ] == WAKE )
obs_stage[ss] = SUDS_WAKE;

else if ( helper->edf.timeline.hypnogram.stages[ ss ] == NREM1 )
else if ( stages[ ss ] == NREM1 )
obs_stage[ss] = suds_t::n_stages == 3 ? SUDS_NR : SUDS_N1;

else if ( helper->edf.timeline.hypnogram.stages[ ss ] == NREM2 )
else if ( stages[ ss ] == NREM2 )
obs_stage[ss] = suds_t::n_stages == 3 ? SUDS_NR : SUDS_N2;

else if ( helper->edf.timeline.hypnogram.stages[ ss ] == NREM3
|| helper->edf.timeline.hypnogram.stages[ ss ] == NREM4 )
else if ( stages[ ss ] == NREM3
|| stages[ ss ] == NREM4 )
obs_stage[ss] = suds_t::n_stages == 3 ? SUDS_NR : SUDS_N3;

else if ( helper->edf.timeline.hypnogram.stages[ ss ] == REM )
else if ( stages[ ss ] == REM )
obs_stage[ss] = SUDS_REM;


Expand Down
148 changes: 147 additions & 1 deletion timeline/epoch-mask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ void timeline_t::select_epoch_randomly( int n )
}


// trim leading and trailing epochs (allow only n)
// trim leading and trailing epochs (allow only n)
void timeline_t::trim_epochs( std::string & label , int n )
{

Expand Down Expand Up @@ -880,6 +880,152 @@ void timeline_t::trim_epochs( std::string & label , int n )
}


// retain contiguous stretch of epochs that include these (+/- n epochs on both sides)
void timeline_t::retain_epochs( const std::set<std::string> & labels )
{

// find first and last examples epochs w/ one of these labels (e.g. a sleep label)
// expand outwards n epochs (if possible)
// mask leading and trailing gaps
// if no matches, then blank all

// if one label is +int then interpret as n epoch border, not as a label
int n = 0;

int first = -1;
int last = -1;

const int ne = epochs.size();

std::set<std::string>::const_iterator aa = labels.begin();
while ( aa != labels.end() )
{

// matches +n ?
if ( aa->substr(0,1) == "+" )
{
if ( Helper::str2int( aa->substr(1) , &n ) )
{
++aa;
continue;
}
}

// treat as annot
annot_t * annot = annotations( Helper::unquote( *aa ) );

if ( annot == NULL ) { ++aa; continue; }

// find first match
// -1 if no leading matches
int leading_end = -1;
for (int e=0;e<ne;e++)
{
// already gone past a prior mark?
if ( e >= first && first != -1 ) break;

interval_t interval = epoch( e );
annot_map_t events = annot->extract( interval );
if ( events.size() > 0 )
{
first = e;
break;
}
}

// find final match
int trailing_start = ne;
for (int e=ne-1;e>=0;e--)
{
// already gone past a prior mark?
if ( e <= last && last != -1 ) break;
interval_t interval = epoch( e );
annot_map_t events = annot->extract( interval );
if ( events.size() > 0 )
{
last = e;
break;
}
}

// look to next annotation now
++aa;
}

//
// any matches? if not, mask all epochs
//

const bool no_matches = first == -1;


// else mark up to 'first' (not including) and after 'last' (not including)

mask_set = true;

// adjust by up to 'n' epochs

first = first > n ? first - n : 0 ;
last = (last + n ) < ne ? last + ne : ne - 1 ;

if ( no_matches ) logger << " did not find any matching epochs, masking all epochs\n";
else logger << " retaining from epoch " << first
<< " to " << last
<< " ( " << last - first + 1 << " epochs ), given up to " << n << " epoch border\n";

int cnt_mask_set = 0;
int cnt_mask_unset = 0;
int cnt_unchanged = 0;
int cnt_now_unmasked = 0;
int cnt_basic_match = 0; // basic count of matches, whether changes mask or not
// blank out any ones needed
for ( int e=0; e<ne; e++)
{
if ( no_matches || e < first || e > last )
{
++cnt_basic_match;

// set new potential mask, depending on match_mode

bool new_mask = true;

int mc = set_epoch_mask( e , new_mask );

if ( mc == +1 ) ++cnt_mask_set;
else if ( mc == -1 ) ++cnt_mask_unset;
else ++cnt_unchanged;
}

if ( !mask[e] ) ++cnt_now_unmasked;

}

std::string lstr = Helper::stringize( labels );

logger << " based on retained region " << lstr << " (w/ up to " << n << " epochs) "
<< cnt_basic_match << " epochs match; ";

logger << cnt_mask_set << " newly masked, "
<< cnt_mask_unset << " unmasked, "
<< cnt_unchanged << " unchanged\n";
logger << " total of " << cnt_now_unmasked << " of " << epochs.size() << " retained\n";

// mask, # epochs masked, # epochs unmasked, # unchanged, # total masked , # total epochs

writer.level( lstr , "EMASK" );
writer.value( "N_MATCHES" , cnt_basic_match );
writer.value( "N_MASK_SET" , cnt_mask_set );
writer.value( "N_MASK_UNSET" , cnt_mask_unset );
writer.value( "N_UNCHANGED" , cnt_unchanged );
writer.value( "N_RETAINED" , cnt_now_unmasked );
writer.value( "N_TOTAL" , (int)epochs.size() );

writer.unlevel( "EMASK" );

}



void timeline_t::unmask_interior()
{
// look back / forward y epochs;
Expand Down
Loading

0 comments on commit f78d4e1

Please sign in to comment.