espressif / esp-dsp

DSP library for ESP-IDF
Apache License 2.0
442 stars 87 forks source link

Need to remove noise from audio signal using IIR low pass filter(esp-dsp library) (DSP-87) #48

Closed jaydeep7563 closed 11 months ago

jaydeep7563 commented 2 years ago

Hi

Hope you are doing good.

esp-idf version = stable release 4.4.1 Dev-Kit = https://github.com/W00ng/ESP32-S3-HMI-DevKit

I am using above mentioned kit and esp-idf version for my Project. Actually I need to record audio from stereo mic and play the same audio after noise filtering (I am using esp-dsp library and IIR-LPF method for the same ). But I am still getting noise after low pass filtering. I think I am missing something or I am doing something wrong configurations.

I2S configurations are as following.

#define I2S_CONFIG_DEFAULT() { \
    .mode                   = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, \
    .sample_rate            = sample_rate, \                      /* sampling rate is 16000 (16k)*/
    .bits_per_sample        = I2S_BITS_PER_SAMPLE_16BIT, \
    .channel_format         = I2S_CHANNEL_FMT_RIGHT_LEFT, \
    .communication_format   = I2S_COMM_FORMAT_STAND_I2S, \
    .intr_alloc_flags       = ESP_INTR_FLAG_LEVEL1, \
    .dma_buf_count          = 6, \
    .dma_buf_len            = 160, \
    .use_apll               = false, \
    .tx_desc_auto_clear     = true, \
    .fixed_mclk             = 0, \
    .mclk_multiple          = I2S_MCLK_MULTIPLE_DEFAULT, \
    .bits_per_chan          = I2S_BITS_PER_CHAN_16BIT, \
}

Audio record and play task is as following.

void audio_record_task(void *args)
{
    static esp_err_t ret;
    static size_t bytes_read = 0;
    static size_t bytes_write = 0;
    while (1) 
    {

        if (mode == record) {
            ESP_LOGI(TAG, "record start");
            audio_index = 0;
            while ((mode == record) && (audio_index < (BUF_SIZE -   FRAME_SIZE)))
            {
                ret = i2s_read(I2S_NUM_0, audio_buffer + audio_index, FRAME_SIZE, &bytes_read, 100);
                if (ret != ESP_OK) {
                    ESP_LOGE(TAG, "[echo] i2s read failed");
                    abort();
                }
                audio_index += FRAME_SIZE;
            }
            if (mode == record) mode = idle;
            ESP_LOGI(TAG, "record end");
        }
        else if (mode == play)
        {
            ESP_LOGI(TAG, "play start");
            ESP_LOGI(TAG, "audio_index = %d", audio_index);
            audio_total = audio_index;  //recorder length
            audio_index = 0;
#if 1    /* IIR low pass filtering */
            esp_err_t ret = ESP_OK, ret_hpf = ESP_OK;
            float coeffs_lpf[5];
            float coeffs_hpf[5];
            float w_lpf[5] = {0,0};

            // Calculate iir filter coefficients
            ret = dsps_biquad_gen_lpf_f32(coeffs_lpf, 0.4, 0.1);
            if (ret  != ESP_OK)
            {
                ESP_LOGE(TAG, "Operation error LPF = %i", ret);
                return;
            }

            while(audio_index < audio_total)
            {
        for (int i=audio_index,j=0; (i-audio_index) < SAMPLES_NUM ; i++,j++)
        {
            d[j] = (float)audio_buffer[i];     /*filling input buffer for dsps_biquad_f32() */
        }
        // Process input signal
        ret = dsps_biquad_f32(d, y, N, coeffs_lpf, w_lpf);
        if (ret  != ESP_OK)
        {
            ESP_LOGE(TAG, "Operation error biquad lpf= %i", ret);
            return;
        }
        for (int i=audio_index, j=0 ; (i-audio_index) < SAMPLES_NUM ; i++,j++)      /* SAMPLES_NUM = 1024 */
        {
            y[j] = y[j] * 0.1;
            audio_buffer[i] = (int16_t)y[j];     /* filling audio_buffer back with filtered output to pass it it i2s_write to play it */
        }
        audio_index += SAMPLES_NUM;
        vTaskDelay((10) / portTICK_PERIOD_MS);
            }
#endif

            audio_index = 0;
            while ((mode == play) && (audio_index < audio_total))
            {
                /* playing low-pass filtered audio signal with speaker */ 
                ret = i2s_write(I2S_NUM_0, audio_buffer + audio_index, FRAME_SIZE, &bytes_write, 100);
                if (ret != ESP_OK) {
                    ESP_LOGE(TAG, "[echo] i2s write failed");
                    abort();
                }
                audio_index += FRAME_SIZE;
            }
           if (mode == play) mode = idle;
            ESP_LOGI(TAG, "play end");
        }
        else
        {
            vTaskDelay((100) / portTICK_PERIOD_MS);  
        }
    }
    vTaskDelete(NULL);
}

