[openfirmware] r1271 - cpu/x86

svn at openfirmware.info svn at openfirmware.info
Tue Aug 4 03:32:33 CEST 2009


Author: wmb
Date: 2009-08-04 03:32:33 +0200 (Tue, 04 Aug 2009)
New Revision: 1271

Modified:
   cpu/x86/iirfilter.fth
Log:
Commented IIR upsampling filter code.




Modified: cpu/x86/iirfilter.fth
===================================================================
--- cpu/x86/iirfilter.fth	2009-08-04 00:46:03 UTC (rev 1270)
+++ cpu/x86/iirfilter.fth	2009-08-04 01:32:33 UTC (rev 1271)
@@ -1,12 +1,22 @@
-purpose: IIR digital filter support
+purpose: IIR digital upsampling filter
 
-\ iir-cascade implements the "Folded Cascade First Order Filters"
-\ structure as shown on page 274 of _Multirate Signal Processing
-\ for Communications Systems_ by fredric j harris, Prentice Hall 2004
-\ ISBN 0-13-146511-2
+\ This file implements x2 and x3 upsampling filters using techniques
+\ described in chapter 10 of _Multirate Signal Processing for Communications
+\ Systems_ by fredric j harris, Prentice Hall 2004, ISBN 0-13-146511-2
+\ The filters may be cascaded for x6 upsampling (e.g. for 8kHz -> 48kHz)
 
-d# 14 constant mulscale
+d# 15 constant mulscale  \ Bits for fractional multipliers
 
