C	subroutines mainly from the book by Silvia & Robinson

C	note that the vectors (because of Fortran) go from index 1 (ej 0)
C	cf. the middle of p. 185 in the book





	SUBROUTINE ZERO (LX, X)
C	zero is to store zero in an array
	REAL X(*)
	IF (LX) 30,30,10
10	DO 20 I=1,LX
20	X(I)=0.0
30	RETURN
	END





	SUBROUTINE DOT (L,X,Y, ANS)
C	dot is dot product
	REAL X(*),Y(*)
	ANS=0.0
	IF (L) 30,30,10
10	DO 20 I=1,L
20	ANS=ANS+X(I)*Y(I)
30	RETURN
	END





	SUBROUTINE FOLD (LA,A,LB,B, LC,C)
C	fold is folding (convolution)
C	note: lc and c are output, cf. foldny below
	REAL A(*),B(*),C(*)
	LC=LA+LB-1
	CALL ZERO(LC,C)
	DO 10 I=1,LA
	 DO 10 J=1,LB
	  K=I+J-1
10	C(K)=A(I)*B(J)+C(K)
	RETURN
	END





	SUBROUTINE FOLDNY (LA,A,LB,B,LC, C)
C	fold is folding (convolution)
C	note: only c is output, cf. fold above
	REAL A(*),B(*),C(*)
	CALL ZERO(LC,C)
	DO 10 I=1,LA
	 DO 10 J=1,MIN(LB,LC+1-I)
	  K=I+J-1
10	C(K)=A(I)*B(J)+C(K)
	RETURN
	END





	SUBROUTINE CROSS (LX,X,LY,Y,LC, C)
C	cross is cross product (cross-correlation)
	REAL X(*),Y(*),C(*)
	DO 10 I=1,LC
10	CALL DOT(MIN0(LY+I-1,LX)-I+1,X(I),Y,C(I))
	RETURN
	END





	SUBROUTINE POLYDV (N,DVS,M,DVD,L, Q)
C	perform division of power series of the form
C	(dvd(1)+x*dvd(2)+x*x*dvd(3)+...)/
C	(dvs(1)+x*dvs(2)+x*x*dvs(3)+...)
C	the result is = q(1)+x*q(2)+x*x*q(3)+...
C	n is the number of coefficients in the divisor polynomial
C	m is the number of coefficients in the dividend polynomial
C	l is the number of coefficients in the quotient polynomial
C	dvs is the input divisor polynomial coefficients
C	dvd is the input dividend polynomial coefficients
C	q is the output quotient polynomial coefficients
C	dvs(1) must be nonzero
C	this could be programmed to allow equivalence (dvd,q)
	REAL DVS(*),DVD(*),Q(*)
	NM=N-1
	DO 8 I=1,L
8	Q(I)=0.0
C	move the used portion of dvd to q
	MML=MIN0(M,L)
	DO 10 I=1,MML
10	Q(I)=DVD(I)
	DO 50 I=1,L
	 Q(I)=Q(I)/DVS(1)
	 IF (I-L) 30,20,30
20	 RETURN
30	 K=I
	 ISUB=MIN0(NM,L-I)
	 DO 40 J=1,ISUB
	  K=K+1
	  Q(K)=Q(K)-Q(I)*DVS(J+1)
40	 CONTINUE
50	CONTINUE
C	program never gets here
	RETURN
	END





	SUBROUTINE PEO (LR,R, A)
C	peo is the auxiliary Toeplitz recursion
C	it gives the prediction-error operator a(i), a(1)=1.0
	REAL R(LR),A(LR)
	V=R(1)
	A(1)=1.0
	IF (LR.EQ.1) RETURN
	DO 6 L=2,LR
	 D=0.0
	 L3=L-1
	 DO 1 J=1,L3
	  K=L-J+1
