src/harmonic.h
Harmonic decomposition
The harmonic_decomposition()
function performs a
continuous, least-square fit of the coefficients Z and (a_i,b_i) of the harmonic fonction
Z + \sum_i a_i \cos(\omega_i t) + b_i \sin(\omega_i t)
to the scalar field s
, with the \omega_i given as input.
If the optional argument e
is given, it is used to store
the residual (i.e. the standard deviation) of the fit.
attribute {
struct {
double * omega;
scalar * A, * B, Z, E;
double ** M, ** Mn;
bool invertible;
} harmonic;
}
static double de (int n, double * ha, double * hx, double ** M)
{
double xm = ha[2*n];
double e = xm*(M[2*n][2*n]*xm - 2.*hx[2*n]);
for (int i = 0; i < n; i++) {
+= 2.*(ha[i]*(xm*M[i][2*n] - hx[i]) +
e [n + i]*(xm*M[n + i][2*n] - hx[n + i]));
hafor (int j = 0; j < n; j++)
+= (ha[i]*ha[j]*M[j][i] +
e [n + i]*ha[n + j]*M[n + j][n + i] +
ha2.*ha[i]*ha[n + j]*M[n + j][i]);
}
return e;
}
void harmonic_decomposition (scalar s, double t, double * omega, scalar e = {-1})
{
if (!s.harmonic.omega) {
int n = 0;
for (double * o = omega; *o > 0.; o++, n++);
.harmonic.omega = malloc(n*sizeof(double));
s(s.harmonic.omega, omega, n*sizeof(double));
memcpy .harmonic.M = (double **) matrix_new (2*n + 1, 2*n + 1, sizeof (double));
s.harmonic.Mn = (double **) matrix_new (2*n + 1, 2*n + 1, sizeof (double));
sfor (int i = 0; i < 2*n + 1; i++)
for (int j = 0; j < 2*n + 1; j++) {
.harmonic.M[i][j] = 0.;
s.harmonic.Mn[i][j] = (i == j);
s}
.harmonic.E = e;
sscalar Z = new scalar;
.harmonic.Z = Z;
s.harmonic.A = s.harmonic.B = NULL;
sfor (int i = 0; i < n; i++) {
scalar a = new scalar, b = new scalar;
char name[80];
(name, 79, "%s%da", s.name, i);
snprintf free (a.name); a.name = strdup (name);
(name, 79, "%s%db", s.name, i);
snprintf free (b.name); b.name = strdup (name);
.harmonic.A = list_append (s.harmonic.A, a);
s.harmonic.B = list_append (s.harmonic.B, b);
s}
(s.harmonic.A, 0.);
reset (s.harmonic.B, 0.);
reset .harmonic.invertible = false;
s}
scalar * A = s.harmonic.A, * B = s.harmonic.B;
scalar Z = s.harmonic.Z, E = s.harmonic.E;
double ** Mn = s.harmonic.Mn;
int n = 0;
for (scalar a in A)
++;
n
double vsin[n], vcos[n];
for (int i = 0; i < n; i++) {
[i] = sin (s.harmonic.omega[i]*t);
vsin[i] = cos (s.harmonic.omega[i]*t);
vcos}
double ** M = s.harmonic.M;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
[i][j] += vcos[j]*vcos[i];
M[i][n + j] += vsin[j]*vcos[i];
M[n + i][j] += vcos[j]*vsin[i];
M[n + i][n + j] += vsin[j]*vsin[i];
M}
[i][2*n] += vcos[i];
M[n + i][2*n] += vsin[i];
M}
for (int j = 0; j < n; j++) {
[2*n][j] += vcos[j];
M[2*n][n + j] += vsin[j];
M}
[2*n][2*n] += 1.;
M
double ** iM = (double **) matrix_new (2*n + 1, 2*n + 1, sizeof (double));
for (int i = 0; i < 2*n + 1; i++)
for (int j = 0; j < 2*n + 1; j++)
[i][j] = M[i][j];
iMif (!matrix_inverse (iM, 2*n + 1, 1e-6)) {
assert (!s.harmonic.invertible);
foreach() {
double x = s[];
scalar a, b;
int i = 0;
for (a,b in A,B) {
[] += x*vcos[i];
a[] += x*vsin[i];
b++;
i}
[] += x;
Zif (E.i >= 0)
[] += x*x;
E}
}
else {
foreach() {
double x = s[], sx2 = 0.;
/* A^n */
double ha[2*n + 1];
scalar a, b;
int i = 0;
for (a,b in A,B) {
[i] = a[];
ha[i + n] = b[];
ha++;
i}
[2*n] = Z[];
ha
/* X^n = M^n.A^n */
double hx[2*n + 1];
for (int i = 0; i < 2*n + 1; i++) {
[i] = 0.;
hxfor (int j = 0; j < 2*n + 1; j++)
[i] += Mn[i][j]*ha[j];
hx}
if (E.i >= 0) {
if (s.harmonic.invertible)
= x*x + Mn[2*n][2*n]*E[] - de (n, ha, hx, Mn);
sx2
else= x*x + E[];
sx2 }
/* X^n+1 = X^n + Delta^n */
for (int i = 0; i < n; i++) {
[i] += x*vcos[i];
hx[i + n] += x*vsin[i];
hx}
[2*n] += x;
hx
/* A^n+1 = (M^n+1)^-1.X^n+1 */
for (int i = 0; i < 2*n + 1; i++) {
[i] = 0.;
hafor (int j = 0; j < 2*n + 1; j++)
[i] += iM[i][j]*hx[j];
ha}
= 0;
i for (a,b in A,B) {
[] = ha[i];
a[] = ha[i + n];
b++;
i}
[] = ha[2*n];
Z
if (E.i >= 0)
[] = (sx2 + de (n, ha, hx, M))/M[2*n][2*n];
E}
.harmonic.invertible = true;
sfor (int i = 0; i < 2*n + 1; i++)
for (int j = 0; j < 2*n + 1; j++)
[i][j] = M[i][j];
Mn}
(iM);
matrix_free }
event cleanup (t = end)
{
for (scalar s in all)
if (s.harmonic.omega) {
free (s.harmonic.omega); s.harmonic.omega = NULL;
(s.harmonic.M);
matrix_free (s.harmonic.Mn);
matrix_free scalar Z = s.harmonic.Z;
delete ({Z});
delete (s.harmonic.A);
free (s.harmonic.A);
delete (s.harmonic.B);
free (s.harmonic.B);
}
}