Problem when realizing DSP algorithm:LMS on xCORE-200 MC Audio

Technical questions regarding the xTIMEcomposer, xSOFTip Explorer and Programming with XMOS.
cjf1699
Active Member
Posts: 40
Joined: Fri Mar 16, 2018 2:30 pm

Problem when realizing DSP algorithm:LMS on xCORE-200 MC Audio

Postby cjf1699 » Sun Apr 15, 2018 12:02 pm

Dear everyone,
I want to realize the LMS(least mean square) algorithm on xCORE-200 MC audio. Actually, my goal is to make an ANC headphone based on XMOS processor. Now I have managed to collect the noise signal and the error signal by microphones. And I tried to use the xCORE-200 DSP library. I created a new LMS function named "dsp_adaptive_new_lms" based on the original function: dsp_adaptive_lms in the library as follows:
The original: which can be seen in the "app_adaptive" from the example AN00209

Code: Select all

int32_t dsp_adaptive_lms
(
    int32_t  source_sample,
    int32_t  reference_sample,
    int32_t* error_sample,
    const int32_t* filter_coeffs,
    int32_t* state_data,
    const int32_t num_taps,
    const int32_t mu,
    const int32_t q_format
) {
    int32_t output_sample, mu_err;
   
    // Output signal y[n] is computed via standard FIR filter:
    // y[n] = b[0] * x[n] + b[1] * x[n-1] + b[2] * x[n-2] + ...+ b[N-1] * x[n-N+1]

    output_sample = dsp_filters_fir( source_sample, filter_coeffs, state_data, num_taps, q_format );
   
    // Error equals difference between reference and filter output:
    // e[n] = d[n] - y[n]

    *error_sample = reference_sample - output_sample;
   
    // FIR filter coefficients b[k] are updated on a sample-by-sample basis:
    // b[k] = b[k] + mu_err * x[n-k] --- where mu_err = e[n] * mu
   
    mu_err = dsp_math_multiply( *error_sample, mu, q_format );
    dsp_vector_muls_addv( state_data, mu_err, (int32_t*) filter_coeffs, (int32_t*) filter_coeffs, num_taps, q_format );
       
    return output_sample;
}



my version:

Code: Select all

int32_t dsp_adaptive_new_lms
(
    int32_t  source_sample,
   //int32_t  reference_sample,
    int32_t*  error_sample,
    const int32_t* filter_coeffs,
    int32_t* state_data,
    const int32_t num_taps,
    const int32_t mu,
    const int32_t q_format
) {
    int32_t output_sample, mu_err;

    // Output signal y[n] is computed via standard FIR filter:
    // y[n] = b[0] * x[n] + b[1] * x[n-1] + b[2] * x[n-2] + ...+ b[N-1] * x[n-N+1]

    output_sample = dsp_filters_fir( source_sample, filter_coeffs, state_data, num_taps, q_format );

   
    output_sample = - output_sample;     //changed , reverse, and my "error example" is from the mic, not calculated as the original shows

 
    // FIR filter coefficients b[k] are updated on a sample-by-sample basis:
    // b[k] = b[k] + mu_err * x[n-k] --- where mu_err = e[n] * mu


  //changed ,I tried to add an "if" condition.
  //if(fabs(F31(*error_sample))!=0){
        mu_err = dsp_math_multiply( *error_sample, mu, q_format );
     // dsp_vector_muls_addv( state_data, mu_err, (int32_t*) filter_coeffs, (int32_t*) filter_coeffs, num_taps, q_format );
  // } 
     
    return output_sample;
}

If I annotate the dsp_vector_muls_addv function, i.e. just apply a FIR filter to the source example and then reverse it, everything is OK, I can view the noise and error signal through xSCOPE (as follows)and the microphones work fine.

Image


However, if I let the yellow line of code in, everything seems to be stopped, I can see no signals but 2 horizontal lines as follows:


Image
In addition , I can hear a buzz at the beginning of the running. And I can't figure out the reason. The dsp_vector_muls_addv function is the core part of the algorithm with the purpose of adjusting the coefficients of the FIR filter, without which the WHOLE project would be a failure.
Thank you very much!!!!
cjf
Last edited by cjf1699 on Tue Apr 17, 2018 3:16 am, edited 3 times in total.
CousinItt
Active Member
Posts: 53
Joined: Wed May 31, 2017 6:55 pm

Postby CousinItt » Mon Apr 16, 2018 2:23 pm

Is the sign of your error_sample correct?
cjf1699
Active Member
Posts: 40
Joined: Fri Mar 16, 2018 2:30 pm

Postby cjf1699 » Mon Apr 16, 2018 4:28 pm

CousinItt wrote:Is the sign of your error_sample correct?

I don't know because the error sample is supposed to be obtained by the combination of the primary noise and the anti-noise. But the anti-noise isn't right at the moment. It is very strange. With whatever code I replace the dsp_vector_muls_addv, the same result happens. It seems that some abnormal termination happens when the dsp_vector_muls_addv exists.
Help..
CousinItt
Active Member
Posts: 53
Joined: Wed May 31, 2017 6:55 pm

