Distorted Sound with FIR Filter

14 posts / 0 new
Last post
matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am
Distorted Sound with FIR Filter

Hello everybody,

I am currently designing a simple audio hardware with a Cortex M7 Processor (STM32F746ZG) and a simple Codec and I am experiencing some issues which I dont't understand.

For better understandig let me sum up the basic design:

- Firmware is based on the examples given in the download section for the STM32F746 Discovery Board
- Hardware is simply the MCU with an external Codec (AK4621)
- Firmware has a modified audio_driver.c etc. to communicate via I²S instead of TDM.

The Problem is pretty simple to describe:
The main goal of the audio hardware which I am desinging is to implement an FIR filter with round about 1000 Taps. On the STM32F746 Discovery Board this works flawlessly. On my target board the audio seems to be some kind of corrupted if I add any filter in the Audio Weaver Layout like this:

I've uploaded a short example of what it sounds like (captured with a microphone but I think the main issue is well audible):

 

If I wire the Input directly to the Output without filtering or if I set all filter coefficient except for the first to zero everything seems to be fine so I could imagine that the CPU Load is to high but the indicator in the audio weaver server displays only a load of about 60%.

Does anyone have the same problem or a similar one?

Thanks for helping me out!

 

Bye

 

Matthias

Axel Nilsson
Offline
Last seen: 3 hours 24 min ago
Joined: 12/19/2016 - 2:02pm

Hi Matthias,

 

A CPU load of 60% could be causing audio dropouts. See this thread for more information on what the CPU load means: https://dspconcepts.com/forums/audio-weaver-designer/421-stm32f746-disco...

Is this distortion you hear based on the size of the filter? For example, do you get artifacts when the filter is 512 taps but not when it's 31 taps?

 

-Axel

matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am

Hi Axel,
thanks for your quick response! Glad that someone is willing to help me out here.

I've just checked if the artifacts are related to the filter depth but that doesn't seem to be the case. Even if I just use a single Tap the artifacts are still there.
But what is interesting about it is that the distortion seems to be related to the coefficient it self. If I put in 1 as the only coefficient everything seems to be fine and not artifacts are audible but if I change the coefficient to 1.1 or -1.1 for example the artifacts are comming back.

The CPU Load also is significant getting down at such a short filter (1 Tap) and Audio Weaver Server shows only 9%.

My problem is: Why does it work on the Demo Board? It is the same Processor (Also a STM32F746) and there is nothing changed. Can the Sample Depth result in such a problem? The Demoboard uses 16Bit ADC and I am using a 24Bit ADC which results of course in a higher processing load right?

 

Axel Nilsson
Offline
Last seen: 3 hours 24 min ago
Joined: 12/19/2016 - 2:02pm

Are you converting the 24-bit audio samples to 32-bit before pumping them into Audio Weaver? This is done in original code for 16-bit audio in AudioDriver.c.

matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am

Well I've modified "AudioBufferIn" and "AudioBufferOut" to INT32 because the former Datatype of INT16 is of course not fitting for the 24Bit Audiodata. 

For better understandig I can give you the modified code for the "AWEProcessing" Function:

