NRF25 using Butterworth bandpass filter for ECG by SAADC

HI everyone, i have a problem when implementing Butterworth bandpass filter in SAADC module to cancel out the noise of our ECG module.

I used " nrf_saadc_value_t m_buffer_pool[2][SAMPLE_BUFFER_LEN] " and " nrfx_saadc_buffer_convert(m_buffer_pool[0], SAMPLE_BUFFER_LEN) "

As far as i had known, the VOLTAGE signal of the analog input will be transfered to the memory of MCU and converted to an appropriate level of BITS, then these value will be stored in registers in terms of BITS. I used a software filter based on the code on this Github link: github.com/.../filter-c

My question is: How can the Butterworth filter cancel out the noises and only select the band of desirable frequency for my project. Does it work only on frequency generated by the electrical voltage Or it can also filter the BITS value in the memory?

Thanks in advance.

  • thank you so much for reply me! I misunderstood the definition of filter, i'm using the digital filter not the analog, now i changed it

  • Hi,

    looking at your code i'd say you can do the filtering inside the callback function named "saadc_callback_handler". After you started the AD conversion with "nrfx_saadc_buffer_convert(m_buffer_pool[0], SAMPLE_BUFFER_LEN);", this callback function will be called when your buffer has been filled. You can do the filtering inside of the for-loop that you already have in there. The "p_event" parameter that is passed into the callback will contain a pointer to your data, so you can use "p_event -> data.done.p_buffer[i]" to access the i-th element, same as in the "NRF_LOG_RAW_INFO(...)" command.

    So similar to the example above you could just change the for-loop like this:

    for(int i = 0; i < SAMPLE_BUFFER_LEN; i++){

       filtered[i] = bw_band_pass(filter, p_event -> data.done.p_buffer[i]);

    }

    Create the filter (like in the example) before the for-loop and destroy it after the loop.

    The only remaining question is where to store the filtered data. Easiest way to try it would be to declare another buffer for the filtered data globally, like you did with the "nrf_saadc_value_t m_buffer_pool".

    The filter outputs floating point numbers, so you should declare a floating point array for the result, like this:

    float filtered[SAMPLE_BUFFER_LEN];

    Best regards

    Frank

  • Thanks so much! Now i can compile the code successfully without any errors

    but the termial output the value  " 0 " continuously no matter how i change the input data by the potentiometer

    I created the global  float filtered[SAMPLE_BUFFER_LEN];  as you suggested, then this is my adc handler:

    void saadc_callback_handler(nrf_drv_saadc_evt_t const * p_event)
    {
        float val;

        if(p_event -> type == NRFX_SAADC_EVT_DONE)
        {
            ret_code_t err_code;

            err_code = nrfx_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLE_BUFFER_LEN);
            APP_ERROR_CHECK(err_code);

            BWLowPass* filter = create_bw_low_pass_filter(10, 500, 30);

            for(int i = 0; i < SAMPLE_BUFFER_LEN; i++)
            {
                 filtered[i] = bw_low_pass(filter, p_event -> data.done.p_buffer[i]);

            }

            NRF_LOG_RAW_INFO("%d\n\r", filtered);

            free_bw_low_pass(filter);
        }
    }

    Did i do it ritght? or i have to create another for loop for NRF_LOG_RAW_INFO() to output the values?

  • Hi,

    the filtering looks correct.

    I think the problem here is the NRF_LOG_RAW_INFO command. I think it can't be used to log floating point values. The documentation says you should log floating point values like this:

    NRF_LOG_INFO("My float number" NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(f)));

    where you can replace "My float number" with your own text, and "f" with the floating point value to print.

    See here: link

    Also you need to use "filtered[i]", otherwise the log function will try to print the address of the array, not the contents of one array element.

    Finally, if you move the log statement inside the for-loop it will print all the values, not only the last one.

    So try this:

            for(int i = 0; i < SAMPLE_BUFFER_LEN; i++)
            {
                 filtered[i] = bw_low_pass(filter, p_event -> data.done.p_buffer[i]);

                 NRF_LOG_INFO("My float number" NRF_LOG_FLOAT_MARKER "\r\n", 

                        NRF_LOG_FLOAT(filtered[i]));

            }

    Hope this works now, i don't use this NRF_LOG_INFO stuff normally.

    Best regards

    Frank

  • sorry, it didn't work

    i think the problem is LOG module, i used this module for a long time and get familiar with this

    How can you output the data through UART port to the laptop screen? My segger embedded had trouble with PRINTF, i dont know how to transfer the data through UART without LOG module

Related