DSPRelated.com
Forums

Fixed Point Arithmetic, Scaling Coefficients

Started by jag304 February 21, 2008
Hi All,

I'm fairly new to DSP, but have learned a lot since I've started work on
it for my senior project at a university. Meaning, please bear with me.

For purposes of discussion here, I'm trying to implement IIR filters in
the audio frequency range. Accomplishing this has proven to be more
difficult than I think it should. I've written Matlab programs to help me
along the way. I've written a few programs which calculate the filter
coefficients for 2nd and 4th order high pass, bandpass and low pass
butterworth filters. These simulate great in matlab.

Next step: I've written a matlab program which takes those fractional
coefficients, divides by a scalar chosen by the user, and then converts
those new fractions to binary and then to hex for actual use on my DSP
chip (which is a Freescale DSP56366, by the way. I have the Freescale
DSPAUDIOEVM).

I simulated with simply dividing all of my coefficients by the largest
needed integer to get all coefficients between -1 and 1. This obviously
didn't work, as I've learned more about now.

I guess to cut to the chase: I'm trying to understand more about fixed
point arithmetic. Only tonight after several hours did I get any
meaningful results, after reading many posts on these boards.

My operation: All coefficients are scaled down by 8 (2^3), and then
converted to hex. In my code when I go to store my coefficients, I shift
them left by 12 bits. This is effectively Q15 representation (Multiplying
by 2^15 and dividing by 2^3 gives 2^12).

I then perform my mac operations, and when finished, shift right by 12
bits. Filtering occurs, but not at the correct frequencies (designing for
cutoff at 200Hz actually is -3dB at 7.3kHz...), and actually with
unexpected gain in some situations. 

I suppose my longwinded question is, am I on the right path? The last
problem I am seeing in my way is this scaling of coefficients, which seems
to completely alter filter characteristics in some ways (likely something I
am doing wrong). I have read as much as I can find about fixed point
arithmetic, but any other resources or opinions would be greatly
appreciated.

Also, if any of my code is desired just ask.
Thanks in advance.

- Jim


Hello Jim,

it´s not fairly clear to me what you are doing, but I think you have some
fix point arithmetic problem (Your coefficients are too high).

So:
1) look in your forward and backward coefficients for biggest coefficient
2) take the log2 of the biggest coefficient and round up to the next
bigger integer value = BI
3) divide all coefficients by 2^BI. They should be now between [-1 1[
4) calculate the  fractional representation of the values for your DSP
5) adapt your filter structure with a number of left shifts BI in the
forward path of the feedback part of your filter structure

to make point 5 more clear (it´s the same for higher order filter):


x                   ___                               y
>----> b_0---------|+ |------->SHIFT left by BI ------>
| |__| | | / \ z^-1 z^-1 / \ | | / \ | |---> b_1----- ---------a_1 <----------- Maybe you have to do the feedback part in double precision (round cycle noise problem). Check that your feedback coefficients have the correct sign - Between the above implementation and the output/input of Matlab functions the "a_" coefficients are toggled in sign. Check that you might have no overflow after the FIR part, or some extension register is capable to manage this in the summation point. Hope that helps, Markus www.two-pi.com
"jag304" <jag304@lehigh.edu> writes:
> [...]
Hi Jim, If your frequency response is this far off, you're doing something very wrong somewhere. You should be able to explain exactly what any arithmetic operation does on your DSP using the rules of fixed-point arithmetic. I have documented those rules in a paper, "Fixed Point Arithmetic: An Introduction" http://www.digitalsignallabs.com/fp.pdf You should be able to understand exactly how to convert any coefficient generated by Matlab into a fixed-point representation. You should know what happens in the accumulator when you multiply a coefficient by a data value and sum the result. If taking a look at this documentation or thinking on these things produces more questions, then let us know what they are. -- % Randy Yates % "She's sweet on Wagner-I think she'd die for Beethoven. %% Fuquay-Varina, NC % She love the way Puccini lays down a tune, and %%% 919-577-9882 % Verdi's always creepin' from her room." %%%% <yates@ieee.org> % "Rockaria", *A New World Record*, ELO http://www.digitalsignallabs.com
Maybe my beautiful ASCII art works with dots instead of blanks:

