perm filename AWFIL.SAI[HAK,ROB] blob sn#507807 filedate 1980-05-04 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00006 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	begin "AWFIL"
C00003 00003	! requires and other declarations
C00005 00004	! local procedures
C00010 00005	! main program here
C00013 00006	end "AWFIL"
C00014 ENDMK
C⊗;
begin "AWFIL"

require "HEADER.SAI[LIB,ROB]" source_file;

! lotsa stuff drawn from
	JAMLIB.JAM[UP,DOC]
	JAMLIB.SAI[SUB,SYS]
	JAMLIB.HDR[SUB,SYS];

! This program takes the frequency response of a system and calculates the
  coefficients for a set of second order filters which would flatten the
  response of the system.

  The input parameters are:
	a text file named MAGFRQ.TXT which contians a preload_with spec for
	   the magnitude of the frequency array.  Should be NPoints long.

  The outputs are:
	various plots of the system response
	the coefficients of the second order sections

  ;
! requires and other declarations;

require "JAMLIB.REL[SUB,SYS]" library;
    external integer procedure POLY(
	real array A; reference real array ZR,ZI; integer N);
    external procedure RTRAN(
	real array X,A,B; integer log2N; boolean inverse);
    external real procedure AUTSOL(
	real array R,A,K; integer M);
    external string procedure DEFAULT(string Inp; reference string Dev;
		string Devext,Devdev);
    external procedure DSETUP(integer nwds; reference integer id);
    external procedure BUFCLR(integer id,nwds);
    external boolean procedure DRELS(reference integer id);
    external procedure WRITE(integer id,pog);
    external procedure DPYSL(integer id; real array X;
	integer N,Nslices,sliceN; string xlabel,ylabel;
	real vxmin,vxmax);

DEFINE
  NPoints = {512},	comment the number of input points;
  Log2NPoints = {9};

! local procedures;

procedure COMBINE(
    real array Rls,Ims,Ai,Bi; integer M);
    begin "COMBINE"
	boolean array taken[1:M];
	integer ind,upto,jj;

	arrclr(taken);
	ind←1;
	for upto←1 step 1 until M do
	begin "FFCR"
	  if taken[upto] then continue "FFCR";
	  if abs(Ims[upto])<.0000001 then
	  begin "ISR"
	    for jj←upto+1 step 1 until M do
	      if abs(Ims[jj])<.0000001 then done;
	    if jj≤M then
	    begin "ISANO"
		Ai[ind]←-Rls[upto]-Rls[jj];
		Bi[ind]←Rls[upto]*Rls[jj];
		taken[jj]←true;
	    end "ISANO"
	    else begin "NOTAN"
		Ai[ind]←-Rls[upto];
		Bi[ind]←0;
	    end "NOTAN";
	  end "ISR"
	  else begin "ISI"
	    for jj←upto+1 step 1 until M do
	      if abs(Ims[upto]+Ims[jj])<.0000001
		∧ abs(Rls[upto]-Rls[jj])<.0000001 then done;
	    if jj>M then usererr(0,0,"Complex filter?????");
	    Ai[ind]←-2*Rls[upto];
	    Bi[ind]←Rls[upto]↑2+Ims[upto]↑2;
	    taken[jj]←true;
	  end "ISI";
	  ind←ind+1;
	end "FFCR";
    end "COMBINE";

procedure ArrSqr(real array Arr);
  ⊂ "ArrSqr"
  define ndims = {-1}, nwrds = {0}, arlo = {1}, arhi = {2};
  integer LoBound, HiBound, I;
  if arrinfo(Arr,ndims) = 1
    then
      ⊂
      LoBound ← arrinfo(Arr,arlo);
      HiBound ← arrinfo(Arr,arhi);
      for I ← LoBound step 1 until HiBound do Arr[I] ← Arr[I]↑2;
      ⊃
    else
      outstr("ArrSqr: multiply dimensioned array.  No good.  No change."&↓);
  ⊃ "ArrSqr";

