Here are the issues that I found not quite accurate in the old oaf code:
1. There is no need to calculate the norm of the witness signal every time from zero:
norm += (*pBufAdapt) * (*pBufAdapt); // add to the norm
Every step the witness signal vector is the same except the first and last values
wit[i].norm += histAdpt[nCoeff]*histAdpt[nCoeff] - histAdpt*histAdpt;
This step will reduce the number of multiplications and summations from 3*M/k to 2*M/k, M - filter length, k - downsample ratio.
2. Old code filter corrects filter coefficients with a delay equal to k=downsample ratio (pretty big):
witness o o o o o o o o o o o o o o o o o o o o o
error o o o o o o o o o o o o o o o o o o o o o
We want the filter to work at green points and skip red points computing output and correcting coefficients at this time (downsample ratio in this example is 4). Old code
But LMS algorithm should correct coefficients according to the latest error. As we calculate output and correct coefficients before the latest error signal will be available, we should change the order:
This scheme is completely equivalent to the ordinary LMS algorithm, as now we correct coefficients according to the latest error signal and so do not add any delay.
3. So long soft start is probably not needed for the LMS filter, it makes the filter to converge longer
// modify adaptation gain for soft start
if( state.iWait < state.nFIR )
adaptGain = 0.0;
decayRate = 1.0; // clear FIR coeffs after reset
As far as I understand this is done to prevent the filter from huge coefficients variations in the beginning when norm is not calculated yet. Instead we can just introduce some small
epsilon = 10.0;
to prevent the filter from divergence in the beginning
delta = mu * error / (wit[i].norm + epsilon);
Though some soft start might be needed by not so long - it will take several minutes before the adaptation gain will take it's specified value.