I've been coding up a working MATLAB simulation on a Blackfin 533 using the 32 bit fractional data type (fract32). I have used FIR filters to implement convolution to get outputs from different filter stages. I'm using look up tables created from MATLAB to simulate the algorithm internally on the processor. The LUTs consist of secondary path filtered white noise and a 30Hz sine wave also filtered through the same impulse response as the white noise. I run the system identification mode for 5 seconds and switch to active mode filtering. During development, I've been using only a fraction of the look up tables(which doesn't contain the full period of the sine wave) which fills a buffer of 512 bytes. This was the case for both the filtered 30Hz input signal as well as the reference sine/cosine waves. This works as I can verify this by plotting the signals on every iteration. However, when i start to input the signals in their full periods, my adaptive coefficients (fract32) starts to saturate and the filter starts to misbehave. I've been reading up on scaling at different filter nodes but to no avail. Any help on this will be greatly appreciated. Here's some pseudo code as to what's going on in active mode. #define ANC_SAMPLE_FREQ_HZ 48000 #define ANC_SAMPLE_SIZE 512 #define ANC_FILTER_ORDER 128. #define ANC_MU 0.00021 #define TEST_FREQ 30.0 /* temp buffers */ static fract32 references[2][ANC_SAMPLE_SIZE]; static fract32 weightedreference[2][ANC_SAMPLE_SIZE]; static fract32 filteredreference[2][ANC_SAMPLE_SIZE]; static fract32 filteredOut[ANC_SAMPLE_SIZE]; static fract32 desiredResponse[ANC_SAMPLE_SIZE]; // output buffer static fract32 _output[ANC_SAMPLE_SIZE]; /* FIR filters that are initialized at startup before DMA fires */ static fir_state_fr32 weightFilter[2]; // Adaptive filters static fir_state_fr32 secondaryFilter[2]; // Secondary path filtering for reference waves static fir_state_fr32 secondarypath; // Secondary path filtering for the output for(n = 0; n < ANC_SAMPLE_SIZE; n++) { references[0][n] = generate_SINE(TEST_FREQ); // Sin references[1][n] = generate_COSINE(TEST_FREQ ; // Cos } // Weighted Sine reference fir_fr32(references[0], weightedreference[0], ANC_SAMPLE_SIZE, &weightFilter[0]); // Weighted Cosine reference fir_fr32(references[1], weightedreference[1], ANC_SAMPLE_SIZE, &weightFilter[1]); // Secondary path filtered sine reference fir_fr32(references[0], filteredreference[0], ANC_SAMPLE_SIZE, &secondaryFilter[0]); // Secondary path filtered cosine reference fir_fr32(references[1], filteredreference[1], ANC_SAMPLE_SIZE, &secondaryFilter[0]); // Compute output for(n = 0; n < ANC_SAMPLE_SIZE; n++) { sData->outputvector[n] = add_fr1x32(weightedreference[0][n], weightedreference[1][n]); } // Secondary path filtered controller output fir_fr32(_output, filteredOut, ANC_SAMPLE_SIZE, &secondarypath); // Compute noise estimate for(n = 0; n < ANC_SAMPLE_SIZE; n++) { debug = generate_debugInput(); // get filtered 30Hz input from LUT desiredResponse[n] = sub_fr1x32(debug, filteredOut[n]); } // Finally, Adapt coefficiants --------------------------------------- Posted through http://www.DSPRelated.com
Adaptive Notch filtering using FxLMS
Started by ●November 5, 2015
Reply by ●November 6, 20152015-11-06
lightbearer <110036@DSPRelated> wrote:>However, when i start to input the signals in their full periods, my >adaptive coefficients (fract32) starts to saturate and the filter starts >to misbehave.[snip]>Here's some pseudo code as to what's going on in active mode.>[snip]> // Finally, Adapt coefficiantsYou did not give any pseudo-code for your "adapt coefficients" block, even though this is likely where your problem is. I have not implemented an adaptive notch, but colleagues tell me it is pretty routine... however, in my experience "adaptive anything" is at least potentially far from routine... My only advice is to perfect the algorithm first in high precision before moving to target precisions (in your case, fract32). Good luck Steve
Reply by ●November 6, 20152015-11-06
Sorry about not adding code for the potential trouble section lol. // Adapting coefficiants int i,j; fract32 temp; fract32 MU = float_to_fr32(ANC_MU); // step size static fract32 state[2][ANC_FILTER_ORDER]; // temp delay buffer static fract32 wvector[2]; // adaptive coeffs for(i = 0; i < ANC_SAMPLE_SIZE) { /* Sine coeffs */ memmove(&state[0][1], &state[0][0], sizeof(fract32) * ANC_FILTER_ORDER-1); // shift left state[0][0] = sample; // Add new value to beginning for(i = 0; i < ANC_FILTER_ORDER; i++) { temp = mult_fr1x32x32(reference->w[i],desired); wvector[0][i] = add_fr1x32(wvector[0][i], mult_fr1x32x32(temp, MU)); } /* Cosine coeffs */ memmove(&state[1][1], &state[1][0], sizeof(fract32) * ANC_FILTER_ORDER-1); // shift left state[1][0] = sample; // Add new value to beginning for(i = 0; i < ANC_FILTER_ORDER; i++) { temp = mult_fr1x32x32(reference->w[i],desired); wvector[1][i] = add_fr1x32(wvector[1][i], mult_fr1x32x32(temp, MU)); } } I Have circular buffer implementation to achieve this but this is essentially whats happening. --------------------------------------- Posted through http://www.DSPRelated.com