void AWEProcessing(fract16 * pUSBSamples, fract32 * pCODECSamples, fract32 * pProcessedSamples)
{
    UINT32   fwInCount, fwOutCount;
    INT32   used_chans, chan;   
    INT32   pinStride;
    INT16   n16BitSample;
    INT32   n32BitSample;
    INT32 * dest32BitPtr;
    INT32 * src32BitPtr;
    INT16 * dest16BitPtr;    
    INT16 * src16BitPtr;    
    UINT32  layoutMask;  
    INT32   nSample;

    const UINT32 nPinNdx = 0;

    // If no AWE layout wired up then output silence
    if (!s_AudioRunning)
    {    
        memset(pProcessedSamples, 0, STEREO_BLOCK_SIZE_IN_SAMPLES * sizeof(fract16) );
        
        //*************** FOR DEBUG ********************************************
        //for (nSample = 0; nSample < STEREO_BLOCK_SIZE_IN_SAMPLES; nSample++)
        //{           
        //    *pProcessedSamples++ = *pUSBSamples++;           
        //}
        //************************************************************************/          
    }
    else
    {  
        // Get Current audio layout number of channels
        awe_fwGetChannelCount(&g_AWEInstance, &fwInCount, &fwOutCount);   
                                           
        // Get the input pin channels actually used
        used_chans = (fwInCount < INPUT_CHANNEL_COUNT) ? fwInCount : INPUT_CHANNEL_COUNT;

        for (chan = 0; chan < used_chans; chan++)
        {
            // Determine where the Framework wants the input data written
            dest32BitPtr = awe_fwGetInputChannelPtr(&g_AWEInstance, nPinNdx, chan, &pinStride);
                            
            // Reorder the input channels to the way AWE expects them
            switch (chan)
            {
                case 0:                      
                    src32BitPtr = pCODECSamples; //Matthias
                    break;
                
                case 1:                      
                    src32BitPtr = pCODECSamples + 1; //Matthias
                    break;                    
                
              /*  case 2:
                    src16BitPtr = pCODECSamples;                   
                    break;
                    
                case 3:
                    src16BitPtr = pCODECSamples + 2;                   
                    break;
                
                case 4:                       
                    src16BitPtr = pCODECSamples + 1;                   
                    break;                    
                   
                case 5:
                    src16BitPtr = pCODECSamples + 3;                   
                    break;
                */
            }   // end switch
            
            for (nSample = 0; nSample < CHANNEL_BLOCK_SIZE_IN_SAMPLES; nSample++)
            {
                n32BitSample = *src32BitPtr;
                 
                // Audio Weaver wants the sample in the high order bytes of the 32-bit word
               // *dest32BitPtr = n16BitSample << 16;
                *dest32BitPtr = n32BitSample;
                
                dest32BitPtr += pinStride;
                

                if (chan < 2)
                {
                    src32BitPtr += 2;
                }
                else
                {
                    src32BitPtr += 1;
                }

            }
        }

        // Zero any unused layout inputs
        for (; chan < fwInCount; chan++)
        {
            // Determine where the Framework wants the input data written
            dest32BitPtr = awe_fwGetInputChannelPtr(&g_AWEInstance, nPinNdx, chan, &pinStride);    
            
            for (nSample = 0; nSample < CHANNEL_BLOCK_SIZE_IN_SAMPLES; nSample++)
            {                                 
                *dest32BitPtr = 0;
                dest32BitPtr += pinStride;                
            }
        }                                    
               
        for (chan = 0; chan < OUTPUT_CHANNEL_COUNT; chan++)
        {
            if (chan < fwOutCount)
            {
                // Determine where the Framework wants the output data written
                src32BitPtr = awe_fwGetOutputChannelPtr(&g_AWEInstance, nPinNdx, chan, &pinStride);
                
                // Implement output volume control
                //awe_vecScaleSmoothFract32(src32BitPtr, pinStride, src32BitPtr, pinStride,
                //                          (fract32 *)&nVolCurrentGain, g_nNewVolGain, 0, SMOOTHING_COEFF, AWE_FRAME_SIZE);
                
                //nVolCurrentGain = g_nNewVolGain;
                
                dest32BitPtr = pProcessedSamples + chan;
                
                for (nSample = 0; nSample < CHANNEL_BLOCK_SIZE_IN_SAMPLES; nSample++)
                {
                    n32BitSample = *src32BitPtr;
                    
                    // Audio Weaver has sample in high order bytes of 32-bit word
                    // n16BitSample = n32BitSample >> PCM_SAMPLE_SIZE_IN_BITS;
                    
                    // *dest16BitPtr = n16BitSample;
                    *dest32BitPtr = n32BitSample;

                    src32BitPtr += pinStride;
                    
                    // Output samples are interleaved
                    dest32BitPtr += OUTPUT_CHANNEL_COUNT;
                }
                
            }
            else
            {
                // The layout doesn't have enough channels; fill the remaining one with zeros
                dest32BitPtr = pProcessedSamples + chan;
                
                for (nSample = 0; nSample < CHANNEL_BLOCK_SIZE_IN_SAMPLES; nSample++)
                {
                    *dest32BitPtr = 0;
                    dest32BitPtr += OUTPUT_CHANNEL_COUNT;
                }
            }
        }

        layoutMask = awe_fwAudioDMAComplete(&g_AWEInstance, nPinNdx, CHANNEL_BLOCK_SIZE_IN_SAMPLES);

        if (layoutMask & 1)
        {
            if (s_AudioRunning && !g_bAudioPump1Active)
            {
                NVIC_SetPendingIRQ(AudioWeaverPump_IRQ1);
            }            
        }
        
        if (layoutMask & 2)
        {
            if (s_AudioRunning && !g_bAudioPump2Active)
            {
                NVIC_SetPendingIRQ(AudioWeaverPump_IRQ2);
            }            
        }        
    }
    
}    // End AWEProcessing

 

 

Axel Nilsson
Offline
Last seen: 3 hours 24 min ago
Joined: 12/19/2016 - 2:02pm

Ok. I think the problem is that you are not inserting fract32 data into your system. When you get your 24-bit audio samples from the DAC, before pumping them into your system you need to left shift them by 8 bits so that the highest bits of your 24 bit data are in the highest bits of the 32-bit data type.