1	 D=D+A(J)*R(K)
	 C=D/V
	 IF (L.EQ.2) GOTO 4
	 L1=(L-2)/2
	 L2=L1+1
	 IF (L2.LT.2) GOTO 3
	 DO 2 J=2,L2
	  HOLD=A(J)
	  K=L-J+1
	  A(J)=A(J)-C*A(K)
2	 A(K)=A(K)-C*HOLD
	 IF (2*L1.EQ.L-2) GOTO 4
3	 LT3=L2+1
	 A(LT3)=A(LT3)-C*A(LT3)
4	 A(L)=-C
6	V=V-C*D
	RETURN
	END





	SUBROUTINE FFT (X,Y, TABLE,M,LL,ISN)
C	fft is in place dft computation using Sande algorithm
C	   and Markel pruning modification
C	x = array of length 2**m used to hold real part of complex input
C	y = array of length 2**m used to hold imaginary part of complex input
C	table = array of length n/4+1 (n=2**m) , contains
C	   quarter-length cosine table
C	m = integer exponent to two which determines size (2**m) of 
C	   fft to be performed  (bit reverse table is set for a
C	   maximum of n=2**16=65536)
C	ll = integer exponent to two which determines the number (2**ll) 
C	   actual data points, number of stages in which no pruning is 
C	   allowable
C	isn :  set to -1 for forward fft (dft)
C	       set to +1 for inverse fft (idft)
C	x = real part of complex output
C	y = imaginary part of complex output
C	
C	observera : vektorerna gaar ju fraan 1 (ej 0) och konventionen med
C	   shift (se oeverst i denna fil) bibehaallen, saa vid dft blir 
C	   & "in-x(1)" vaerde vid tiden 0
C	   & "in-y(1)" vaerde vid tiden 0
C	   & "ut-x(1)" 0-frekvens (dvs dc) komponent
C	   & "ut-y(1)" 0-frekvens (dvs dc) komponent


C	this is exactly what happens to the x,y arrays:

C	for k=1,2,...,2**m
C	  x(out)(k) + i*y(out)(k)   :=   SUM (n=1,2**m)  
C	             (x(in)(n)+i*y(in)(n)) * exp(isn*2*pi*i*(n-1)*(k-1)/2**m)
C	end
C	if (isn.gt.0) then all elements of the x,y arrays are finally
C	                   divided by 2**m


	REAL X(*),Y(*),TABLE(*)
	INTEGER L(16)
	EQUIVALENCE (L16,L(1)),(L15,L(2)),(L14,L(3)),(L13,L(4)),
     $	(L12,L(5)),(L11,L(6)),(L10,L(7)),(L9,L(8)),(L8,L(9)),
     $	(L7,L(10)),(L6,L(11)),(L5,L(12)),(L4,L(13)),(L3,L(14)),
     $	(L2,L(15)),(L1,L(16))
	IF (M.GT.16) THEN
	  WRITE(*,*) ' %%% FFT reverse table set too small'
	  STOP 1616
	END IF
	N=2**M
	ND4=N/4
	ND4P1=ND4+1
	ND4P2=ND4P1+1
	ND2P2=ND4+ND4P2
	LLL=2**LL
	DO 8 LO=1,M
	 LMX=2**(M-LO)
	 LMM=LMX
	 LIX=2*LMX
	 ISCL=N/LIX
C	 test for pruning
	 IF (LO-M+LL) 1,2,2
1	 LMM=LLL
2	 DO 8 LM=1,LMM
	  IARG=(LM-1)*ISCL+1
	  IF (IARG.LE.ND4P1) GOTO 4
	   K1=ND2P2-IARG
	   C=-TABLE(K1)
	   K3=IARG-ND4
	   S=ISN*TABLE(K3)
	   GOTO 6
4	  C=TABLE(IARG)
	   K2=ND4P2-IARG
	   S=ISN*TABLE(K2)
6	  CONTINUE
	  DO 8 LI=LIX,N,LIX
	   J1=LI-LIX+LM
	   J2=J1+LMX
	   T1=X(J1)-X(J2)
	   T2=Y(J1)-Y(J2)
	   X(J1)=X(J1)+X(J2)
	   Y(J1)=Y(J1)+Y(J2)
	   X(J2)=C*T1-S*T2
	   Y(J2)=C*T2+S*T1
