qub_idlstim.cpp.html mathcode2html   
 Source file:   qub_idlstim.cpp
 Converted:   Thu Feb 26 2015 at 13:39:00
 This documentation file will not reflect any later changes in the source file.

$$\phantom{******** If you see this on the webpage then the browser could not locate *********}$$
$$\phantom{******** jsMath/easy/load.js or the variable root is set wrong in this file *********}$$
$$\newcommand{\vector}[1]{\left[\begin{array}{c} #1 \end{array}\right]}$$ $$\newenvironment{matrix}{\left[\begin{array}{cccccccccc}} {\end{array}\right]}$$ $$\newcommand{\A}{{\cal A}}$$ $$\newcommand{\W}{{\cal W}}$$

/* Copyright 2008-2015 Research Foundation State University of New York   */

/* This file is part of QUB Express.                                      */

/* QUB Express is free software; you can redistribute it and/or modify    */
/* it under the terms of the GNU General Public License as published by   */
/* the Free Software Foundation, either version 3 of the License, or      */
/* (at your option) any later version.                                    */

/* QUB Express is distributed in the hope that it will be useful,         */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/* GNU General Public License for more details.                           */

/* You should have received a copy of the GNU General Public License,     */
/* named LICENSE.txt, in the QUB Express program directory.  If not, see  */
/* <http://www.gnu.org/licenses/>.                                        */

/*
Up
*/

#ifdef _WIN32
  #include <windows.h>
  #include <time.h>
  #define sleep Sleep
#else
  #include <stdlib.h>
  #define BOOL int
  #define TRUE 1
  #define FALSE 0
#endif

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <math.h>
#include <string.h>

#include "qub_idlstim.h"
#include "qub_eventmaker.h"

class qub_idlstim
{
public:
  int add_deltas;
  double amp_delta;
  double min_dur_ms;
  double sampling_ms;
  std::vector<double> known;
  EventMaker eventMaker;

  qub_idlstim(double *_amps, int _amp_count, int _add_deltas, double _amp_delta, double _min_dur_ms, double _sampling_ms)
    : add_deltas(_add_deltas), amp_delta(_amp_delta), min_dur_ms(_min_dur_ms), sampling_ms(_sampling_ms)
  {
    for (int i=0; i<_amp_count; ++i)
      known.push_back(_amps[i]);
  }
  
  ~qub_idlstim()
  {}
  
  void add(float *samples, int sample_count)
  {
    std::vector<double> pageAmps(sample_count);
    std::vector<int> pageAmpAssigned(sample_count);
    // set pageAmps to nearest known, with pageAmpAssigned telling if it's within delta
    if ( known.size() )
      for (int i=0; i<sample_count; ++i)
	pageAmpAssigned[i] = FindKnownAmp(known, samples[i], amp_delta, pageAmps[i]);
    
    // set the rest of the pageamps to delta-separated levels if requested
    double amp = 0.0;
    int count = 0;
    if ( add_deltas ) {
      for ( int i=0; i < sample_count; ++i ) {
	// end-of-event ?
	if ( (count==0) || pageAmpAssigned[i] || (fabs(amp - samples[i]) >= amp_delta) ) {
	  // assign pageAmps for last event
	  if ( count ) {
	    double avg = 0.0;
	    for ( int j=count; j>0; --j )
	      avg += samples[i-j];
	    avg /= count;
	    for ( int j=count; j>0; --j )
	      pageAmps[i-j] = avg;
	  }
	  
	  // setup next event, ignoring assigned (known)
	  if ( pageAmpAssigned[i] ) {
	    count = 0;
	  } else {
	    count = 1;
	    amp = samples[i];
	  }
	}
	else {
	  ++count;
	}
      }
      // assign pageAmps for last event (last count points of page)
      if ( count ) {
	double avg = 0.0;
	for ( int j=count; j>0; --j )
	  avg += samples[sample_count-j];
	avg /= count;
	for ( int j=count; j>0; --j )
	  pageAmps[sample_count-j] = avg;
      }
    }

    // generate events
    amp = pageAmps[0];
    count = 1;
    for ( int i=1; i<sample_count; ++i ) {
      if ( amp != pageAmps[i] ) {
	eventMaker.add(amp, count);
	amp = pageAmps[i];
	count = 1;
      }
      else {
	++count;
      }
    }
    if ( count ) {
      eventMaker.add(amp, count);
    }
  }
  
  void done_add()
  {
    int StopFlag = 0; // bogus
    eventMaker.consolidate(amp_delta, known, StopFlag);
  }
  
  int get_amp_count()
  {
    return (int) eventMaker.ampOfCls.size();
  }
  
  int get_amps(double *amps)
  {
    int n = (int) eventMaker.ampOfCls.size();
    memcpy(amps, &(eventMaker.ampOfCls[0]), n*sizeof(double));
    return n;
  }
  
  int get_next_dwells(int offset_in_data, int sample_count, int *firsts, int *lasts, int *classes, float *durations)
  {
    int last = offset_in_data - 1;
    int ndwt = 0;
    int cls, count;
    while ( sample_count ) {
      eventMaker.nextEvent(cls, count, sample_count);
      if ( ! count )
	break; // should never happen if add's counts match get_next_dwells's
      sample_count -= count;
      firsts[ndwt] = last + 1;
      last += count;
      lasts[ndwt] = last;
      classes[ndwt] = cls;
      ++ndwt;
    }
    if ( min_dur_ms > 0.0 ) {
      ndwt = delete_short_events(ndwt, firsts, lasts, classes, int(ceil(min_dur_ms / sampling_ms)));
    }
    if ( durations ) {
      for (int i=0; i<ndwt; ++i)
	durations[i] = (float) ((lasts[i] - firsts[i] + 1) * sampling_ms);
    }
    return ndwt;
  }
};


QUBFAST_API void*  qub_idlstim_create(double *amps, int amp_count, int add_deltas, double amp_delta, double min_dur_ms, double sampling_ms)
{
  return new qub_idlstim(amps, amp_count, add_deltas, amp_delta, min_dur_ms, sampling_ms);
}

QUBFAST_API void   qub_idlstim_destroy(void *idlstim)
{
  delete (qub_idlstim*) idlstim;
}

QUBFAST_API void   qub_idlstim_add(void *idlstim, float *samples, int count)
{
  ((qub_idlstim*) idlstim)->add(samples, count);
}

QUBFAST_API void   qub_idlstim_done_add(void *idlstim)
{
  ((qub_idlstim*) idlstim)->done_add();
}

QUBFAST_API int    qub_idlstim_get_amp_count(void *idlstim)
{
  return ((qub_idlstim*) idlstim)->get_amp_count();
}

QUBFAST_API int    qub_idlstim_get_amps(void *idlstim, double *amps)
{
  return ((qub_idlstim*) idlstim)->get_amps(amps);
}

QUBFAST_API int    qub_idlstim_get_next_dwells(void *idlstim, int offset_in_data, int sample_count,
					       int *firsts, int *lasts, int *classes, float *durations)
{
  return ((qub_idlstim*) idlstim)->get_next_dwells(offset_in_data, sample_count, firsts, lasts, classes, durations);
}