#include "LPC.h" // http://kbs.cs.tu-berlin.de/~jutta/gsm/lpc.html #define P_MAX 8 /* order p of LPC analysis, typically 8..14 */ /* Invented by N. Levinson in 1947, modified by J. Durbin in 1959. */ double /* returns minimum mean square error */ levinson_durbin( double const * ac, /* in: [0...p] autocorrelation values */ double * ref, /* out: [0...p-1] reflection coef's */ double * lpc) /* [0...p-1] LPC coefficients */ { int i, j; double r, error = ac[0]; if (ac[0] == 0) { for (i = 0; i < P_MAX; i++) ref[i] = 0; return 0; } for (i = 0; i < P_MAX; i++) { /* Sum up this iteration's reflection coefficient. */ r = -ac[i + 1]; for (j = 0; j < i; j++) r -= lpc[j] * ac[i - j]; ref[i] = r /= error; /* Update LPC coefficients and total error. */ lpc[i] = r; for (j = 0; j < i/2; j++) { double tmp = lpc[j]; lpc[j] += r * lpc[i-1-j]; lpc[i-1-j] += r * tmp; } if (i % 2) lpc[j] += lpc[j] * r; error *= 1.0 - r * r; } return error; } /* I. Sch"ur's recursion from 1917 is related to the Levinson-Durbin * method, but faster on parallel architectures; where Levinson-Durbin * would take time proportional to p * log(p), Sch"ur only requires * time proportional to p. The GSM coder uses an integer version of * the Sch"ur recursion. */ double /* returns the minimum mean square error */ schur( double const * ac, /* in: [0...p] autocorrelation c's */ double * ref) /* out: [0...p-1] reflection c's */ { int i, m; double r, error = ac[0], G[2][P_MAX]; if (ac[0] == 0.0) { for (i = 0; i < P_MAX; i++) ref[i] = 0; return 0; } /* Initialize rows of the generator matrix G to ac[1...P] */ for (i = 0; i < P_MAX; i++) G[0][i] = G[1][i] = ac[i+1]; for (i = 0;;) { /* Calculate this iteration's reflection * coefficient and error. */ ref[i] = r = -G[1][0] / error; error += G[1][0] * r; if (++i >= P_MAX) return error; /* Update the generator matrix. * * Unlike the Levinson-Durbin summing of reflection * coefficients, this loop could be distributed to * p processors who each take only constant time. */ for (m = 0; m < P_MAX - i; m++) { G[1][m] = G[1][m+1] + r * G[0][m]; G[0][m] = G[1][m+1] * r + G[0][m]; } } }