program form(input, output); { version H: Sun Oct 16 03:27:50 EDT 1988 } { copyright Prof. K. Steiglitz Dept. of Computer Science Princeton University Princeton, NJ 08544 } { generates input file for meteor } { Constraint-based design of linear-phase fir filters with upper and lower bounds, and convexity constraints. Finds minimum length, or optimizes fixed length, or pushes band-edges. If L is the filter length, the models are odd-length cosine: sum ( i from 0 to (L-1)/2 ) coeff[i]*cos(i*omega) sine: sum ( i from 0 to (L-1)/2 ) coeff[i]*sin((i+1)*omega) even-length cosine: sum ( i from 0 to L/2-1 ) coeff[i]*cos((i+.5)*omega) sine: sum ( i from 0 to L/2-1 ) coeff[i]*sin((i+.5)*omega) } const Lmax = 128; { filter length } nspecmax = 20; { max. no. of specifications } maxnamelength = 10; { max. length of output file name } type name = packed array [1..maxnamelength] of char; var infile, outfile: text; infilename, outfilename: name; ch: char; gotwhattodo: boolean; { remembers if we've gotten whattodo } Lsmallest, Llargest: 1..Lmax; n: integer; { there are n+1 columns from 0 to pi } i: integer; result: array[1..nspecmax] of real; whichway: (ll, rr); nspec: 0..nspecmax; { no. of bands } spectype: array[1..nspecmax] of (con, lim); { type of band } left, right: array[1..nspecmax] of real; { bandedges as read in } bound1, bound2: array[1..nspecmax] of real; { left and right bounds } sense: array[1..nspecmax] of char; { sense of constraint, + up, - down } interpolate: array[1..nspecmax] of char; { g=geometric, a=arithmetic } hug: array[1..nspecmax] of char; { allow this constraint to be hugged? } whattodo: (findlen, maxdist, pushedge); { type of optimization } npushed: integer; { number of bandedges pushed } bandpushed: array[1..nspecmax] of integer; { bandedges pushed } ok: boolean; { flag to get good input } symtype: (cosine, sine); { cosine or sine model } procedure getnum (nnum: integer); { finds the first nnum fixed-point numbers in input line, puts the numbers in the array called result } const maxlinelen= 250; zero= '0'; nine= '9'; point= '.'; blank= ' '; plus= '+'; minus= '-'; radix= 10.0; type buffer= array [1..maxlinelen] of char; var sign, count: integer; state: 0..6; scalefactor: real; length, pos: integer; ch: char; line: buffer; digit, invalid, done: boolean; procedure getline( var line: buffer; var length: integer; var infile: text); { reads a line into buffer } var ch: char; begin { getline } length:=0; while not eoln(infile) do begin read(infile, ch); if length < maxlinelen then begin length:=length+1; line[length]:=ch end end; readln(infile) end; { getline } procedure scan( var r: real; var i: integer ); { scans line buffer for a number r, starting at position i+1 } begin { scan } state:= 0; sign:= 1; while( ( i < length ) and ( state < 5 ) ) do { finite-state machine } begin { to recognize numbers } i:= i + 1; ch:= line[i]; digit:= ( zero <= ch ) and ( ch <= nine ); case state of 0: if( digit ) then begin r:= ord(ch) - ord(zero); state:= 1 end else if( ( ch = plus ) or ( ch = minus ) ) then begin if( ch = minus ) then sign:= -1; state:= 2 end else if( ch = point ) then begin scalefactor:= radix; state:= 4 end else if( ch = blank ) then state:= 0 else state:= 5; 1: if digit then r:= r*radix + ord(ch)-ord(zero) else if( ch = point ) then begin scalefactor:= radix; state:= 3 end else if( ch = blank ) then state:= 6 else state:= 5; 2: if( digit ) then begin r:= ord(ch)-ord(zero); state:= 1 end else if( ch = point ) then begin scalefactor:= radix; state:= 4 end else state:= 5; 3: if ( digit ) then begin r:= r + (ord(ch)-ord(zero))/scalefactor; scalefactor:= scalefactor*radix end else if( ch = blank ) then state:= 6 else state:= 5; 4: if( digit ) then begin r:= (ord(ch)-ord(zero))/scalefactor; scalefactor:= scalefactor*radix; state:= 3 end else state:= 5 end end; case state of 0, 2, 4, 5: invalid:= true; 1, 3, 6: r:= sign*r end; end; { scan } begin { getnum } done:= false; while ( not done ) do begin getline(line, length, input); count:= 1; invalid:= false; pos:= 0; while( ( count <= nnum ) and ( not invalid ) ) do begin scan( result[count], pos ); if( not invalid ) then begin count:= count + 1; if( count > nnum ) then done:= true end else writeln('input not valid, please try again') end end end; { getnum } procedure getspec(i: integer); { reads in data for one spec } begin { getspec } writeln; writeln(' reading data for spec ', i:3); writeln('enter "l" for a limit spec, "c" for a convexity spec'); readln(ch); if( ch = 'c' ) then begin spectype[i]:= con; writeln('enter "+" for convex up, "-" for down'); readln( sense[i] ); writeln('enter left and right band edges'); getnum( 2 ); left[i]:= result[1]; right[i]:= result[2] end; if( ch = 'l') then begin spectype[i]:= lim; writeln('enter "+" for upper limit, "-" for lower'); readln( sense[i] ); writeln('enter "a" for arithmetic interpolation, "g" for geometric'); readln( interpolate[i] ); writeln('enter "h" if this constraint can be hugged/ "n" otherwise'); readln( hug[i] ); writeln('enter left and right band edges'); getnum( 2 ); left[i]:= result[1]; right[i]:= result[2]; writeln('enter bounds at left and right band edges'); getnum( 2 ); bound1[i]:= result[1]; bound2[i]:= result[2] end; end; { getspec } procedure writefile; { writes data to outfile } begin {writefile } writeln(outfile, Lsmallest, Llargest, ' smallest and largest length'); if (symtype = cosine) then writeln(outfile, 'c') else writeln(outfile, 's'); if( whattodo = pushedge ) then begin if( whichway = ll ) then writeln(outfile, 'left direction of pushed specs') else writeln(outfile, 'right direction of pushed specs'); writeln(outfile, npushed, ' number of specs pushed'); for i:= 1 to npushed do write(outfile, bandpushed[i]); writeln(outfile, ' specs pushed') end; if( whattodo = maxdist ) then writeln(outfile, 'neither left nor right: maximize distance from constraints'); writeln(outfile, n, ' number of grid points'); for i:= 1 to nspec do begin if( spectype[i] = con ) then writeln(outfile, 'convex spec') else writeln(outfile, 'limit spec'); if( spectype[i] = lim ) then if( sense[i] = '+' ) then writeln(outfile, '+ upper limit') else writeln(outfile, '- lower limit'); if( spectype[i] = con ) then if( sense[i] = '+' ) then writeln(outfile, '+ convex up') else writeln(outfile, '- convex down'); if( spectype[i] = lim) then if( interpolate[i] = 'a' ) then writeln(outfile, 'arithmetic interpolation') else writeln(outfile, 'geometric interpolation'); if( spectype[i] = lim) then if( hug[i] = 'h' ) then writeln(outfile, 'hugged spec') else writeln(outfile, 'not hugged spec'); writeln(outfile, left[i], right[i], ' band edges'); if( spectype[i] = lim) then writeln(outfile, bound1[i], bound2[i], ' bounds') end; writeln(outfile, 'end') end; { writefile } procedure getfilename( var filename: name); { gets name of output file } var length: 0..maxnamelength; begin { getfilename } length:=0; while not eoln do begin read(ch); if length < (maxnamelength - 1) then begin length:= length + 1; filename[length]:= ch end end; readln end; { getfilename } procedure getwhattodo; { gets problem data besides specs: whattodo, Lsmallest, Llargest, npushed, bandpushed, n. Meant to be interactive, so doesn't abort. } begin { getwhattodo } gotwhattodo:= true; writeln('enter "m" to find minimum length'); writeln(' "o" to optimize'); writeln(' "p" to push a band edge'); readln(ch); if( ch = 'm' ) then whattodo:= findlen; if( ch = 'o' ) then whattodo:= maxdist; if( ch = 'p' ) then whattodo:= pushedge; if ( whattodo = findlen ) then begin writeln; writeln(' finding minimum length'); ok:= false; while not ok do begin writeln(' enter smallest and largest lengths to be considered'); writeln(' both odd, or both even, between 1 and ', Lmax:3); getnum( 2 ); Lsmallest:= trunc(result[1]); Llargest:= trunc(result[2]); if ( (Lsmallest < 1) or (Llargest > Lmax) ) then writeln('Lsmallest < 1 or Llargest > ', Lmax:3, '; please try again') else if odd(Lsmallest)<>odd(Llargest) then writeln('parity of lengths not the same; please try again') else ok:= true end end; if( whattodo = maxdist ) then begin writeln; writeln(' finding solution that maximizes distance from constraints'); ok:= false; while not ok do begin writeln(' enter (fixed) filter length, between 1 and ', Lmax:3); getnum( 1 ); Lsmallest:= trunc(result[1]); Llargest:= Lsmallest; if ( (Lsmallest < 1) or (Llargest > Lmax) ) then writeln('length < 1 or length > ', Lmax:3, '; please try again') else ok:= true end end; if ( whattodo = pushedge ) then begin writeln; writeln(' pushing edges'); ok:= false; while not ok do begin writeln(' enter (fixed) filter length, between 1 and ', Lmax:3); getnum( 1 ); Lsmallest:= trunc(result[1]); Llargest:= Lsmallest; if ( (Lsmallest < 1) or (Llargest > Lmax) ) then writeln('length < 1 or length > ', Lmax:3, '; please try again') else ok:= true end; writeln('enter "l" to push left, or "r" to push right'); readln(ch); if( ch = 'l' ) then whichway:= ll else whichway:= rr; writeln('enter number of bandedges to be pushed'); getnum( 1 ); npushed:= trunc(result[1]); writeln('enter list of bandedges to be pushed'); getnum( npushed ); for i:= 1 to npushed do bandpushed[i]:= trunc(result[i]) end; writeln('enter "c" or "s" for cos or sin model (symm. or anti-symm. coeffs.)'); readln(ch); if (ch = 'c') then symtype:= cosine else symtype:= sine; writeln('enter number of grid points less 1'); getnum( 1 ); n:= trunc(result[1]) end; { getwhattodo } procedure print; { prints table of specs and whattodo } begin { print } if( nspec > 0 ) then begin writeln(' # type sense edge1 edge2 bound1 bound2 hugged? interp'); for i:= 1 to nspec do begin if( spectype[i] = lim ) then writeln(i:3, ' limit ', sense[i], ' ', left[i]:8:5, ' ', right[i]:8:5, ' ', bound1[i]:8:5, ' ', bound2[i]:8:5, ' ', hug[i], ' ', interpolate[i]); if( spectype[i] = con ) then writeln(i:3, ' convex ', sense[i], ' ', left[i]:8:5, ' ', right[i]:8:5, ' ') end end; if( gotwhattodo ) then begin if( whattodo = findlen ) then begin writeln(' FINDING MIN LENGTH '); if odd(Lsmallest) then writeln(' ODD LENGTHS from ', Lsmallest:3, ' to ', Llargest:3) else writeln(' EVEN LENGTHS from ', Lsmallest:3, ' to ', Llargest:3) end; if( whattodo = maxdist ) then writeln(' OPTIMIZING, fixed length= ', Lsmallest:3); if( whattodo = pushedge ) then begin if( whichway = ll ) then write('PUSHING ', npushed:2, ' BANDEDGES LEFT, fixed length= ', Lsmallest:3); if( whichway = rr ) then write('PUSHING ', npushed:2, ' BANDEDGES RIGHT, fixed length= ', Lsmallest:3); write(', bands: '); for i:= 1 to npushed do write(bandpushed[i]:3); writeln; end; if (symtype = cosine) then writeln(' COSINE model (symmetric coeffs.)') else writeln(' SINE model (anti-symmetric coeffs.)'); writeln(' ', (n+1):5, ' grid points') end end; { print } procedure delete(k: integer); { deletes k-th spec } begin { delete } for i:= k to (nspec-1) do begin sense[i]:= sense[i+1]; left[i]:= left[i+1]; right[i]:= right[i+1]; bound1[i]:= bound1[i+1]; bound2[i]:= bound2[i+1]; hug[i]:= hug[i+1]; spectype[i]:= spectype[i+1]; sense[i]:= sense[i+1]; left[i]:= left[i+1]; right[i]:= right[i+1] end; nspec:= nspec - 1 end; { delete } procedure readdata; { reads in data from old file } { not meant to be interactive, so aborts on bad filter lengths } begin { readdata } readln(infile, Lsmallest, Llargest); readln(infile, ch); if (ch = 'c') then symtype:= cosine else symtype:= sine; if odd(Lsmallest)<>odd(Llargest) then begin writeln('parity of lengths not the same in input file: quitting'); halt end; if ( (Lsmallest < 1) or (Llargest > Lmax) ) then begin writeln('filter length out of range: quitting'); halt end; if( Lsmallest <> Llargest ) then whattodo:= findlen; if( Lsmallest = Llargest ) then begin readln(infile, ch); { right, left, or neither: edges to be pushed? } if( ch = 'n' ) then whattodo:= maxdist else begin whattodo:= pushedge; if( ch = 'r' ) then whichway:= rr else whichway:= ll; readln(infile, npushed); for i:= 1 to npushed do read(infile, bandpushed[i]); readln(infile) end end; gotwhattodo:= true; readln(infile, n); { there are n+1 grid points between 0 and pi } nspec:= 0; readln(infile, ch); while( ch <> 'e' ) do { 'e' for end } begin nspec:= nspec + 1; i:= nspec; if( ch = 'c') then begin spectype[i]:= con; readln( infile, sense[i] ); readln( infile, left[i], right[i] ) end; if( ch = 'l') then begin spectype[i]:= lim; readln( infile, sense[i] ); readln( infile, interpolate[i] ); readln( infile, hug[i] ); readln( infile, left[i], right[i] ); readln( infile, bound1[i], bound2[i] ); end; readln(infile, ch) { next } end { while } end; { readdata } begin { main } writeln('WELCOME TO METEOR FORMATTER: GENERATES INPUT FILE FOR METEOR'); writeln; gotwhattodo:= false; nspec:= 0; writeln('enter "y" if you want to edit an old file'); readln(ch); if( ch = 'y') then begin writeln('enter name of input file, up to ', maxnamelength:3, ' characters'); getfilename(infilename); writeln('filename: ', infilename); reset(infile, infilename); readdata; print end; writeln; writeln('enter name of output file, up to ', maxnamelength:3, ' characters'); getfilename(outfilename); while( outfilename = infilename ) do begin writeln('same as infilename, please try again'); getfilename(outfilename) end; writeln('filename: ', outfilename); rewrite(outfile, outfilename); ch:= 'x'; while( ch <> 'w' ) do begin writeln(' '); writeln('enter "y" to read spec number ', nspec+1:3); writeln(' "p" to print current information'); writeln(' "r" to re-enter a spec'); writeln(' "d" to delete a spec'); writeln(' "s" to specify what to do'); writeln(' "w" to write output file and exit'); readln(ch); if( ch = 'y' ) then begin nspec:= nspec + 1; getspec(nspec) end; if( ch = 'p' ) then print; if( ch = 'r' ) then begin writeln('enter number of spec you want to re-enter'); getnum( 1 ); i:= trunc(result[1]); getspec(i) end; if( ch = 'd') then begin writeln('enter number of spec you want to delete'); getnum(1); i:= trunc(result[1]); delete(i) end; if( ch = 's') then getwhattodo; if( ch = 'w' ) then if( gotwhattodo and ( nspec > 0 ) ) then begin writeln; write('writing file "'); for i:= 1 to 10 do if (outfilename[i]<> ' ') then write(outfilename[i]); writeln('" and exiting'); writefile end else begin if( not gotwhattodo ) then writeln('please specify what to do'); if( nspec = 0 ) then writeln('please enter some specs'); ch:= 'x' { don't exit loop } end end end. { main }