When I play audio output it is actual audio signal(low voise) with noise(high voise).

@dmitry1945 I have also checked your reply in https://github.com/espressif/esp-dsp/issues/15 post, but didn't get it how it will be applicable to my code. I think I am missing something or doing something silly. Please suggest me for next step to remove noise from audio signal. Also suggest another filtering method if it is easy rather than IIR-LPF for my task.

Thanks in advance.

dmitry1945 commented 2 years ago

@jaydeep7563 your filter has next response:


I (331) main: Impulse response of IIR filter with F=0.400000, qFactor=0.100000
I (331) view: Data min[17] = -0.000209, Data max[1] = 0.364938
 ________________________________________________________________
0                                                                |
1                                                                |
2-                                                               |
3 -                                                              |
4  --------------------------------------------------------------|
5                                                                |
6                                                                |
7                                                                |
8                                                                |
9                                                                |
 0123456789012345678901234567890123456789012345678901234567890123
I (411) view: Plot: Length=128, min=-1.000000, max=1.000000
I (421) view: Data min[511] = -111.133377, Data max[0] = 0.000000
 ________________________________________________________________
0                                                                |
1                                                                |
2-------------                                                   |
3             -----------------------------                      |
4                                          ---------------       |
5                                                         -----  |
6                                                              --|
7                                                               -|
8                                                               -|
9                                                                |
 0123456789012345678901234567890123456789012345678901234567890123
I (491) view: Plot: Length=512, min=-100.000000, max=0.000000
I

I think the band stop is to small. Please set ret = dsps_biquad_gen_lpf_f32(coeffs_lpf, 0.2, 1); or ret = dsps_biquad_gen_lpf_f32(coeffs_lpf, 0.01, 1); You should hear that sound has changed from original one. If you hear less noise, then just add one more (ore even few more) LPF biquad. Now, I think, the pass band if your filter is to high.

jaydeep7563 commented 2 years ago

Hi @dmitry1945,

Thanks for the response. I'll check with your suggestions and will update the result here.

Thanks again.

jaydeep7563 commented 2 years ago

Hi @dmitry1945

Hope you are doing good.

I tried (0.2 freq with 1 qFactor) and (0.01 freq with 1 qFactor) but didn't get clear voice in it also. I also tried by adding one/multiple LPF biquad filters but didn't get result(actually by doing this there is a noise only).

1) Can you please share some more info about how to decide freq, cut-off freq (i.e. normalized freq= cut-off/sampling rate)and qFactor from the plot/graph you shared ?

2) Also can you please confirm that from above code like I am doing LPF biquad to every 1024 samples (because audio buff is apporx 90Kb to 100Kb) and taking filtered 1024 samples as a input to speaker, is a right method ?

Thanks in advance.

dmitry1945 commented 11 months ago

Hi @jaydeep7563

I think the noise is not related to the processing or to ADC, and it's related to the system flow. Try to replace filtered signal audio_buffer[i] = (int16_t)y[j]; by sine wave, something like this: audio_buffer[i] = INT16_MAX*0.1*sinf(2*M_PI*0.0625*j);

In this case you should hear clear sine wave without any noise. If you will still have a noise, then the problem in the system flow, it means you application miss some buffers or samples.

Regards, Dmitry

jaydeep7563 commented 11 months ago

Hi @jaydeep7563

I think the noise is not related to the processing or to ADC, and it's related to the system flow. Try to replace filtered signal audio_buffer[i] = (int16_t)y[j]; by sine wave, something like this: audio_buffer[i] = INT16_MAX*0.1*sinf(2*M_PI*0.0625*j);

In this case you should hear clear sine wave without any noise. If you will still have a noise, then the problem in the system flow, it means you application miss some buffers or samples.

Regards, Dmitry

Thanks for your reply. Actually noise was due to the buffer issue (when catching the voice data from i2s to local buffer, at that time it was changing endianness of original data and was adding extra 0x00 to each byte, due to which there were heavy noice in original data signal. So by keeping same endianness of original data and by removing extra 0x00(which was added by mistake in each byte), able to get clear data signal.)(filter was not required anymore to remove the noice).

Again Thanks for your help.