Postby CousinItt » Mon Apr 16, 2018 6:40 pm

There is a bug relating to alignment of integer arrays when using dual-issue instructions (as is the case with the dsp library).

See here: viewtopic.php?t=4669

The workaround described there works for me.
cjf1699
Active Member
Posts: 40
Joined: Fri Mar 16, 2018 2:30 pm

Postby cjf1699 » Tue Apr 17, 2018 3:32 am

CousinItt wrote:There is a bug relating to alignment of integer arrays when using dual-issue instructions (as is the case with the dsp library).

See here: viewtopic.php?t=4669

The workaround described there works for me.

Ok,thank you for your answer, I will give it a try. But actually I didn't have the same problem as described in that post.
cjf1699
Active Member
Posts: 40
Joined: Fri Mar 16, 2018 2:30 pm

Postby cjf1699 » Tue Apr 17, 2018 4:13 am

Hey CousinItt,
I tried your workaround but nothing changed. Once the dsp_vector_muls_addv function is added, the programme seems stopped. Without it, the dsp_filters_fir works fine. With it, everything seems frozen. Unfortunately, the dsp_vector_muls_addv is full of assemble language which I can't understand.
I really hope to find some materials about how to use the lib_dsp on concrete applications like mine, well, especially about the adaptive part. But thank you all the same. Would you please give me some more help?
cjf
CousinItt
Active Member
Posts: 53
Joined: Wed May 31, 2017 6:55 pm

Postby CousinItt » Tue Apr 17, 2018 9:40 pm

I would think the best approach is to use a debugger - either the simulator (which I find really useful) or in hardware to run your function with known input data. You don't need to know the details of inline assembly to check the results of each function.

Since you have the working example, you can look at how that behaves and compare it with your code. You wouldn't need to run through the function many times to get an idea of what's going on. Don't forget you can print data values too.

Also, I have some difficulties working out what you're trying to do here:

Code: Select all

if(fabs(F31(*error_sample))!=0)


It's an awful lot of manipulation just to check if a float is equal to a zero int. It may be optimised out, but if not you could just compare the value with zero directly:

Code: Select all

if(*error_sample != 0)


There's no need to take the absolute value - it's either zero or it ain't.
cjf1699
Active Member
Posts: 40
Joined: Fri Mar 16, 2018 2:30 pm

Postby cjf1699 » Wed Apr 18, 2018 9:06 am

Thank you for your advice. I will have a try. As for

Code: Select all

 if((F31(*error_sample))!=0){

The reason is that if I annotate this line , there was no wave in the xscope while with this line ,there was awful waves which I can't explain. And it's my fault, thank you for your correction.
I found that perhaps my q_format isn't suitable for my application. Over the past few days I have used Q31 format . Actually the arguments of the functions in the lib_dsp are all fixed-point numbers. For example, in the app_adaptive, the function dsp_adaptive_lms is called as follows:

Code: Select all

x = dsp_adaptive_lms( Q31(0.08), Q31(0.10), &err, lms_coeffs, fir_state, c, Q31(0.01), Q_N );

The 0.08, 0.10 and 0.01 are the original values and they are transferred to Q31 format which would be integers.
However, in my application, the value of samples obtained by the ADC is already int32_t type. When running the program I watch the values through "printf" like this:

Code: Select all

printf("%d %d out\n",index,sample);

The value of sample is pretty large, which is around 4*10e7. I don't know whether it had been transferred to a "Q format" or not. Is the value its original value? In other words, when I call the dsp_adaptive_lms function, should I pass the parameter "Q31(sample)" or just "sample"?
CousinItt
Active Member
Posts: 53
Joined: Wed May 31, 2017 6:55 pm

Postby CousinItt » Wed Apr 18, 2018 5:25 pm

Re printing, you would expect the values you see normally to be very large. In using Q31 format, you are using 31 of the bits in a 32-bit integer to represent the fractional part of a number, with the one remaining bit used for the sign. As an example, the Q31 representation of 0.01 decimal is 21474836 decimal. For your printf to run quickly enough, you should use a format that minimises the amount of work the print function needs to do in real time, so your printf is fine as it is.

Be aware that Q31 doesn't give you much headroom. The data values are limited to the range +/- 0.99999.. and this can easily give rise to overflow errors. For a lot of audio work the least significant bits are not relevant so you might just as easily work in Q24 or Q20 format. The important things are that you (i) select a format to avoid overflow and maximise signal-to-noise ratio, within the constraints of the chosen word size and (ii) you scale your inputs and outputs appropriately when transferring them to the appropriate I/O handlers.

When you say "annotate" do you mean comment out (// style)?
cjf1699
Active Member
Posts: 40
Joined: Fri Mar 16, 2018 2:30 pm

Postby cjf1699 » Thu Apr 19, 2018 4:43 am

Yes..I mean comment out..

The problem is that I can't ensure the range of values of samples obtained by A/D, so I can't select a format rationally. According to the results of my printf, the values are so large regardless of the format...

Who is online

Users browsing this forum: No registered users and 17 guests