qub_adaptive_resample.cpp.html |
mathcode2html
|
Source file: qub_adaptive_resample.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-2011 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/>. */
/*
*/
#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_adaptive_resample.h"
#include "qub_mean.h"
#include "qub_eventmaker.h"
typedef struct {
int Cls, N;
} NCls;
typedef struct {
int First, Last;
double Mean, Std;
} ResIval;
class ResTree {
public:
int First, Last;
double Mean, Std;
ResTree *Left, *Right;
ResTree(int aFirst, int aLast)
: First(aFirst), Last(aLast), Left(NULL), Right(NULL)
{}
~ResTree() {
if ( Left ) delete Left;
if ( Right ) delete Right;
}
void split() {
// Assert((Left = nil) and (Right = nil), 'TAdResTree.Split: not a leaf node');
int count = Last - First + 1;
splitBefore(First + (count / 2));
}
void splitBefore(int RightFirst) {
Left = new ResTree(First, RightFirst-1);
Right = new ResTree(RightFirst, Last);
}
void calcMeanStd(float* data) {
int n = Last - First + 1;
qub_mean_rss(data+First, n, &Mean, &Std);
if ( n <= 1 )
Std = 0.0;
else
Std = sqrt(Std / (n-1));
}
void splitStd(float* data, double MaxStd) {
if ( ! Left ) {
calcMeanStd(data);
if ( Std > MaxStd )
split();
}
if ( Left ) {
Left->splitStd(data, MaxStd);
Right->splitStd(data, MaxStd);
}
}
};
class ResTreeDFS {
private:
bool LeavesOnly;
vector<ResTree*> ToVisit;
void push(ResTree* node) { ToVisit.push_back(node); }
ResTree* pop() {
ResTree* result = ToVisit.back();
ToVisit.pop_back();
return result;
}
public:
ResTree* Here;
ResTreeDFS(ResTree* Root, bool aLeavesOnly)
: LeavesOnly(aLeavesOnly), Here(NULL)
{
push(Root);
}
bool next() { // returns false if no more
bool result = ToVisit.size();
if ( result ) {
Here = pop();
if ( Here->Left ) {
push(Here->Right);
push(Here->Left);
if ( LeavesOnly )
result = next();
}
}
return result;
}
};
//******************************************************************************
extern "C" QUBFAST_API int qub_adaptive_resample(float *data, int ndata, double MaxStd,
float *out_mean, float *out_std,
int *out_first, int *out_last, int *out_closest)
// Fills out_* with a reduced form of data, as intervals with all out_std[i] <= MaxStd (binary decomposition).
// @param data: sampled input array
// @param ndata: length of data array
// @param MaxStd: desired ceiling for out_std[i]
// @param out_mean: array of each interval's mean value; must have room for up to ndata intervals
// @param out_std: array of each interval's standard deviation
// @param out_first: array of each interval's first sample index, relative to start of data
// @param out_last: array of each interval's final sample index
// @param out_closest: array of closest sample index to mean in each interval
// @returns: number of intervals
{
ResTree *tree = new ResTree(0, ndata-1);
tree->splitStd(data, MaxStd);
int out_i=0;
ResTreeDFS *trav = new ResTreeDFS(tree, true);
while ( trav->next() ) {
out_first[out_i] = trav->Here->First;
out_last[out_i] = trav->Here->Last;
out_mean[out_i] = (float) trav->Here->Mean;
if ( out_std )
out_std[out_i] = (float) trav->Here->Std;
if ( out_closest) {
out_closest[out_i] = out_first[out_i];
double closest_diff = fabs(data[out_first[out_i]] - out_mean[out_i]);
for (int j=out_first[out_i]; j<=out_last[out_i]; ++j) {
double diff = fabs(data[j] - out_mean[out_i]);
if ( diff < closest_diff ) {
out_closest[out_i] = j;
closest_diff = diff;
}
}
}
++out_i;
}
delete trav;
delete tree;
return out_i;
}
//******************************************************************************
class qub_adres
{
public:
double amp_delta;
double min_dur_ms;
double sampling_ms;
QUB_EventMaker_ByGauss eventMaker;
qub_adres(double _amp_delta, double _min_dur_ms, double _sampling_ms)
: amp_delta(_amp_delta), min_dur_ms(_min_dur_ms), sampling_ms(_sampling_ms)
{}
~qub_adres()
{}
void add(float *samples, int sample_count)
{
vector<float> means(sample_count), stds(sample_count);
vector<int> ff(sample_count), ll(sample_count);
int Nevent = qub_adaptive_resample(samples, sample_count, amp_delta, & means[0], & stds[0], & ff[0], & ll[0], NULL);
for (int i=0; i<Nevent; ++i) {
eventMaker.add_event(means[i], ((float)(sample_count-1))*squared(stds[i]), ll[i]-ff[i]+1);
}
}
void done_add()
{
eventMaker.done_add();
eventMaker.combine_all(amp_delta);
}
int get_class_count()
{
return eventMaker.class_count();
}
int get_dist(double *amps, double *stds)
{
eventMaker.get_dist(& amps[0], & stds[0]);
return eventMaker.class_count();
}
int get_next_dwells(int offset_in_data, int sample_count, int *firsts, int *lasts, int *classes, float *durations)
{
int ndwt = eventMaker.get_next_dwells(offset_in_data, sample_count, firsts, lasts, classes);
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_adres_create(double amp_delta, double min_dur_ms, double sampling_ms)
{
return new qub_adres(amp_delta, min_dur_ms, sampling_ms);
}
QUBFAST_API void qub_adres_destroy(void *adres)
{
delete (qub_adres*) adres;
}
QUBFAST_API void qub_adres_add(void *adres, float *samples, int count)
{
((qub_adres*) adres)->add(samples, count);
}
QUBFAST_API void qub_adres_done_add(void *adres)
{
((qub_adres*) adres)->done_add();
}
QUBFAST_API int qub_adres_get_class_count(void *adres)
{
return ((qub_adres*) adres)->get_class_count();
}
QUBFAST_API int qub_adres_get_dist(void *adres, double *amps, double *stds)
{
return ((qub_adres*) adres)->get_dist(amps, stds);
}
QUBFAST_API int qub_adres_get_next_dwells(void *adres, int offset_in_data, int sample_count,
int *firsts, int *lasts, int *classes, float *durations)
{
return ((qub_adres*) adres)->get_next_dwells(offset_in_data, sample_count, firsts, lasts, classes, durations);
}