Likewise, on the output you need to right-shift by 8 bits to get the fract32 data into the expected 24-bit format. 

 

Having the incorrect data type can cause the oddities that you are experiencing. 

matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am

Ah ok that makes perfectly sense to me! I was expecting that the SAI in the STM32 already shifted the data but that was just an assumption. I'll try that and get back here with the results so everybody can profit from this post.

But first I'm on vacation for the next two weeks so it can take a while to try that.

For now thank you for your great help! Its not that common to find people willing to help for free.

 

Bye

 

Matthias

matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am

Hi Axel,
I've now updated my code and added the shifting of the incoming samples. Unfortunately that doesn't solve the problem.
I still get the same results when I start adding a filter or some other element (I've also tried a simple delay to make sure it doesn't only happen when using the FIR module).

The CPU usage is also in the very low numbers (like max. 10%) so I am still sure there is enough processing power to solve a simple operation like a one tap FIR or a short delay.
What confuses me the most is that this setup runs without a problem on the discoveryboard and I have only changed the following things in the demofirmware:

- modified the "audiodriver_modified.c" in the SAI configuration (I got an I²S Codec instead of a TDM Codec)
- modified the "audiodriver.c" like seen in my earlier post plus the sample shifting
- modified the datatypes of the incoming samples to INT32 in the DMA
- commented out some features which no longer exist in my hardware: External RAM, LCD etc.

Thats it basically. What am I doing wrong? Would you take a quick look at it if I send you the source-code with comments on the positions where I've edited the demo firmware? 
And again: Thank you so much for your help!

 

 

 

Axel Nilsson
Offline
Last seen: 3 hours 24 min ago
Joined: 12/19/2016 - 2:02pm

Hi Matthias,

 

Yes, you can send me your source code at anilsson@dspconcepts.com. But could you first try a few other things to check what your output sounds like?

- Input a pure 1000 Hz sine wave into your system instead of Bruno Mars and record the output. This will make it easier to see how exactly the signal is being distorted.

- In your Audio Weaver layout, send the input directly to a sink module and create a Sine Generator Module that feeds to the output pin. Put a -24 dB scaler module in between the Sin module and the output to avoid a full scale output. Since this signal is generated inside of Audio Weaver, this is a good way to isolate the cause of the issue.

 

Thanks

-Axel

 

matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am

Hi Axel,
Thanks for your answer! I'll do the requested tests and get back to you but I have to prepare them so it will take some time.

I'll also optimize the Source Code for your understanding (remove all unused functions, add some more comments) and send it to you next week.

Thanks for helping me out!

matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am

Hi Axel,
sorry for my late reply but I am currently a bit busy. I also got some problems with my codec on the board right now so I first need to find a decent fix for that so I can run the tests you suggested (feeding 1kHz sine wave via Audio Weaver etc.).
But I already commented the modifications we made in the Source Code and sent you an E-mail with a download link so you can take a quick look at it. Maybe there is an obvious mistake in it.

I'll give my best to do the measurements you requested as soon as possible!

 

Thanks again for the great support!

 

Bye

 

Matthias

 

matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am

Hello again,
for the other readers: Axel has reviewed my source code and cannot find obvious mistakes.

For further investigation I've now simply inserted (as Axel already requested) a sine generator in Audio-Weaver to check if the problem has something to do with the input or the output part of the firmware or both. 

The Layout looks like that now:

The output is still very distorted and sounds like this:

I've also put the Signal on the Oscilloscope and investigated what the Waveform looks like with shocking results:

Seems like there is something modulated on the 1kHz sine but I can't figure out what is going on here. Any Ideas how to isolate the problem even more?

 

 

Axel Nilsson
Offline
Last seen: 3 hours 24 min ago
Joined: 12/19/2016 - 2:02pm

Hi Matthias. It looks like you've shown that the problem exists for sure on the output. Now to isolate where the issue is happening, you can skip the Audio Weaver processing altogether and just write a clean sin wave into the output buffer directly in your firmware. If this is still distorted then you know the distortion isn't coming from Audio Weaver and you can focus on where in the audio path the problem lies. Keep moving this sin wave copy step further downstream in your audio path until you find that the output signal is clean.

Make sure to pick a frequency that will fit cleanly (an integer number of periods) in a single block.

 

Also, if you check the frequency content of the signal you recorded, you'll see the fundamental frequency is actually 500 Hz with a lot of harmonic content instead of a clean 1000 Hz. This is a hint that your only processing half of the data expected.

-Axel

matthias.braune_1777
Offline
Last seen: 1 week 6 days ago
Joined: 12/18/2017 - 8:15am

Hey Axel,
thanks again for your input. I'll go on and isolate the problem even more like you suggested. I really hope I can solve the issue because I am sure it is a small mistake that I am overseeing.