x..................___...............................y
>----> b_0---------|+ |------->SHIFT left by BI ------>
.|................|__|..........................|.... .|.............. /...\........................z^-1... .z^-1.........../.....\.........................|.... .|............./.......\........................|.... .|---> b_1-----.........---------a_1 <-----------.... For the calculation of your fix point arithmetic values, please use Randys link. Fine Regards, Markus www.two-pi.com
On Feb 21, 8:25 am, "jag304" <jag...@lehigh.edu> wrote:
> Hi All, > > I'm fairly new to DSP, but have learned a lot since I've started work on > it for my senior project at a university. Meaning, please bear with me. > > For purposes of discussion here, I'm trying to implement IIR filters in > the audio frequency range. Accomplishing this has proven to be more > difficult than I think it should. I've written Matlab programs to help me > along the way. I've written a few programs which calculate the filter > coefficients for 2nd and 4th order high pass, bandpass and low pass > butterworth filters. These simulate great in matlab. > > Next step: I've written a matlab program which takes those fractional > coefficients, divides by a scalar chosen by the user, and then converts > those new fractions to binary and then to hex for actual use on my DSP > chip (which is a Freescale DSP56366, by the way. I have the Freescale > DSPAUDIOEVM). > > I simulated with simply dividing all of my coefficients by the largest > needed integer to get all coefficients between -1 and 1. This obviously > didn't work, as I've learned more about now. > > I guess to cut to the chase: I'm trying to understand more about fixed > point arithmetic. Only tonight after several hours did I get any > meaningful results, after reading many posts on these boards. > > My operation: All coefficients are scaled down by 8 (2^3), and then > converted to hex. In my code when I go to store my coefficients, I shift > them left by 12 bits. This is effectively Q15 representation (Multiplying > by 2^15 and dividing by 2^3 gives 2^12). > > I then perform my mac operations, and when finished, shift right by 12 > bits. Filtering occurs, but not at the correct frequencies (designing for > cutoff at 200Hz actually is -3dB at 7.3kHz...), and actually with > unexpected gain in some situations. > > I suppose my longwinded question is, am I on the right path? The last > problem I am seeing in my way is this scaling of coefficients, which seems > to completely alter filter characteristics in some ways (likely something I > am doing wrong). I have read as much as I can find about fixed point > arithmetic, but any other resources or opinions would be greatly > appreciated. > > Also, if any of my code is desired just ask. > Thanks in advance. > > - Jim
Try using FDATool in Matlab to design filters. You have an option to scale the coefficients. If you use Butterworth you can simplify many of them (they become 1 or -1). If I were you I would scale them between -2 and 2. Cheers
> >Maybe my beautiful ASCII art works with dots instead of blanks: > >x..................___...............................y >>----> b_0---------|+ |------->SHIFT left by BI ------> >.|................|__|..........................|.... >.|.............. /...\........................z^-1... >.z^-1.........../.....\.........................|.... >.|............./.......\........................|.... >.|---> b_1-----.........---------a_1 <-----------.... > > >For the calculation of your fix point arithmetic values, please use
Randys
>link. > >Fine Regards, >Markus > >www.two-pi.com >
Ok, last try: If you copy and paste the ASCII picture in an text editor (with equally spaced fonts) you will see the correct schematic. Fine regards, Markus www.two-pi.com
it's been a while since i coded for any Mot 56K or 563xx, but i
remember a few things about it.

On Feb 21, 6:25 am, "jag304" <jag...@lehigh.edu> wrote:
> > My operation: All coefficients are scaled down by 8 (2^3),
so you're saying that the natural range of your coefficients are meant to be between -8 and just under +8, right? and the 563xx core in your chip has a natural scaling of -1 to just under +1, right? the Mot assembler knows how to deal with constants (immediate addressing mode or "dc" in memory) that are expressed as fractional, base 10 numbers: -1.0000000 <= the_constant <= 0.99999998
> and then > converted to hex. In my code when I go to store my coefficients, I shift > them left by 12 bits.
*what* are you shifting left 12 bits? an integer? a fixed point fractional number? for a simple biquad filter, your feedback coefficients will be less than 2 in magnitude, your feedforward coefs could be greater (like 8, which seems like a logical range), but to implement that greater range (of +/- 8), you must shift the output value (in accumulator A or B) left 3 bits before storing the (possibly saturated) accumulator into memory or wherever it goes.
> This is effectively Q15 representation
but it's a 24-bit DSP. ???
> (Multiplying > by 2^15 and dividing by 2^3 gives 2^12). > > I then perform my mac operations, and when finished, shift right by 12 > bits.
uh, i don't think you should be doing that. maybe you should shift *left* by 3 bits. do you not get your output from the most significant word (not the 8 guard bits) in the accumulator (a1 or b1)?
> Filtering occurs, but not at the correct frequencies (designing for > cutoff at 200Hz actually is -3dB at 7.3kHz...), and actually with > unexpected gain in some situations. > > I suppose my longwinded question is, am I on the right path? The last > problem I am seeing in my way is this scaling of coefficients, which seems > to completely alter filter characteristics in some ways (likely something I > am doing wrong). I have read as much as I can find about fixed point > arithmetic, but any other resources or opinions would be greatly > appreciated. > > Also, if any of my code is desired just ask.
yeah, you better put some of that up. r b-j
Alrighty then. Here is my MatLab code for converting Fractional Numbers to
Binary and then to Hex. The DSP56366 uses fixed point representation from
2^(0) to 2^(-23) where 2^(0) is the sign bit. 

function coef2hex(coef,scaling)
format long 

