/*-------------------------------------------------------
* Package: Wavelet Analysis Tool
* File name: wavedata.cc
*-------------------------------------------------------
*/
//________________________________________________________
// WaveData class is the base class for generic wavelet
// data structures and methods.
#ifndef _STREAM_H
#include <stream.h>
#define _STREAM_H
#endif
#ifndef _WDATA_H
#include "wavedata.h"
#endif
#ifdef _USE_ROOT
ClassImp(WaveData)
#endif
/*********************************************************************
* Default constructor
*********************************************************************/
WaveData::WaveData() : N(0), data(NULL) {}
/*********************************************************************
* Constructor which allocates space for data array with
* N=n elements of type "wavereal".
*********************************************************************/
WaveData::WaveData(int n)
{
if (n <= 0 ) n = 1;
data = new wavereal[n];
N = n;
}
/*********************************************************************
* Copy constructor
*********************************************************************/
WaveData::WaveData(const WaveData& a)
{
N = a.N;
Rate = a.Rate;
data = NULL;
if (a.N>0) {
data = new wavereal[a.N];
for (int i=0; i < N; i++) data[i] = a.data[i];
}
}
/*********************************************************************
* Destructor
*********************************************************************/
WaveData::~WaveData()
{
if(data != NULL) delete [] data;
}
WaveData& WaveData::operator=(const WaveData& a)
{
if (this != &a) {
if (N != a.N) Resize(a.N);
for (int i=0; i < N; i++) data[i] = a.data[i];
Rate = a.Rate;
}
return *this;
}
WaveData& WaveData::operator=(const WaveData* a)
{ return *this=*a; }
// assign value c to all array elements
WaveData& WaveData::operator=(const wavereal c)
{
for (int i=0; i < N; i++) data[i] = c;
return *this;
}
WaveData& WaveData::operator+=(const WaveData &a)
{
if (Rate != a.Rate) {
cout <<
" Error: attempt to use operator += for data with different sample rate.n";
cout <<" Data unchanged!n";
}
if (N != a.N) {
cout <<
" Error: attempt to use operator += for data with different length.n";
cout <<" Data unchanged!n";
return *this;
}
for (int i=0; i < N; i++) data[i] += a.data[i];
return *this;
}
WaveData& WaveData::operator+=(const WaveData *a)
{ return *this+=*a; }
WaveData& WaveData::operator-=(const WaveData &a)
{
if (Rate != a.Rate) {
cout <<
" Error: attempt to use operator -= for data with different sample rate.n";
cout <<" Data unchanged!n";
return *this;
}
if (N != a.N) {
cout <<
" Error: attempt to use operator -= for data with different length.n";
cout <<" Data unchanged!n";
return *this;
}
for (int i=0; i < N; i++) data[i] -= a.data[i];
return *this;
}
WaveData& WaveData::operator-=(const WaveData *a)
{ return *this-=*a; }
// add constant shift to all elements of array
WaveData& WaveData::operator+=(const wavereal c)
{
for (int i=0; i < N; i++) data[i] += c;
return *this;
}
/*********************************************************************
* subtract constant shift from all elements of array
*********************************************************************/
WaveData& WaveData::operator-=(const wavereal c)
{
for (int i=0; i < N; i++) data[i] -= c;
return *this;
}
/*********************************************************************
* multiply all elements of data array by constant
*********************************************************************/
WaveData& WaveData::operator*=(const wavereal c)
{
for (int i=0; i < N; i++) data[i] *= c;
return *this;
}
/*********************************************************************
* Dumps data array to file *fname in ASCII format.
*********************************************************************/
void WaveData::Dump(const char *fname, int app)
{
// Dumps data array to file *fname in ASCII format.
//
int n=N;
char *mode = "w";
if (app == 1) mode = "a";
FILE *fp;
if ( (fp = fopen(fname, mode)) == NULL ) {
cout << " Dump() error: cannot open file " << fname <<". n";
return;
};
for (int i = 0; i < n; i++) fprintf( fp,"%e n", data[i]);
fclose(fp);
}
/*********************************************************************
* Dumps data array to file *fname in binary format and type "wavereal".
*********************************************************************/
void WaveData::DumpBinary(const char *fname, int app)
{
// Dumps data array to file *fname in binary format and type "wavereal".
//
int n = N * sizeof(wavereal);
char *mode = "wb";
if (app == 1) mode = "ab";
FILE *fp;
if ( (fp=fopen(fname, mode)) == NULL ) {
cout << " DumpBinary() error : cannot open file " << fname <<". n";
return ;
}
// cout << "Writing binary record, size="<< n <<"n";
fwrite(data, n, 1, fp);
fclose(fp);
}
/*********************************************************************
* Dumps data array to file *fname in binary format and type "short".
*********************************************************************/
void WaveData::DumpShort(const char *fname, int app)
{
// Dumps data array to file *fname in binary format and type "short".
//
int n = N;
char *mode = "wb";
if (app == 1) mode = "ab";
FILE *fp;
if ( (fp = fopen(fname, mode)) == NULL ) {
cout << " DumpShort() error : cannot open file " << fname <<". n";
return;
}
short *dtemp;
dtemp=new short[n];
for ( int i=0; i<n; i++ ) dtemp[i]=short(data[i]) ;
n = n * sizeof(short);
// cout << " Writing binary record, size="<< n <<"n";
fwrite(dtemp, n, 1, fp);
fclose(fp);
delete [] dtemp;
}
void WaveData::ReadBinary(const char *fname)
{
// Read data from file in binary format. Type of data is wavereal.
//
int step = sizeof(wavereal);
FILE *fp;
wavereal d;
if ( (fp=fopen(fname,"rb")) == NULL ) {
cout << " ReadBinary() error : cannot open file " << fname <<". n";
return;
}
if(N == 0){ // find the data length
while(!feof(fp)){
fread(&d,step,1,fp);
N++;
}
N--;
rewind(fp);
Resize(N);
}
int n = N * sizeof(wavereal);
fread(data, n, 1, fp); // Reading binary record
fclose(fp);
}
void WaveData::ReadShort(const char *fname)
{
// Read data from file with given filename in written in binary format as short.
//
short *dtmp;
dtmp = new short[N];
int n = N * sizeof(short);
FILE *fp;
if ( (fp=fopen(fname,"rb")) == NULL ) {
cout << " ReadShort() error : cannot open file " << fname <<". n";
return;
}
cout << " Reading binary record, size="<< n <<"n";
fread(dtmp, n, 1, fp);
for (int i = 0; i < N; i++) data[i] = wavereal(dtmp[i]);
fclose(fp);
}
/*********************************************************************
* Dumps spectrum of current signal to text file *fname,
* option=2 corresponds to power spectrum,
* option=1 corresponds to square root of power spectrum (default)
* This function does not change the original signal
*********************************************************************/
void WaveData::DumpSpectrum(const char *fname, int option)
{
wavereal x,y,s,df;
FILE *fp;
if ( (fp=fopen(fname,"w")) == NULL )
{ cout << "Cannot open file " << fname <<". n"; return;};
WaveData *td;
td=new WaveData(N);
for (int i=0;i<N;i++) td->data[i]=data[i];
td->FFT();
x=td->data[0];
s=sqrt(x*x);
df=Rate/N;
// print value for frequency=0
fprintf(fp,"%14.6f %14.6en",0.,s);
// print Fourier without F[0]
for (int i=1;i<N/2;i++)
{ x=td->data[2*i];
y=td->data[2*i+1];
s=2.*(x*x+y*y);
// option=2 mean power spectrum
// =1 -> sqrt(power) spectrum
if (option==1) s=sqrt(x*x+y*y);
fprintf(fp,"%14.6f %14.6en",df*i,s);
}
// F[n/2] is not printed
fclose(fp);
delete td;
}
/*********************************************************************
* Resizes data array of the object to a new value N=n.
*********************************************************************/
void WaveData::Resize(int n)
{
if(data != NULL) delete [] data;
data = new wavereal[n];
N = n;
}
/*********************************************************************
* Calculates and returns mean and root mean square of the signal.
*********************************************************************/
inline void WaveData::getStatistics(wavereal &mean, wavereal &rms)
{
// Calculates and returns mean and root mean square of the signal.
//
wavereal v;
mean = 0.;
rms = 0.;
for (int i=0;i<N;i++) {
v=data[i];
mean +=v;
rms += v*v;
}
mean /= double(N);
rms /= double(N);
rms -= mean*mean;
rms=sqrt(rms);
return;
}
/************************************************************************
* Creates new data set by resampling original data from "WaveData &a" *
* with new sample frequency "f". Uses polynomial interpolation scheme *
* (Lagrange formula) with np-points, "np" must be even number, by *
* default np=6 (corresponds to 5-th order polynomial interpolation). *
* This function calls WaveData::Resize() function to adjust *
* current data array if it's size does not exactly match new number *
* of points. *
************************************************************************/
void WaveData::Resample(WaveData const &a, wavereal f, int np)
{
int i1, imax, n1, n2, n, np2 = np/2;
wavereal s, x, *c, *v;
c=new wavereal[np];
v=new wavereal[np];
Rate = f;
n = a.N;
imax = int(a.N * Rate / a.Rate + 0.5);
if ( N != imax ) Resize(imax);
// calculate constant filter part c(k) = -(-1)^k/k!/(np-k-1)!
for (int i = 0; i < np; i++) {
int m = 1;
for (int j = 0; j < np; j++) if (j != i) m *= (i - j);
c[i] = 1./double(m);
}
for (int i = 0; i < N; i++)
{
x = i*a.Rate/Rate;
i1 = int(x);
x = x - i1 + np2 - 1;
// to treat data boundaries we need to calculate critical numbers n1 and n2
n1 = i1 - np2 + 1;
n2 = i1 + np2 + 1 - n;
// here we calculate the sum of products like h(k)*a(k), k=0..np-1,
// where h(k) are filter coefficients, a(k) are signal samples
// h(k) = c(k)*prod (x-i), i != k, c(k) = -(-1)^k/k!/(np-k-1)!
// get signal part multiplied by constant filter coefficients
if ( n1 >= 0 )
if ( n2 <= 0 )
// regular case - far from boundaries
for (int j = 0; j < np; j++) v[j] = c[j]*a.data[i1 + j - np2 + 1];
else {
// right border case
x = x + n2;
for (int j = 0; j < np; j++) v[j] = c[j]*a.data[n + j - np];
}
else {
// left border case
x = x + n1;
for (int j = 0; j < np; j++) v[j] = c[j]*a.data[j];
}
// multiply resulted v[j] by x-dependent factors (x-k), if (k != j)
for (int k = 0; k < np; k++) {
for (int j = 0; j < np; j++) if (j != k) v[j] *= x;
x -= 1.; }
s = 0.;
for (int j = 0; j < np; j++) s += v[j];
data[i] = s;
}
delete [] c;
delete [] v;
}
/******************************************************************************
* copies data from data array of the object WaveData a to *this
* object data array. Procedure starts from the element "a_pos" in
* the source array which is copied to the element "pos" in the
* destination array. "length" is the number of data elements to copy.
* By default "length"=0, which means copy all source data or if destination
* array is shorter, copy data until the destination is full.
*****************************************************************************/
void WaveData::cpf(const WaveData &a,
int length=0, int a_pos=0, int pos=0)
{
if (length == 0 )
length = ((N - pos) < (a.N - a_pos))? (N - pos) : (a.N - a_pos);
if( length > (N - pos) ) length = N - pos;
if( length > (a.N - a_pos) ) length = a.N - a_pos;
for (int i = 0; i < length; i++)
data[i + pos] = a.data[i + a_pos];
Rate = a.Rate;
}
/******************************************************************************
* Adds data from data array of the object WaveData a to *this
* object data array. Procedure starts from the element "a_pos" in
* the source array which is added starting from the element "pos" in the
* destination array. "length" is the number of data elements to add.
* By default "length"=0, which means add all source data or if destination
* array is shorter, add data up to the end of destination.
*****************************************************************************/
inline void WaveData::add( const WaveData &a,
int length = 0, int a_pos = 0, int pos = 0 )
{
if (Rate != a.Rate) {
cout << " Error: attempt to add data with different sample rate.n";
return;
}
if (length == 0 )
length = ((N - pos) < (a.N - a_pos))? (N - pos) : (a.N - a_pos);
if( length > (N - pos) ) length = N - pos;
if( length > (a.N - a_pos) ) length = a.N - a_pos;
for (int i = 0; i < length; i++)
data[i + pos] += a.data[i + a_pos];
}
/******************************************************************************
* Substracts data array of the object WaveData a from *this
* object data array. Procedure starts from the element "a_pos" in
* the source array which is subtracted starting from the element "pos" in
* the destination array. "length" is number of data elements to subtract.
* By default "length"=0, which means subtract all source data or if the
* destination array is shorter, subtract data up to the end of destination.
******************************************************************************/
inline void WaveData::sub(const WaveData &a, int length = 0,
int a_pos = 0, int pos = 0 )
{
if (Rate != a.Rate) {
cout << " Error: attempt to subtract data with different sample rate.n";
return;
}
if ( length == 0 )
length = ((N - pos) < (a.N - a_pos))? (N - pos) : (a.N - a_pos);
if( length > (N - pos) ) length = N - pos;
if( length > (a.N - a_pos) ) length = a.N - a_pos;
for (int i = 0; i < length; i++)
data[i + pos] -= a.data[i + a_pos];
}
/*****************************************************************
* Calculates Fourier Transform for real signal using
* Fast Fourier Transform (FFT) algorithm. Packs resulting
* complex data into original array of real numbers.
* Calls wavefft() function which is capable to deal with any
* number of data points. FFT(1) means forward transformation,
* which is default, FFT(-1) means inverse transformation.
*****************************************************************/
void WaveData::FFT(int direction=1)
{
double *a, *b;
int n2=N/2;
a=new double[N];
b=new double[N];
switch (direction)
{ case 1:
// direct transform
for (int i=0; i<N; i++) { a[i]=data[i]; b[i]=0.;}
wavefft(a, b, N, N, N, -1);
// pack complex numbers to real array
for (int i=0;i<n2;i++)
{ data[2*i]=a[i]/N;
data[2*i+1]=b[i]/N; }
// data[1] is not occupied because imag(F[0]) is always zero and we
// store in data[1] the value of F[N/2] which is pure real for even "N"
data[1]=a[n2]/N;
// in the case of odd number of data points we store imag(F[N/2])
// in the last element of array data[N]
if ((N&1) == 1) data[N-1]=b[n2]/N;
break;
case -1:
// inverse transform
// unpack complex numbers from real array
for (int i=1;i<n2;i++)
{ a[i]=data[2*i];
b[i]=data[2*i+1];
a[N-i]=data[2*i];
b[N-i]=-data[2*i+1];
}
a[0]=data[0];
b[0]=0.;
if ((N&1) == 1)
{ a[n2]=data[1]; b[n2]=data[N-1]; } // for odd n
else
{ a[n2]=data[1]; b[n2]=0.; }
wavefft(a, b, N, N, N, 1); // call FFT for inverse tranform
for (int i=0; i<N; i++) data[i]=a[i]; // copy result from array "a"
}
delete [] b;
delete [] a;
}
/*************************************************************************
* Stack generates WaveData *this by stacking data from WaveData td.
* Input data are devided on subsets with with samples "length"
* then they are added together. Average over the all subsets is saved in
* *this.
*************************************************************************/
inline wavereal WaveData::Stack(const WaveData &td, int length)
{
wavereal ss, s0, s2;
Rate = td.Rate;
int k = td.N/length;
int n = k*length;
if (k == 0) {
cout <<" Stack() error: data length too short to contain n"
<< length << " samplesn";
return 0.;
}
if (N != length) Resize(length);
// sum (stack) all k periods of frequency f to produce 1 cycle
s0 = 0.;
for (int i = 0; i < length; i++) {
ss = 0.;
for (int j = i; j < n; j += length) ss += td.data[j];
data[i] = ss/k;
s0 += ss;
}
s0 /= (k*length);
// remove constant displacement (zero frequency component)
s2 = 0.;
for (int i = 0; i < length; i++) {
data[i] -= s0;
s2 += data[i]*data[i];
}
s2 /= length;
return s2; // return stacked signal power (energy/N)
}
/*************************************************************************
* Another version of Stack:
* Input data (starting from sample "start") are devided on "k" subsets
* with sections "length"
* Average over the all sections is saved in *this.
*************************************************************************/
inline wavereal WaveData::Stack(const WaveData &td,
int length,
int start){
wavereal avr, rms;
Rate = td.Rate;
if(start+length > td.N) length = td.N-start;
int k = (N<1) ? 0 : length/N;
if (k == 0) {
cout <<" Stack() error: data length too short to contain n"
<< length << " samplesn";
return 0.;
}
*this = 0.;
for (int i = 0; i<k; i++) add(td, N, start+i*N);
*this *= 1./k;
getStatistics(avr,rms);
*this -= avr;
return rms*rms; // return stacked signal power
}
inline wavereal WaveData::Stack(const WaveData &td, wavereal window)
{
// Stack generates WaveData *this by stacking data from WaveData td.
// Input data are devided on subsets with with samples "length"
// then they are added together. Average over the all subsets is saved in
// *this.
return this->Stack(td, int(td.Rate * window)); }
#ifdef _USE_DMT
WaveData& WaveData::operator=(const TSeries &ts)
{
Interval ti = ts.getTStep();
wavereal Tsample = ti.GetSecs();
int n=ts.getNSample();
if(n != N) Resize(n);
if ( Tsample > 0. )
Rate = 1./Tsample;
else {
cout <<" Invalid sampling interval = 0 sec.\n";
}
TSeries r(ts.getStartTime(), ti, ts.getNSample());
r = ts;
float *vec_ref;
vec_ref= (float*)(r.refData());
for ( int i=0; i<n; i++ ) data[i]=wavereal(vec_ref[i]);
return *this;
}
WaveData& WaveData::operator=(const TSeries *ts)
{ return *this=*ts; }
#endif // use DMT
#ifdef _USE_ROOT
// Stream a WaveData object. Required by ROOT system for
// reading and writing the object to file.
void WaveData::Streamer(TBuffer &b)
{
int n;
if (b.IsReading()) {
Version_t v = b.ReadVersion();
Wavelet::Streamer(b);
b >> n;
if (n != N) Resize(n);
//cout <<" Reading data array of N="<<N<<" elements."<<"n";
b.ReadFastArray(data,N);
b >> Rate;
} else {
b.WriteVersion(WaveData::IsA());
Wavelet::Streamer(b);
b << N;
//cout <<" Writing data array of N="<<N<<" elements."<<"n";
b.WriteFastArray(data,N);
b << Rate;
}
}
#endif
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.