+0 [if]
+
+\ iir-cascade-z2 implements a folded cascade of multiple sections
+\ of a second-order IIR filter block in a polynomial in Z^2.
+\ This is the basic building block for half-band all-pass
+\ recursive filters, as described in section 10.2 of the book
+\ cited above.   
+\ This code is commented out because we don't use it directly,
+\ instead using the -z1 variant below in a polyphase structure.
+
 code iir-cascade-z2 ( sample weights z #sections -- out )
    cx pop     \ CX: Number of sections
 
@@ -28,20 +38,29 @@
 
       0 [bp]       dx  mov
       dx       4 [bp]  mov
-      bx       0 [bp]  mov   \ Update M[i]
+      bx       0 [bp]  mov   \ Update Z[i]
 
-      8 [bp]       bp  lea   \ Point to next M[i]
+      8 [bp]       bp  lea   \ Point to next Z[i]
    loopa
 
    0 [bp]       dx  mov
    dx       4 [bp]  mov
-   ax       0 [bp]  mov   \ Update M[i]
+   ax       0 [bp]  mov   \ Update Z[i]
 
    bp pop     \ Restore BP
    si pop     \ Restore SI
    ax push    \ Return value
 c;
 
+\ iir-cascade-z1 is the same basic structure as iir-cascade-z2,
+\ but the Z^-2 delays have been replaced by Z^-1.  It is used
+\ in the polyphase upsampler "up2".  When the rate is doubled,
+\ a zero sample is inserted between each pair of input samples,
+\ causing every other computation of the Z^-2 polynomial to be
+\ unnecessary.  The basic block can thus be restructured to have
+\ a single delay element, and the block only has to run at half
+\ the rate.  See section 10.6 (figure 10.48) of the book.
+
 code iir-cascade-z1 ( sample weights z #sections -- out )
    cx pop     \ CX: Number of sections
 
@@ -54,25 +73,32 @@
    bx push    \ Saved BP on stack
    begin
       ax           bx  mov   \ Save last value
-      d#  4 [bp]   ax  sub   \ last - M[i+1]
+      d#  4 [bp]   ax  sub   \ last - Z[i+1]
 
-      0 [si]           imul  \ alpha[i] * (last - M[i+1])  (kills DX)
+      0 [si]           imul  \ alpha[i] * (last - Z[i+1])  (kills DX)
       4 [si]       si  lea   \ Increment alpha pointer
       mulscale #  dx  ax  shrd  \ Scale down by multiplier scale factor
 
-      d#  0 [bp]   ax  add   \ M[i] + alpha[i] * (last - M[i+1])
+      d#  0 [bp]   ax  add   \ Z[i] + alpha[i] * (last - Z[i+1])
 
-      bx       0 [bp]  mov   \ Update M[i]
+      bx       0 [bp]  mov   \ Update Z[i]
 
-      4 [bp]       bp  lea   \ Point to next M[i]
+      4 [bp]       bp  lea   \ Point to next Z[i]
    loopa
-   ax          0 [bp]  mov   \ Update M[i]
+   ax          0 [bp]  mov   \ Update Z[i]
 
    bp pop     \ Restore BP
    si pop     \ Restore SI
    ax push    \ Return value
 c;
 
+\ iir-cascade-z2g implements the generalized second-order
+\ low pass filter cascade as shown in section 10.5.1 (figure 10.35)
+\ of the book.  The generalized form allows arbitrary bandwidths
+\ as opposed to the half-band restriction of the simplifed form.
+\ We use this form for 3x upsampling so we can set the lowpass
+\ frequency to Fnyquist/3.
+
 code iir-cascade-z2g  ( sample weights z #sections -- out )
    cx pop     \ CX: Number of sections
 
@@ -121,12 +147,14 @@
 c;
 
 
+\ Convert a decimal fraction to a scaled integer multiplier
 : mul:  ( "coef" -- )
    safe-parse-word  push-decimal $number drop pop-base  ( n )
    1 mulscale lshift  d# 1,000,000,000 */                         ( n' )
    ,
 ;
 
+\ Clip too-large sample values to +- 15 bits
 code saturate  ( s -- s' )
    ax pop
    d# 32767 # ax cmp  >  if
@@ -146,44 +174,56 @@
 ;
 [then]
 
-\ upsample by 4
-
 2 constant #coefs
 
 \ This is for a 9-pole, 9-zero 2-path all-pass halfband IIR filter
+\ From page 278 of the book
 create weights0 mul: .101467517  mul: .612422841   \ Even path
 create weights1 mul: .342095596  mul: .867647439   \ Odd path
 
 0 [if]
 \ This is for a 5-pole, 5-zero 2-path all-pass halfband IIR filter
+\ From page 276 of the book
 create weights2 mul: .141348600   \ Even path
 create weights3 mul: .589994800   \ Odd path
 [then]
 
 \ This is for a 5-pole, 5-zero 2-path all-pass third-band IIR filter
 \ G0 and G1 use iir-cascade-z2g, H1 uses iir-cascade-z1
+\ This is derived from the 5-pole halfband coefficients according
+\ to the formulas on page 291, with fb/fs = 1/6 (fb/fnyquist = 1/3).
+\ The book has a missing sign somewhere, because without the minus
+\ signs on c1 and b, you end up with the corner frequency at 2/6
+\ instead of 1/6.  I had to figure that out the hard way, by trial
+\ and error (looking at spectra of impulse responses).  If you
+\ replace b with -b in equation 10.25, the c1's work out automatically.
+
+\               c1                c2
 create coefg0   mul: -.605502011  mul: .211004022    \ Even path G0
 create coefg1   mul: -.817448745  mul: .634897489    \ Odd path G1
+\               b
 create coefh1   mul: -.267949192
 
 
-#coefs 1+ 2* /n* constant buflen
-buflen buffer: z0  \ First upsampler even path delay buffer
-buflen buffer: z1  \ First upsampler odd path delay buffer
-buflen buffer: z2  \ 3x upsampler even path G0 delay buffer
-buflen buffer: z3  \ 3x upsampler odd path G1 delay buffer
-buflen buffer: z4  \ 3x upsampler odd path H1 delay buffer
+2 1+ /n* constant buflen0  \ 2 stages of Z^-1 plus final feedback
 
-: init-upsample
-   z0 buflen erase
-   z1 buflen erase
-   z2 buflen erase
-   z3 buflen erase
-   z4 buflen erase
+buflen0 buffer: z0  \ First upsampler even path delay buffer
+buflen0 buffer: z1  \ First upsampler odd path delay buffer
+
+1 1+ 2* /n* constant buflen0  \ 1 stage of Z^-2 plus final feedback
+
+buflen1 buffer: z2  \ 3x upsampler even path G0 delay buffer
+buflen1 buffer: z3  \ 3x upsampler odd path G1 delay buffer
+buflen1 buffer: z4  \ 3x upsampler odd path H1 delay buffer
+
+: init-upsample  ( -- )
+   z0 buflen0 erase
+   z1 buflen0 erase
+   z2 buflen1 erase
+   z3 buflen1 erase
+   z4 buflen1 erase
 ;
 
-0 value lastsample
-
 \ This is a polyphase decomposition of upsampling by 2
 \ The filter prototype for each path is a polynomial in Z^2,
 \ but when you apply the polyphase transform with Nobel's identity,
@@ -194,6 +234,8 @@
 ;
 
 0 [if]
+0 value lastsample
+
 \ This is the base rate (non-polyphase) version of up2
 \ Both paths run for each sample, with Z^-1 between the
 \ paths, summing the paths to get a lowpass output.
@@ -234,6 +276,7 @@
 : 8khz>48khz  ( inbuf #samples stride outbuf -- )
    to sample-stride         ( inbuf #samples outbuf )
    sample-outp !            ( inbuf #samples )
+   init-upsample            ( inbuf #samples )
    0  ?do                   ( inbuf )
       dup sample-stride +   ( inbuf inbuf' )
       swap <w@              ( inbuf' sample )
@@ -247,6 +290,7 @@
 : 16khz>48khz  ( inbuf #samples stride outbuf -- )
    to sample-stride         ( inbuf #samples outbuf )
    sample-outp !            ( inbuf #samples )
+   init-upsample            ( inbuf #samples )
    0  ?do                   ( inbuf )
       dup sample-stride +   ( inbuf inbuf' )
       swap <w@              ( inbuf' sample )
@@ -254,3 +298,28 @@
    loop                     ( inbuf )
    drop
 ;
+
+0 [if]
+\ Here is some Matlab/Octave code to do the "coefg.." coefficient
+\ transformations
+function retval = c1(a, b)
+   retval = 2 * b * (1 + a) / (1 + a * b * b);
+end
+function retval = c2(a, b)
+   retval = ((b * b) + a) / (1 + a * b * b);
+end
+function retval = cvtb(frac)
+   retval = (1 - tan(pi * frac)) / (1 + tan(pi * frac));
+end
+function cvtfilt (bw) % bw is fb/fs
+  a0 = .141348600
+  a1 = .589994800
+
+  b = cvtb(bw)
+  c10 = c1(a0, b)
+  c20 = c2(a0, b)
+  c11 = c1(a1, b)
+  c21 = c2(a1, b)
+end
+cvtfilt(1/6);
+[then]




More information about the openfirmware mailing list