a = zeros(1,24);
if(coef<0)                %If negative, first bit is 1
    a(1) = 1;
    newcoef=-coef/scaling;  %Make coefficient positive for processing
else
    a(1) = 0;            %If positive, first bit is 0
    newcoef = coef/scaling;
end

for(i=2:1:24)              %Generating binary representation
    if(newcoef>=2^(-i+1))
        a(i) = 1;
        newcoef = newcoef - 2^(-i+1);
    end
end

if(a(1)==1)
    
    hitFirst1 = 0;
    for(i=24:-1:2)   %Starting at the LSB, scan left
        
        if(hitFirst1==1)  %If already found first bit, 
            if(a(i)==1)     %invert all following bits to the left
                a(i)=0;
            else
                a(i)=1;
            end
        end
        
        if(hitFirst1==0 && a(i)==1)
            hitFirst1=1;
        end
    end
end


%Done making binary representation
S = int2str(a);

%Time to go to hex

for(i=4:4:24)
    h(i/4) = a(i-3)*8 + a(i-2)*4 + a(i-1)*2 + a(i)*1;
    
    if(h(i/4)<10)
        T(i/4) = int2str(h(i/4));
    elseif(h(i/4)==10)
        T(i/4) = 'A';
    elseif(h(i/4)==11)
        T(i/4) = 'B';
    elseif(h(i/4)==12)
        T(i/4) = 'C';
    elseif(h(i/4)==13)
        T(i/4) = 'D';
    elseif(h(i/4)==14)
        T(i/4) = 'E';
    elseif(h(i/4)==15)
        T(i/4) = 'F';
    end
end    
    
T

Next up, one of my programs which computes the filter coefficients based on
cutoff frequency and sampling frequency. I got the coefficient formulae by
using Maple to do a bilinear transformation on a 2nd order butterworth low
pass filter. By defining the sinusoids at the beginning I can test
different filter types and settings. 

function secondordlowpass(cutoff,fs,scale)
format long 

t = 0:(1/fs):0.025;
x = sin(2*pi*200*t) + sin(2*pi*2000*t);

Wo = 2*pi*cutoff;

a1 = (Wo^2)/(4*fs^2+Wo^2+2*sqrt(2)*Wo*fs)

a2 = 2*a1

a3 = a1

b1 = (-8*fs^2 + 2*Wo^2)/(4*fs^2 + Wo^2 + 2*sqrt(2)*Wo*fs)

b2 = (-2*2^(1/2)*Wo*fs+4*fs^2+Wo^2)/(4*fs^2+Wo^2+2*sqrt(2)*Wo*fs)

%Done finding coefficients

subplot(311),plot(t,x);
title('2kHz Sinusoid Modulated On a 200Hz Sinusoid');
xlabel('Time');
ylabel('Magnitude');

y = zeros(1,length(x));

for(n=3:1:length(x))       %For every sample of the input
    y(n) = a1*x(n) + a2*x(n-1) + a3*x(n-2) - b1*y(n-1) - b2*y(n-2);
end

subplot(312),plot(t,y);

title(['Sinusoidal Input Filtered by a 2nd Order Low Pass Butterworth with
a ',num2str(cutoff),...
    'Hz Cutoff Frequency']);
xlabel('Time');
ylabel('Magnitude');

coef2hex(a1,scale);
coef2hex(a2,scale);
coef2hex(a3,scale);
coef2hex(-b1,scale);
coef2hex(-b2,scale);

I can keep track of a scaling factor here which is used in converting the
fractional numbers to hex, to be sure there is no overflow. 
On Feb 21, 3:20 pm, "jag304" <jag...@lehigh.edu> wrote:
> Next up, one of my programs which computes the filter coefficients based on > cutoff frequency and sampling frequency. I got the coefficient formulae by > using Maple to do a bilinear transformation on a 2nd order butterworth low > pass filter.
that's one way to get get 'em.
> > coef2hex(a1,scale); > coef2hex(a2,scale); > coef2hex(a3,scale); > coef2hex(-b1,scale); > coef2hex(-b2,scale);
why are you doing this at all? don't you know that you can define constants in the 563xx asm language as: org y:$100 a0 dc 0.98765432 a1 dc 0.12345678 ... ??? there is no need anywhere i am aware of to convert your coefficients to integer values, let alone hexadecimal. if you're loading these coefs into the DSP via some CPU that sees everything as integers, then you simply scale the coefficients up by 2^23 (if the range is -1 to +1) or 2^20 (if the range is -8 to +8), round to the nearest integer (MATLAB has the round() function, but if it's in C or someplace without round(), you can add 0.5 and round down with the floor() function). something like this: a0_fixed = round(8388608.0*a0); or a0_fixed = floor(8388608.0*a0 + 0.5); if -1 <= a0 < +1 . (8388608 happens to be 2^23.) as best as i can tell, you're making this so much harder than it need be nor should be. r b-j