8	CONTINUE

C	perform bit reversal

	DO 40 J=1,16
	 L(J)=1
	 IF (J-M) 31,31,40
31	 L(J)=2**(M+1-J)
40	CONTINUE
	JN=1
	DO 60 J1=1,L1
	 DO 60 J2=J1,L2,L1
	  DO 60 J3=J2,L3,L2
	   DO 60 J4=J3,L4,L3
	    DO 60 J5=J4,L5,L4
	     DO 60 J6=J5,L6,L5
	      DO 60 J7=J6,L7,L6
	       DO 60 J8=J7,L8,L7
	        DO 60 J9=J8,L9,L8
	         DO 60 J10=J9,L10,L9
	          DO 60 J11=J10,L11,L10
	           DO 60 J12=J11,L12,L11
	            DO 60 J13=J12,L13,L12
	             DO 60 J14=J13,L14,L13
	              DO 60 J15=J14,L15,L14
	               DO 60 JR=J15,L16,L15
	                IF (JN-JR) 51,51,54
51	                R=X(JN)
	                X(JN)=X(JR)
	                X(JR)=R
	                FI=Y(JN)
	                Y(JN)=Y(JR)
	                Y(JR)=FI
54	                IF (ISN) 53,53,52
52	                X(JR)=X(JR)/FLOAT(N)
	                Y(JR)=Y(JR)/FLOAT(N)
53	                JN=JN+1
60	CONTINUE
	RETURN
	END





	SUBROUTINE COSQT (M, TABLE)
C	cosqt generates quarter-length cosine table
	REAL TABLE(*)
	N=2**M
	ND4P1=N/4+1
	SCL=6.283185307/FLOAT(N)
	DO 10 I=1,ND4P1
	 ARG=FLOAT(I-1)*SCL
10	TABLE(I)=COS(ARG)
	RETURN
	END





	SUBROUTINE CENV (X,Y, TABLE,M)

C	cenv aer rutin foer diskret "complex envelope" utnyttjande fft-
C	   rutinen ovan, jmf Farnbach i BSSA 65:4 (1975) sid. 952

C	x = array of length 2**m used to hold real part of complex input
C	y = array of length 2**m used to hold imaginary part of complex input
C	table = array of length n/4+1 (n=2**m) , contains
C	   quarter-length cosine table
C	m = integer exponent to two which determines size (2**m) of 
C	   cenv to be performed
C	x = real part of complex output
C	y = imaginary part of complex output

C	note: the accuracy may be increased by extending "input x&y" with 
C	zeroes, since the frequency sampling of the DFT will then be 
C	more dense

	REAL X(*),Y(*),TABLE(*)
	CALL FFT(X,Y,TABLE,M,M,-1)
	N=2**M
	ND2=N/2
	ND2P2=ND2+2
	DO K=2,ND2
	 X(K)=2.0*X(K)
	 Y(K)=2.0*Y(K)
	END DO
	DO K=ND2P2,N
	 X(K)=0.0
	 Y(K)=0.0
	END DO
	CALL FFT(X,Y,TABLE,M,M,+1)
	RETURN
	END











	SUBROUTINE CFFT (CXY, TABLE,M,LL,ISN)
C	cfft is in place dft computation using Sande algorithm
C	   and Markel pruning modification
C	   (complex input/output)
C	cxy = array of length 2**m used to hold complex input
C	table = array of length n/4+1 (n=2**m) , contains
C	   quarter-length cosine table
C	m = integer exponent to two which determines size (2**m) of 
C	   cfft to be performed  (bit reverse table is set for a
C	   maximum of n=2**16=65536)
C	ll = integer exponent to two which determines the number (2**ll) 
C	   actual data points, number of stages in which no pruning is 
C	   allowable
C	isn :  set to -1 for forward cfft (dft)
C	       set to +1 for inverse cfft (idft)
C	cxy = complex output
	
