! ! This file is part of SACAMOS, State of the Art CAble MOdels in Spice. ! It was developed by the University of Nottingham and the Netherlands Aerospace ! Centre (NLR) for ESA under contract number 4000112765/14/NL/HK. ! ! Copyright (C) 2016-2017 University of Nottingham ! ! SACAMOS is free software: you can redistribute it and/or modify it under the ! terms of the GNU General Public License as published by the Free Software ! Foundation, either version 3 of the License, or (at your option) any later ! version. ! ! SACAMOS is distributed in the hope that it will be useful, but ! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ! for more details. ! ! A copy of the GNU General Public License version 3 can be found in the ! file GNU_GPL_v3 in the root or at . ! ! SACAMOS uses the EISPACK library (in /SRC/EISPACK). EISPACK is subject to ! the GNU Lesser General Public License. A copy of the GNU Lesser General Public ! License version can be found in the file GNU_LGPL in the root of EISPACK ! (/SRC/EISPACK ) or at . ! ! The University of Nottingham can be contacted at: ggiemr@nottingham.ac.uk ! ! File Contents: ! SUBROUTINE calculate_min_resistance_function(H,R,w0) ! SUBROUTINE calculate_min_resistance_value(H,R,w0) ! ! NAME ! calculate_min_resistance_value ! ! DESCRIPTION ! This subroutine calculates the minimum resistance of a rational transfer function ! and the angular frequency at which it occurs ! See F. F. Kuo, "Network Analysis and Synthesis" section 10.3 ! ! The algorithm first obtains an expression for the real part of the rational function as ! a function of frequency. This is then differentiated and the minima calculated. ! The lowest minimum, or the resistance as f-> infinty if is smaller is then the minimum resistance ! ! SEE ALSO ! ! ! HISTORY ! ! started 05/10/2017 CJS ! SUBROUTINE calculate_min_resistance_value(H,R,w0) USE type_specifications USE general_module USE constants USE frequency_spec USE filter_module USE Sfilter_fit_module IMPLICIT NONE ! variables passed to subroutine type(Sfilter),intent(INOUT) :: H ! Input Rational transfer function real(dp),intent(OUT) :: R ! Output Minimum resistance (real part of the transfer function) real(dp),intent(OUT) :: w0 ! Output Angular frequency at which the minimum occurs ! local variables type(Sfilter) :: Hnew type(polynomial) :: m1,m2,n1,n2,t1,t2,A2,A,Ap,B,B2,Bp,Q integer :: i,ii,order,m_order,n_order,a_order integer :: poly_order complex(dp),allocatable :: roots(:) complex(dp),allocatable :: rroots(:) complex(dp),allocatable :: croots(:) integer :: nreal integer :: ncomplex integer :: root real(dp) :: min_R,min_w0,w,f,R_w logical :: pole_at_zero logical :: local_verbose !START ! local_verbose=.TRUE. local_verbose=.FALSE. if (local_verbose) then write(*,*)'CALLED calculate_min_resistance_value' write(*,*)'Input filter function:' CALL write_Sfilter(H,0) end if if (abs(H%b%coeff(0)).LT.zero_test_small) then pole_at_zero=.TRUE. else pole_at_zero=.FALSE. end if ! assemble the odd and even polynomials m1 and n1 from the numerator of H order=H%a%order if (mod(order,2).EQ.0) then m_order=order n_order=max(order-1,0) else m_order=max(order-1,0) n_order=order end if m1=allocate_polynomial(m_order) n1=allocate_polynomial(n_order) m1%coeff(:)=0d0 do i=0,m_order,2 m1%coeff(i)=H%a%coeff(i) end do n1%coeff(:)=0d0 do i=1,n_order,2 n1%coeff(i)=H%a%coeff(i) end do if (local_verbose) then write(*,*)'Numerator:' CALL write_poly_local3(H%a) write(*,*)'m1: even order terms' CALL write_poly_local3(m1) write(*,*)'n1: odd order terms' CALL write_poly_local3(n1) end if ! assemble the odd and even polynomials m2 and n2 from the denominator of H order=H%b%order if (mod(order,2).EQ.0) then m_order=order n_order=max(order-1,0) else m_order=max(order-1,0) n_order=order end if m2=allocate_polynomial(m_order) n2=allocate_polynomial(n_order) m2%coeff(:)=0d0 do i=0,m_order,2 m2%coeff(i)=H%b%coeff(i) end do n2%coeff(:)=0d0 do i=1,n_order,2 n2%coeff(i)=H%b%coeff(i) end do if (local_verbose) then write(*,*)'Denominator:' CALL write_poly_local3(H%b) write(*,*)'m2: even order terms' CALL write_poly_local3(m2) write(*,*)'n2: odd order terms' CALL write_poly_local3(n2) end if ! Calculate the polynomial A2(jw)=m1(jw)m2(jw)-n1(jw)n2(jw) t1=m1*m2 t2=n1*n2 A2=t1-t2 CALL get_min_order_poly(A2) if (local_verbose) then write(*,*)'A2(jw)=m1m2-n1n2' CALL write_poly_local3(A2) end if ! Calculate the coefficients of A(w) order=A2%order if (mod(order,2).EQ.0) then a_order=order else write(*,*)'Error in calculate_min_resistance_function. Order of A2(jw) is not an even number' end if A=allocate_polynomial(a_order) do i=0,a_order A%coeff(i)=A2%coeff(i) end do ! At the moment A is a function of (jw) not w with zero odd order coefficients ! We get the function of w by making the jw**2n order coefficients negative do i=2,a_order,4 A%coeff(i)=-A%coeff(i) end do CALL get_min_order_poly(A) if (local_verbose) then write(*,*)'A(w)=' CALL write_poly_local3(A) end if ! Calculate the polynomial B2(jw)=m2(jw)m2(jw)-n2(jw)n2(jw) t1=m2*m2 t2=n2*n2 B2=t1-t2 CALL get_min_order_poly(B2) if (local_verbose) then write(*,*)'B2(jw)=m1m2-n1n2' CALL write_poly_local3(B2) end if ! Calculate the coefficients of B(w) order=B2%order if (mod(order,2).EQ.0) then a_order=order else write(*,*)'Error in calculate_min_resistance_function. Order of B2(jw) is not an even number' end if B=allocate_polynomial(a_order) do i=0,a_order B%coeff(i)=B2%coeff(i) end do ! Bt the moment B is a function of (jw) not w with zero odd order coefficients ! We get the function of w by making the jw**2n order coefficients negative do i=2,a_order,4 B%coeff(i)=-B%coeff(i) end do CALL get_min_order_poly(B) if (local_verbose) then write(*,*)'B(w)=' CALL write_poly_local3(B) end if ! Calculate the derivative of A(w)/B(w) wrt w order=max(0,A%order-1) Ap=allocate_polynomial(order) if (A%order.GT.0) then do i=0,Ap%order Ap%coeff(i)=A%coeff(i+1)*dble(i+1) end do end if if (local_verbose) then write(*,*)"Deivative function A'(w)=" CALL write_poly_local3(Ap) end if order=max(0,B%order-1) Bp=allocate_polynomial(order) if (B%order.GT.0) then do i=0,Bp%order Bp%coeff(i)=B%coeff(i+1)*dble(i+1) end do end if if (local_verbose) then write(*,*)"Deivative function B'(w)=" CALL write_poly_local3(Bp) end if ! Calculate the zeros of the derivative function d/dw(A(w)/B(w))= t1=Ap*B t2=A*Bp Q=t1-t2 if (local_verbose) then write(*,*)"we require Q(w)=0 where Q=" CALL write_poly_local3(Q) end if CALL get_min_order_poly(Q) if (local_verbose) then write(*,*)"we require Q(w)=0 where Q=" CALL write_poly_local3(Q) end if poly_order=Q%order ALLOCATE( roots(1:poly_order) ) CALL findroots(Q,roots,poly_order) if (local_verbose) then write(*,*)'Roots of the derivative function are' do root=1,poly_order write(*,*)roots(root) end do end if ALLOCATE( rroots(1:poly_order) ) ALLOCATE( croots(1:poly_order) ) CALL rootsort(poly_order,roots,rroots, & croots,nreal,ncomplex,poly_order) if (local_verbose) write(*,*)'Getting the high frequency resistance' write(*,*)'Getting the high frequency resistance of H:' CALL write_Sfilter(H,0) write(*,*)'aorder=',H%a%order write(*,*)'border=',H%b%order min_w0=1D30 min_R=evaluate_Sfilter_high_frequency_limit(H) if (local_verbose) write(*,*)'High frequency resistance=',min_R if (local_verbose) write(*,*)'Checking real roots: number of roots=',nreal,poly_order do root=1,nreal w=-dble(rroots(root)) f=w*H%wnorm/(2d0*pi) if ((pole_at_zero).AND.(abs(f).LT.zero_test_small)) then ! perturb the frequency slightly away from the pole at zero write(*,*)'Special case, f=',f write(*,*)'(pole_at_zero).AND.(abs(f).LT.zero_test_small),zero_test_small=',zero_test_small f=f+zero_test_small write(*,*)'new f=',f end if R_w=evaluate_Sfilter_frequency_response(H,f) if (local_verbose) then write(*,*)'root',rroots(root),'w=',w,' R=',R_w end if if (R_w.EQ.min_R) then ! if we have roots at + and - p, choose the one with positive frequency min_R=R_w min_w0=max(w,min_w0) else if (R_w.LT.min_R) then min_R=R_w min_w0=w end if end do R=min_R w0=min_w0 if (local_verbose) then write(*,*)'FINISHED calculate_min_resistance_value' write(*,*) write(*,*)'R0=',R write(*,*)'w0=',w0 write(*,*) end if ! finish up DEALLOCATE( roots ) DEALLOCATE( rroots ) DEALLOCATE( croots ) RETURN END SUBROUTINE calculate_min_resistance_value ! ! NAME ! calculate_min_resistance_function ! ! DESCRIPTION ! This subroutine calculates the minimum resistance value of a PR function ! and then subtracts it from the input function to give a function ! whose minimum resistance is zero. This is required in the Brune Synthesis. ! ! SEE ALSO ! ! ! HISTORY ! ! started 04/03/09 CJS ! SUBROUTINE calculate_min_resistance_function(H,R,w0) USE type_specifications USE general_module USE constants USE frequency_spec USE filter_module USE Sfilter_fit_module IMPLICIT NONE ! variables passed to subroutine type(Sfilter),intent(INOUT) :: H ! Input/ Output Rational transfer function real(dp),intent(OUT) :: R ! Output Minimum resistance (real part of the transfer function) real(dp),intent(OUT) :: w0 ! Output Angular frequency at which the minimum occurs ! local variables type(Sfilter) :: Hnew type(polynomial) :: t1,t2 real(dp) :: min_R,min_w0,w,f,R_w logical ::local_verbose !START local_verbose=.TRUE. if (local_verbose) then write(*,*)'CALLED calculate_min_resistance_function' write(*,*)'Input filter function:' CALL write_Sfilter(H,0) end if CALL calculate_min_resistance_value(H,min_R,min_w0) ! Deal with the numerics around small values of min_R if (min_R.LT.-zero_test_small) then write(*,*)'calculate_min_resistance_function called with non positive real function' STOP else if (abs(min_R).LT.zero_test_small) then min_R=0d0 end if if (local_verbose) then write(*,*)'Minimum R=',min_R,' at w=',min_w0 end if ! now subtract R_min from the input function H(jw) Hnew=H t1=H%a t2=H%b t2%coeff(:)=t2%coeff(:)*min_R Hnew%a=t1-t2 CALL get_min_order_poly(Hnew%a) H=Hnew R=min_R w0=min_w0 if (local_verbose) then write(*,*)'FINISHED calculate_min_resistance_function' write(*,*)'Output filter function:' CALL write_Sfilter(H,0) write(*,*) end if RETURN END SUBROUTINE calculate_min_resistance_function