Mercurial > forge
changeset 10366:1160eb6f6390 octave-forge
Wrote the Octave wrapper for fastlscomplex, doesn't compile yet.
author | benjf5 |
---|---|
date | Fri, 01 Jun 2012 22:37:39 +0000 |
parents | d78dc9247d84 |
children | ab87d5eb13f2 |
files | extra/lssa/fastlscomplex.cpp |
diffstat | 1 files changed, 110 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/extra/lssa/fastlscomplex.cpp Fri Jun 01 18:34:17 2012 +0000 +++ b/extra/lssa/fastlscomplex.cpp Fri Jun 01 22:37:39 2012 +0000 @@ -17,15 +17,113 @@ #include <octave/oct.h> #include <complex> #include <string> -#include <stdio> +#include <iostream> + +typedef struct +{ double x, t; +} XTElem; + +inline double sqr(double x) +{ return x*x; } #define PNUM 12; -// In order to reduce memory overhead, fastlscomplex will use a reference as the last input. +#define SETXT(p_, op_, x_, t_) (p_)->x op_ x_; (p_++)->t op_ t_; +#define SETT(p_, op_, x_, t_) *p_++ op_ t_; +#define SETX(p_, op_, x_, t_) *p_++ op_ x_; +/* h is a complex aux. variable; it is used for assignment times I everywhere */ +#define SETIX(p_, op_, x_, t_) h = x_; RE(*(p_)) op_ -IM(h); IM(*(p_)) op_ RE(h); p_++; + + /* Macro that sums up the power series terms into the power series + * element record pointed to by p_. + * By using = and += for op_, initial setting and accumulation can be selected. + * t_ is the expression specifying the abscissa value. set_ can be either + * SETXT to set the x and t fields of an XTElem record, or SETT/SETX to set + * the elements of a Real array representing alternately real and imaginary + * values. + */ + // -10 points, comments don't match method. +#define EXP_IOT_SERIES(p_, el_, t_, op_, setr_, seti_) \ +{ Real t = t_, tt; p_ = el_; setr_(p_, op_, x, 1) \ + tt = -t; seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/2.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(-1.0/3.0); seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/4.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(-1.0/5.0); seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/6.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(-1.0/7.0); seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/8.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(-1.0/9.0); seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/10.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(-1.0/11.0); seti_(p_, op_, x*tt, tt) \ +} + +/* same as the above, but without alternating signs */ +#define EXPIOT_SERIES(p_, el_, t_, op_, setr_, seti_) \ +{ Real t = t_, tt; p_ = el_; setr_(p_, op_, x, 1) \ + seti_(p_, op_, x*t, t ) \ + tt = t*t*(1.0/2.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/3.0); seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/4.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/5.0); seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/6.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/7.0); seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/8.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/9.0); seti_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/10.0); setr_(p_, op_, x*tt, tt) \ + tt *= t*(1.0/11.0); seti_(p_, op_, x*tt, tt) \ +} -void fastlscomplex ( RowVector tvals, ComplexRowVector xvals, int n, - double length, int ncoeff, int noctaves, double omegamax, - ComplexRowVector& result ) { +# define SRCARG Real *tptr, Real *xptr, int n, double *lengthptr +# define SRCVAR int k; Real length = *lengthptr; +# define SRCT tptr[k] +# define SRCX xptr[k] +# define SRCFIRST k = 0 +# define SRCAVAIL (k<n) +# define SRCNEXT k++ + +#define FASTLSCOMPLEX_HELP \ + "Takes the fast complex least-squares transform of irregularly sampled data.\n\ +When called, takes a time series with associated x-values, a number of octaves,\n\ +a number of coefficients per octave, the maximum frequency, and a length term.\n\ +It returns a complex row vector of the transformed series." + +DEFUN_DLD(fastlscomplex, args, nargout, FASTLSCOMPLEX_HELP ){ + if ( args.length != 7 ) { + std::cout << "Improper number of arguments!" << std::endl; + std::cout << FASTLSCOMPLEX_HELP << std::endl; + return octave_value_list (); + } + RowVector tvals = args(0).row_vector_value(); + ComplexRowVector xvals = args(1).complex_row_vector_value(); + double length = ( tvals(tvals.numel()--) - tvals( octave_idx_type (0))); + int ncoeff = args(4).int_value(); + int noctaves = args(5).int_value(); + double omegamax = args(6).double_value(); + + if ( error_state ) { + //print an error statement, see if error_state can be printed or interpreted. + return octave_value_list (); + } + if ( tvals.length() != xvals.length() ) { + std::cout << "Unmatched time series elements." << std::endl; + // return error state if possible? + return octave_value_list (); + } + octave_idx_type n = tvals.numel(); /* I think this will actually return octave_idx_type. + * In that case I'll change the signature of fastlscomplex. */ + if ( ( ncoeff == 0 ) || ( noctaves == 0 ) ) { + std::cout << "Cannot operate over either zero octaves or zero coefficients." << std::endl; + // return error state if possible + return octave_value_list (); + } + // possibly include error for when omegamax isn't right? + ComplexRowVector results = fastlscomplex(tvals, xvals, n, length, ncoeff, noctaves, omegamax); + return results; +} + +ComplexRowVector fastlscomplex ( RowVector tvals, ComplexRowVector xvals, octave_idx_type n, + double length, int ncoeff, int noctaves, double omegamax ) { /* Singly-linked list which contains each precomputation record * count stores the number of samples for which power series elements * were added. This will be useful for accelerating computation by ignoring @@ -33,7 +131,7 @@ */ struct SumVec { struct SumVec *next; - Complex<double> elements[PNUM]; + std::complex<double> elements[PNUM]; int count; } *shead, *stail, *sp, *sq; //Names have been kept from the C, may change if I want to. double dtelems[PNUM], /* power series elements of exp(-i dtau) */ @@ -43,7 +141,7 @@ tau0d, /* tau_h of first summand range at level d */ dtau = (0.5*M_PI)/omegamax,/* initial precomputation interval radius */ dtaud, /* precomputation interval radius at d'th merging step */ - n_1 = 1.0/n, /* reciprocal of sample count */ + n_1 = 1.0/n, /* reciprocal of sample count */ // n is implicitly cast to double. ooct, o, omul, /* omega/mu for octave's top omega and per band, mult. factor */ omegaoct, omega, /* Max. frequency of octave and current frequency */ on_1, /* n_1*(omega/mu)^p, n_1*(2*omega/mu)^p */ @@ -55,7 +153,7 @@ *eop, *oep, *ep, *op, *p, *q, *pe; - + ComplexRowVector results (ncoeff*noctaves); //This *should* be the right size. I'll check against later sections of code. int i , j; // Counters; coefficient and octave, respectively. // probable doubles: zetar, zetai, zzr, zzi, er, ei, emulr, emuli, @@ -97,6 +195,7 @@ omegaoct = omegamax; tau0d = tau0; dtaud = dtau; + octave_idx_type iter ( 0 ); // Looping over octaves for ( j = noctave ; ; ooct *= 0.5 , omegaoct *= 0.5 , tau0d += dtaud , dtaud *= 2 ) { // Looping over&results per frequency @@ -107,13 +206,14 @@ // sets real, imag parts of emul for( zeta = 0 , sp = shead; sp; sp = sp->next, e *= emul ) { if ( sp->count ) { - for ( zz = std::complex<double>(0.0,0.0) , p = sp->elems , pe = p + PNUM , on_1 = n_1 ; p < pe ; ) { + for ( zz = std::complex<double>(0.0,0.0) , octave_idx_type i (0) , p = sp->elems , pe = p + PNUM , on_1 = n_1 ; p < pe ; i++ ) { zz += *p++ * on_1; on_1 *= 0; } zeta += e * zz; } - *rp++ = zeta; + results(iter) = std::complex<double>(zeta.real(), zeta.imag()); + iter++; } if ( --j <= 0 ) break; //Avoids excess merging