Understanding cascaded integrators

Started by ChuckMcM 5 years ago2 replieslatest reply 5 years ago257 views

Hi All,

I am working my way though the design and implementation of a #CIC filter to process the output of a PDM waveform (coming from a MEMS microphone). I know there are libraries and canned functions to use here, the goal is the learning.

The microphone returns a stream of 1s and 0s to represent full on and full off. When it is quiet, the microphone is sending 1/0/1/0/1/0/1/0... which averages out to 0.5 (or if you use +1 for 1, and -1 for 0 to 0, this removes the nominal DC bias from the signal). My integrator code is simply: 

integrator[0].acc += (bit == 1) ? 1 : -1;

The member acc is a signed 32 bit integer. In cascade my code looks like :

integrator[0].acc += (bit == 1) ? 1 : -1;
integrator[1].acc += integrator[0].acc;
integrator[2].acc += integrator[1].acc;
integrator[3].acc += integrator[2].acc;

Of course its in a loop in my code but you get the point. When I feed this cascade with a stream of alternating 1s and zeros I get some results that I am trying to understand. And, as with most things, having multiple gaps in my knowledge operating in parallel leads to its own issues. 

So with a stream of 0x55 (0101010101010101....) after iterating for 16384 cycles my integrator accumulators have 0, -65536, -65536, -715882496 in them.  looking at that in binary it looks like this:

Stage values:
        [0] -                    0      00000000000000000000000000000000
        [1] -               -65536      11111111111111111111000000000000
        [2] -               -65536      11111111111111111111000000000000
        [3] -           -715882496      11111101010101010100100000000000

Clearly 1/0/1/0... is the nyquist frequency coming from the microphone. If I try 0x0f (Fs/8) as the test input I get :

Stage values:
        [0] -                    0      00000000000000000000000000000000
        [1] -              -262144      11111111111111111100000000000000
        [2] -              -262144      11111111111111111100000000000000
        [3] -           1431764992      0000010101010101011100000000000
[ - ]
Reply by chalilOctober 20, 2019

Hi, you may check your mac. CIC expects the addition to be signed int add without saturation, ie if the value overflows it should wrap instead of saturation. overflow is expected with finite acc width unless you do stage wise shift then there is no issues. 

when i did similar exercise couple years years back, i had written a matlab code for early simulation. you may find it useful for understanding purpose, relevant parts attached. 

the integration stage:

    obj.aState(1) = ls_math.add(obj.aState(1) , x(i));
    for j = 1:obj.N 
           obj.aState(j + 1) = ls_math.add(obj.aState(j + 1) , obj.aState(j));

the add and sub routines are as follows for the required acc width. bits is the max acc width. This simulates 2's complement signed add / sub for user specified acc width. when you add/sub with 32bit integer or 64 bit int in C, normal signed add would do. 

function s = wrap(sum)
           % bits = 31
           bits = 60;  
           minv = -2^bits;
           maxv = 2^bits-1;
           s = sum;
                if(sum > maxv)
                    s = minv + s-(maxv);
                if(sum < minv)
                    dd = abs(s)-abs(minv);
                    s = maxv - dd;
      function s = add( a, b)
                s = ls_math.wrap(a+b);
      function s = sub( a, b)
                s = ls_math.wrap(a-b);      
      function s = mul( a, b)
                s = ls_math.wrap(a*b);

hope it helps. 


[ - ]
Reply by ChuckMcMOctober 20, 2019

Hi Chalil, 

It is helpful, thank you. In this particular case I am relying on the 32 bit nature of the registers to deal with overflow.

The math question though is the relationship of a discrete element integrator to the notion of integration. A typically integration of \( \cos(x) \) returns \( \sin(x) \).

$$ \int \cos(x) \,dx = \sin(x) + C $$

The constant C depends on the initial conditions, which we assume are zero. Over the definite interval of \( (0, 2\pi) \) evaluates to zero. What is more evaluating over the interval \( (0, k*2\pi) \) should also evaluate to zero for values of 1, 2, 3, ... of k.

The sequence 101010... means \( \omega = F_{s}/2 \) And \( 2\pi \) would be four bits.

So if cascading integrators in discrete mathematics was equivalent to

$$ \iint \cos(x) $$

Then each level of integration would swap the function from \( \cos(x) \) to \( \sin(x) \) an back again. So integrating over an interval that was a multiple of \( \omega \) I would expect result in zero.

And yet my code shows an increasing integrator value in all integrators > 2. I'm trying to figure out if my code is wrong, or if I still don't understand the mathematics behind cascaded integrators.


(should be interesting to see if MathJAX catches all of that math :-))