procedure GetArray(real array Arr);
  ⊂ "GetArray"
  ! This routine reads in a file (defaults to .FUN extension), which expects
  exactly one "smoothed seg function" as produced by the FUNC program.  The
  function is then loaded into the array Arr;
  integer I,ArrChan,cnt,brk,eof;
  string FilNam,DevNam;
  while true do
    ⊂
    outstr(".FUN file:  ");
    FilNam ← DEFAULT(inchwl, DevNam, "FUN", "DSK");
    outstr("Reading "&DevNam&":"&Filnam&"."&↓);
    open(ArrChan←getchan,DevNam,0,19,19,cnt,brk,eof);
    if eof then errquit(<"Couldn't OPEN file."&↓>);
    lookup(ArrChan,FilNam,eof);
    if ¬eof then done;
    print("File "&DevNam&":"&FilNam&" not found...try again.",↓);
    release(ArrChan);
    ⊃;
    do until realin(ArrChan)= 520.00;
    for I ← 0 step 1 until NPoints do Arr[I] ← realin(ArrChan);
    release(ArrChan);
  ⊃ "GetArray";

procedure Magnitude(real array Ai,Bi,HMag; integer N);
  ⊂ "Magnitude"
  ! Given the coefficients of a cannonical filter (in Ai and Bi), this
    routine calculates the magnitude frequency response, storing the
    result in HMag.  The array HMag is assumed to be N points long.

    |H[i]| = SQRT((.....)/(......))
  ;

  integer OMEGA,I;
  real num1,num2,den1,den2,angle,cospart,sinpart;
  for omega ← 0 step 1 until N do
    begin
    num1←num2←den1←den2←0;
    for I ← 0 step 1 until M do
      begin
      angle ← -I*omega;
      cospart ← cos(agle);
      sinpart ← sin(angle);
      num1 ← num1 + A[I]*cospart;
      num2 ← num2 + A[I]*sinpart;
      den1 ← den1 + B[I]*cospart;
      den2 ← den2 + B[I]*sinpart;
      end;
    H[omega] ← sqrt((num1↑2 + num2↑2)/(den1↑2 + den2↑2));
    end;
  ⊃ "Magnitude";

! main program here;

String str;
integer NCoeffs, brk;
PRINT("How many filter sections:  ");
str ← inchwl;
NCoeffs ← 2*intscan(str,brk);

⊂ "MAIN"

real array MagFrq[0:NPoints];
real array Zeros[0:NPoints];
real array AutCor[1:2*NPoints];
real array APrams[0:NCoeffs],KPrams[1:NCoeffs],TAPrams[0:NCoeffs];
real array RRoots[1:NCoeffs],IRoots[1:NCoeffs];
real array Ai[0:NCoeffs],Bi[0:NCoeffs];
integer id, NRoots, I;

arrclr(Zeros);
DSETUP(2000,id);

GetArray(MagFrq);
DPYSL(id, MagFrq, NPoints, 2, 2, "Frequency", "Magnitude", 0, 512);
WRITE(id,0);
OUTSTR("<alt> for next"&↓);INCHRW;
BUFCLR(id,2000);

! square the magnitude response;
ArrSqr(MagFrq);
DPYSL(id, MagFrq, NPoints, 2, 2, "Frequency", "Magnitude squared", 0, 512);
WRITE(id,0);
OUTSTR("<alt> for next"&↓);INCHRW;
BUFCLR(id,2000);

! take the inverse FFT of the squared magnitude response (yeilds autocorrelation);
RTRAN(AutCor,MagFrq,Zeros,Log2NPoints,TRUE);
DPYSL(id, AutCor, NPoints, 2, 2, "AutCor", "", 0, 512);
WRITE(id,0);
OUTSTR("<alt> for next"&↓);INCHRW;
BUFCLR(id,2000);

! run a Linear Predictor over it to get the filter coefficients;
AUTSOL(AutCor,APrams,KPrams,NCoeffs);

! factor the filter coefficients into their component roots;
for I ← 0 step 1 until NCoeffs do TAPrams[I] ← APrams[NCoeffs-I]; ! invert order;
NRoots ← POLY(TAPrams,RRoots,IRoots,NCoeffs);
If NRoots = 0
  then errquit(<"Couldn't get the roots (?)."&↓>)
  else outstr("Found "&CVS(NRoots)&" roots:"&↓);

! combine the roots into conjugate pairs;
COMBINE(RRoots,IRoots,Ai,Bi,NRoots);

! output the roots, now suitable for a cascaded second order system;
outstr("i"&tab&"Ai"&"Bi"&↓);
for I ← 1 step 1 until NRoots/2 do outstr(I&TAB&cvf(Ai[I])&TAB&cvf(Bi[I])&↓);

⊃ "MAIN";

end "AWFIL";