C	observera : vektorerna gaar ju fraan 1 (ej 0) och konventionen med
C	   shift (se oeverst i denna fil) bibehaallen, saa vid dft blir 
C	   & "in-cxy(1)" vaerde vid tiden 0
C	   & "ut-cxy(1)" 0-frekvens (dvs dc) komponent

C	this is exactly what happens to the cxy array:

C	for k=1,2,...,2**m
C	  cxy(out)(k) :=   SUM (n=1,2**m)  
C	             cxy(in)(n) * exp(isn*2*pi*i*(n-1)*(k-1)/2**m)
C	end
C	if (isn.gt.0) then all elements of the cxy array are finally
C	                   divided by 2**m


	COMPLEX CXY(*)
	REAL TABLE(*)
	INTEGER L(16)
	COMPLEX CT12,CR
	EQUIVALENCE (L16,L(1)),(L15,L(2)),(L14,L(3)),(L13,L(4)),
     $	(L12,L(5)),(L11,L(6)),(L10,L(7)),(L9,L(8)),(L8,L(9)),
     $	(L7,L(10)),(L6,L(11)),(L5,L(12)),(L4,L(13)),(L3,L(14)),
     $	(L2,L(15)),(L1,L(16))
	IF (M.GT.16) THEN
	  WRITE(*,*) ' %%% CFFT reverse table set too small'
	  STOP 1616
	END IF
	N=2**M
	ND4=N/4
	ND4P1=ND4+1
	ND4P2=ND4P1+1
	ND2P2=ND4+ND4P2
	LLL=2**LL
	DO 8 LO=1,M
	 LMX=2**(M-LO)
	 LMM=LMX
	 LIX=2*LMX
	 ISCL=N/LIX
C	 test for pruning
	 IF (LO-M+LL) 1,2,2
1	 LMM=LLL
2	 DO 8 LM=1,LMM
	  IARG=(LM-1)*ISCL+1
	  IF (IARG.LE.ND4P1) GOTO 4
	   K1=ND2P2-IARG
	   C=-TABLE(K1)
	   K3=IARG-ND4
	   S=ISN*TABLE(K3)
	   GOTO 6
4	  C=TABLE(IARG)
	   K2=ND4P2-IARG
	   S=ISN*TABLE(K2)
6	  CONTINUE
	  DO 8 LI=LIX,N,LIX
	   J1=LI-LIX+LM
	   J2=J1+LMX
	   CT12=CXY(J1)-CXY(J2)
	   CXY(J1)=CXY(J1)+CXY(J2)
	   CXY(J2)=CMPLX(C,S)*CT12
8	CONTINUE

C	perform bit reversal

	DO 40 J=1,16
	 L(J)=1
	 IF (J-M) 31,31,40
31	 L(J)=2**(M+1-J)
40	CONTINUE
	JN=1
	DO 60 J1=1,L1
	 DO 60 J2=J1,L2,L1
	  DO 60 J3=J2,L3,L2
	   DO 60 J4=J3,L4,L3
	    DO 60 J5=J4,L5,L4
	     DO 60 J6=J5,L6,L5
	      DO 60 J7=J6,L7,L6
	       DO 60 J8=J7,L8,L7
	        DO 60 J9=J8,L9,L8
	         DO 60 J10=J9,L10,L9
	          DO 60 J11=J10,L11,L10
	           DO 60 J12=J11,L12,L11
	            DO 60 J13=J12,L13,L12
	             DO 60 J14=J13,L14,L13
	              DO 60 J15=J14,L15,L14
	               DO 60 JR=J15,L16,L15
	                IF (JN-JR) 51,51,54
51	                CR=CXY(JN)
	                CXY(JN)=CXY(JR)
	                CXY(JR)=CR
54	                IF (ISN) 53,53,52
52	                CXY(JR)=CXY(JR)/N
53	                JN=JN+1
60	CONTINUE
	RETURN
	END
