! ! This file is part of SACAMOS, State of the Art CAble MOdels for 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-2018 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 ! ! ! OVERALL DESCRIPTION ! These subroutines perform processes related to the conductor impedance models available ! ! The subroutines operate on the conductor_impedance_model structure defined in cable_module.F90 ! ! Models are: ! ! impedance_model_type_PEC ! impedance_model_type_cylindrical_with_conductivity ! impedance_model_type_filter ! impedance_model_type_cylidrical_shell_with_conductivity ! impedance_model_type_cylindrical_shield ! impedance_model_type_rectangular_with_conductivity ! File Contents: ! SUBROUTINE read_conductor_impedance_model ! SUBROUTINE write_conductor_impedance_model ! SUBROUTINE evaluate_conductor_impedance_model ! SUBROUTINE calculate_Rdc ! SUBROUTINE calculate_internal_impedance ! SUBROUTINE ber_bei ! SUBROUTINE deallocate_conductor_impedance_model ! ! NAME ! read_conductor_impedance_model ! ! AUTHORS ! Chris Smartt ! ! DESCRIPTION ! Read the conductor_impedance_model structure from file ! The impedance model type is read first then the parameters relating to that particular model type ! ! COMMENTS ! ! ! HISTORY ! ! started 12/5/2016 CJS ! 24/8/2016 CJS Include cylindrical shell model ! ! SUBROUTINE read_conductor_impedance_model(conductor_impedance,unit) USE type_specifications IMPLICIT NONE ! variables passed to subroutine type(conductor_impedance_model),intent(OUT) :: conductor_impedance ! impedance model structure to read integer,intent(IN) :: unit ! file unit to read from ! local variables ! START ! reset to default values initially conductor_impedance%radius=0d0 conductor_impedance%conductivity=0d0 conductor_impedance%thickness=0d0 conductor_impedance%width=0d0 conductor_impedance%height=0d0 conductor_impedance%Rdc=0d0 conductor_impedance%Resistance_multiplication_factor=1d0 read(unit,*,ERR=9000)conductor_impedance%impedance_model_type write(*,*)'MODEL TYPE ',conductor_impedance%impedance_model_type if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_PEC) then RETURN ! no additional information required for PEC type else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylindrical_with_conductivity) then read(unit,*,ERR=9000)conductor_impedance%radius read(unit,*,ERR=9000)conductor_impedance%conductivity read(unit,*,ERR=9000)conductor_impedance%Resistance_multiplication_factor else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylidrical_shell_with_conductivity) then read(unit,*,ERR=9000)conductor_impedance%radius read(unit,*,ERR=9000)conductor_impedance%conductivity read(unit,*,ERR=9000)conductor_impedance%Resistance_multiplication_factor read(unit,*,ERR=9000)conductor_impedance%thickness write(*,*)'THICKNESS ',conductor_impedance%thickness else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_filter) then CALL read_Sfilter(conductor_impedance%ZT_filter,unit) else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylindrical_shield) then read(unit,*,ERR=9000)conductor_impedance%radius read(unit,*,ERR=9000)conductor_impedance%conductivity read(unit,*,ERR=9000)conductor_impedance%Resistance_multiplication_factor read(unit,*,ERR=9000)conductor_impedance%thickness CALL read_Sfilter(conductor_impedance%ZT_filter,unit) else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_rectangular_with_conductivity) then read(unit,*,ERR=9000)conductor_impedance%width read(unit,*,ERR=9000)conductor_impedance%height read(unit,*,ERR=9000)conductor_impedance%conductivity read(unit,*,ERR=9000)conductor_impedance%Resistance_multiplication_factor else write(run_status,*)'ERROR in read_conductor_impedance_model: Unknown impedance model type:' & ,conductor_impedance%impedance_model_type CALL write_program_status() STOP 1 end if RETURN 9000 run_status='ERROR in read_conductor_impedance_model' CALL write_program_status() STOP 1 END SUBROUTINE read_conductor_impedance_model ! ! NAME ! write_conductor_impedance_model ! ! AUTHORS ! Chris Smartt ! ! ! DESCRIPTION ! Write the conductor_impedance_model structure from file ! The impedance model type is written first then the parameters relating to that particular model type ! ! COMMENTS ! ! ! HISTORY ! ! started 12/5/2016 CJS ! 24/8/2016 CJS Include cylindrical shell model ! ! SUBROUTINE write_conductor_impedance_model(conductor_impedance,unit) USE type_specifications IMPLICIT NONE ! variables passed to subroutine type(conductor_impedance_model),intent(IN) :: conductor_impedance ! impedance model to write integer,intent(IN) :: unit ! unit to write to ! local variables ! START write(unit,*)conductor_impedance%impedance_model_type,' # Conductor impedance model type' if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_PEC) then RETURN ! no additional information required for PEC type else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylindrical_with_conductivity) then write(unit,*)conductor_impedance%radius,' # conductor radius' write(unit,*)conductor_impedance%conductivity,' # conductivity' write(unit,*)conductor_impedance%Resistance_multiplication_factor,' # Resistance_multiplication_factor' else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylidrical_shell_with_conductivity) then write(unit,*)conductor_impedance%radius,' # conductor radius' write(unit,*)conductor_impedance%conductivity,' # conductivity' write(unit,*)conductor_impedance%Resistance_multiplication_factor,' # Resistance_multiplication_factor' write(unit,*)conductor_impedance%thickness,' # shield thickness' else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_filter) then CALL write_Sfilter(conductor_impedance%ZT_filter,unit) else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylindrical_shield) then write(unit,*)conductor_impedance%radius,' # conductor radius' write(unit,*)conductor_impedance%conductivity,' # conductivity' write(unit,*)conductor_impedance%Resistance_multiplication_factor,' # Resistance_multiplication_factor' write(unit,*)conductor_impedance%thickness,' # shield thickness' CALL write_Sfilter(conductor_impedance%ZT_filter,unit) else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_rectangular_with_conductivity) then write(unit,*)conductor_impedance%width,' # conductor width' write(unit,*)conductor_impedance%height,' # conductor height' write(unit,*)conductor_impedance%conductivity,' # conductivity' write(unit,*)conductor_impedance%Resistance_multiplication_factor,' # Resistance_multiplication_factor' end if RETURN END SUBROUTINE write_conductor_impedance_model ! ! NAME ! evaluate_conductor_impedance_model ! ! AUTHORS ! Chris Smartt ! ! DESCRIPTION ! Given the parameters of a conductor impedance model and a frequency ! evaluate: complex surface impedance, d.c. surface impedance ! : complex transfer imedance, d.c. transfer impedance ! as required. ! ! COMMENTS ! ! ! HISTORY ! ! started 12/5/2016 CJS ! 24/8/2016 CJS Include cylindrical shield model ! 24/8/2016 CJS Include self (condcutor) and transfer impedances in the calculation ! ! SUBROUTINE evaluate_conductor_impedance_model(conductor_impedance,f,Z_c,Rdc_c,Z_t,Rdc_t) USE type_specifications USE constants IMPLICIT NONE ! variables passed to subroutine type(conductor_impedance_model),intent(IN) :: conductor_impedance ! impedance model real(dp),intent(IN) :: f ! frequency complex(dp),intent(OUT) :: Z_c ! Complex conductor surface impedance value to be returned real(dp),intent(OUT) :: Rdc_c ! d.c. conductor resistance to be returned complex(dp),intent(OUT) :: Z_t ! Complex transfer impedance value to be returned real(dp),intent(OUT) :: Rdc_t ! d.c. transfer resistance to be returned ! local variables real(dp) :: sigma,rw,rs,t,w real(dp) :: den real(dp) :: f0 ! START if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_PEC) then Z_c=(0d0,0d0) Rdc_c=0d0 Z_t=(0d0,0d0) Rdc_t=0d0 else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylindrical_with_conductivity) then sigma=conductor_impedance%conductivity rw=conductor_impedance%radius CALL calculate_internal_impedance(sigma,rw,f,Z_c,Rdc_c) Z_t=(0d0,0d0) Rdc_t=0d0 else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylidrical_shell_with_conductivity) then sigma=conductor_impedance%conductivity rs=conductor_impedance%radius t=conductor_impedance%thickness CALL calculate_internal_impedance_shell(sigma,rs,t,f,Z_c,Rdc_c) ! set the transfer impedance to be zero Z_t=(0d0,0d0) Rdc_t=0d0 else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_filter) then ! transfer impedance calculation Z_t=evaluate_Sfilter_frequency_response(conductor_impedance%ZT_filter,f) Rdc_t=conductor_impedance%ZT_filter%a%coeff(0)/conductor_impedance%ZT_filter%b%coeff(0) ! Set the conductor impedance to be equal to the transfer impedance. This model is no longer used and may be removed Z_c=Z_t Rdc_c=Rdc_t else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_cylindrical_shield) then ! transfer impedance calculation Z_t=evaluate_Sfilter_frequency_response(conductor_impedance%ZT_filter,f) Rdc_t=conductor_impedance%ZT_filter%a%coeff(0)/conductor_impedance%ZT_filter%b%coeff(0) ! conductor impedance calculation sigma=conductor_impedance%conductivity rs=conductor_impedance%radius t=conductor_impedance%thickness CALL calculate_internal_impedance_shell(sigma,rs,t,f,Z_c,Rdc_c) else if (conductor_impedance%impedance_model_type.EQ.impedance_model_type_rectangular_with_conductivity) then ! The rectangular conductor model assumes Z(jw)=(1+sqrt(f/f0)(1+j)) See C.R. Paul, ! "Analysis of Multiconductor Transmission Lines" 1st Edition, p 175-177 and p 320-323. Z_t=(0d0,0d0) Rdc_t=0d0 sigma=conductor_impedance%conductivity w=conductor_impedance%width t=conductor_impedance%height CALL calculate_internal_impedance_rectangular(sigma,w,t,f,Z_c,Rdc_c) end if RETURN END SUBROUTINE evaluate_conductor_impedance_model ! ! NAME ! calculate_Rdc ! ! DESCRIPTION ! Calculate the d.c.resistance of a cylindrical conductor given the ! conductivity and radius ! If the conductivity is set to zero then return zero internal impedance i.e. for infinite conductivity ! ! COMMENTS ! ! ! HISTORY ! ! started 27/04/2016 CJS based on phase 1 work in 2015 ! ! SUBROUTINE calculate_Rdc(sigma,r,Rdc) USE type_specifications USE constants IMPLICIT NONE ! variables passed to subroutine real(dp),intent(IN) :: sigma ! conductivity real(dp),intent(IN) :: r ! shell radius real(dp),intent(OUT) :: Rdc ! d.c. resistance ! START if ((r.EQ.0d0).OR.(sigma.eq.0d0)) then ! zero parameters - indicates a perfect conductor so return zero d.c. resistance Rdc=0d0 RETURN end if ! Evaluate the d.c. resistance Rdc=1d0/(sigma*pi*(r**2)) ! #EQN_REFERENCE_REQUIRED RETURN END SUBROUTINE calculate_Rdc ! ! NAME ! calculate_internal_impedance ! ! DESCRIPTION ! Calculate the internal impedance of a cylindrical conductor given the ! conductivity, radius and frequency ! This software uses an exact formula using Kelvin functions if the ! radius if the wire is less than a specified number of skin depths (10), otherwise we use ! an approximate formula. This is due to convergence problems when rw >> delta ! If the conductivity is set to zero then return zero internal impedance i.e. for infinite conductivity ! ! COMMENTS ! The equation references are from the theory manual ! but more detail is found in C. R. Paul,"Analysis of Multiconductor Transmission Lines" 1st edition ! and S.A.Schelkunoff, 'The Electromagnetic Theory of Coaxial Transmission Lines and Cylindrical Shields', ! Bell System Technical Journal,Vol 13, No 4, pp 532-579, 1934. ! ! HISTORY ! ! started 27/04/2016 CJS based on phase 1 work in 2015 ! 8/5/2017 CJS: Include references to Theory_Manual ! ! SUBROUTINE calculate_internal_impedance(sigma,r,f,Zint,Rdc) USE type_specifications USE constants IMPLICIT NONE ! variables passed to subroutine real(dp),intent(IN) :: sigma ! conductivity real(dp),intent(IN) :: r ! shell radius real(dp),intent(IN) :: f ! frequency complex(dp),intent(OUT) :: Zint ! Condcutor impedance real(dp),intent(OUT) :: Rdc ! d.c. resistance ! local variables real(dp) :: q,delta ! Kelvin function variables real(dp) ber,bei,dber,dbei ! START if (sigma.eq.0d0) then ! zero conductivity - indicates a perfect conductor so return zero internal impedance zint=(0d0,0d0) Rdc=0d0 RETURN end if ! special case for f=0. In this case return the d.c. resistance in both Rdc and zint if (f.eq.0d0) then CALL calculate_Rdc(sigma,r,Rdc) zint=Rdc RETURN end if ! skin depth delta=1d0/(sqrt(pi*f*mu0*sigma)) ! Theory_Manual_Eqn 3.63 if (r.LT.10d0*delta) then ! use the Kelvin function form ! Q parameter equation 3.196b ! Theory_Manual_Eqn 3.64 q=sqrt(2d0)*r/delta CALL ber_bei(q,ber,bei,dber,dbei) ! Evaluate the impedance, equation 3.196a ! Theory_Manual_Eqn 3.62 zint=(1d0/(sqrt(2d0)*pi*r*sigma*delta))*(ber+j*bei)/(dbei-j*dber) else ! Evaluate the impedance, equation 3.202b ! C. R. Paul, Equation 3.202b zint=(1d0/(2d0*r))*sqrt(mu0/(pi*sigma))*sqrt(f)+j*2d0*pi*f*(1d0/(4d0*pi*r))*sqrt(mu0/(pi*sigma))/sqrt(f) end if ! r greater than 10 skin depths ! Evaluate the d.c. resistance CALL calculate_Rdc(sigma,r,Rdc) RETURN END SUBROUTINE calculate_internal_impedance ! ! NAME ! calculate_internal_impedance_shell ! ! DESCRIPTION ! Calculate the internal impedance of a cylindrical shell conductor given the ! conductivity, radius, thickness and frequency ! ! COMMENTS ! The calculation is based on the Zaa calculation in equation 82 of: ! S. A. Schelkunoff, "The Electroomagnetic Theory of Coaxial Transmission ! Lines and Cylindrical Shields" Bell Sys Tech J, vol 13, pp 532-579, Oct 1934. ! ! HISTORY ! ! started 24/08/2016 CJS ! 8/5/2017 CJS: Include references to Theory_Manual ! ! SUBROUTINE calculate_internal_impedance_shell(sigma,r,t,f,Zint,Rdc) USE type_specifications USE constants IMPLICIT NONE ! variables passed to subroutine real(dp),intent(IN) :: sigma ! conductivity real(dp),intent(IN) :: r ! shell radius real(dp),intent(IN) :: t ! shell thickness real(dp),intent(IN) :: f ! frequency complex(dp),intent(OUT) :: Zint ! Condcutor impedance real(dp),intent(OUT) :: Rdc ! d.c. resistance ! local variables real(dp) :: delta ! skin depth complex(dp) :: gamma ! complex propagation constant in conductor complex(dp) :: sinh_gt complex(dp) :: cosh_gt ! START if (sigma.eq.0d0) then ! zero conductivity - indicates a perfect conductor so return zero internal impedance zint=(0d0,0d0) Rdc=0d0 RETURN end if Rdc=1d0/(2d0*pi*r*t*sigma) ! Theory_Manual_Eqn 3.65 if (f.NE.0d0) then ! skin depth calculation delta=1d0/(sqrt(pi*f*mu0*sigma)) ! skin depth in conductor Theory_Manual_Eqn 3.63 gamma=cmplx(1d0,1d0)/cmplx(delta) ! complex propagation constant in shield Theory_Manual_Eqn 3.66 sinh_gt=(exp(gamma*t)-exp(-gamma*t))/(2d0,0d0) cosh_gt=(exp(gamma*t)+exp(-gamma*t))/(2d0,0d0) ! Theory_Manual_Eqn 3.67 zint=Rdc*gamma*t*cosh_gt/sinh_gt else ! at zero frequency Zint=Rdc Zint=Rdc end if RETURN END SUBROUTINE calculate_internal_impedance_shell ! ! NAME ! calculate_internal_impedance_rectangular ! ! DESCRIPTION ! Calculate the internal impedance of a rectangular conductor given the ! conductivity, width, thickness and frequency ! The equation references are from the theory manual ! but more detail is found in C. R. Paul,"Analysis of Multiconductor Transmission Lines" 1st edition ! ! COMMENTS ! ! ! HISTORY ! ! started 10/10/2016 CJS ! 8/5/2017 CJS: Include references to Theory_Manual ! ! SUBROUTINE calculate_internal_impedance_rectangular(sigma,w,t,f,Zint,Rdc) USE type_specifications USE constants IMPLICIT NONE ! variables passed to subroutine real(dp),intent(IN) :: sigma ! conductivity real(dp),intent(IN) :: w ! conductor width real(dp),intent(IN) :: t ! conductor thickness real(dp),intent(IN) :: f ! frequency complex(dp),intent(OUT) :: Zint ! Condcutor impedance real(dp),intent(OUT) :: Rdc ! d.c. resistance ! local variables ! START if (sigma.eq.0d0) then ! zero conductivity - indicates a perfect conductor so return zero internal impedance Zint=(0d0,0d0) Rdc=0d0 RETURN end if Rdc=1d0/(w*t*sigma) ! Theory_Manual_Eqn 3.69 if (f.NE.0d0) then Zint=Rdc+(0.5d0/(w+t))*sqrt(mu0/sigma)*sqrt(j*2d0*pi*f) ! Theory_Manual_Eqn 3.68 with 3.70 else ! at zero frequency Zint=Rdc Zint=Rdc end if RETURN END SUBROUTINE calculate_internal_impedance_rectangular ! ! NAME ! ber_bei ! ! DESCRIPTION ! Calculate Kelvin functions and their derivatives ! using a series expansion method ! ! COMMENTS ! may not be the most efficient way to do this... ! ! HISTORY ! ! started 27/04/2016 CJS based on phase 1 work in 2015 ! ! SUBROUTINE ber_bei(x,ber,bei,dber,dbei) ! calculate Kelvin functions and derivatives ! See Abramowitz and Stegun, "Handbook of Mathematical Functions" equation 9.9.10 USE type_specifications USE constants IMPLICIT NONE ! variables passed to subroutine real(dp),intent(IN) :: x ! input argument real(dp),intent(OUT) :: ber,bei,dber,dbei ! output kelvin fuction and derivative values ! local variables real(dp) :: arg,sign,fac,term,last_term,p integer :: k real(dp),parameter :: cvg_test=1d-12 integer,parameter :: kmax=1000 ! START arg=x*x/4d0 ber=1d0 dber=0d0 last_term=ber sign=-1d0 do k=2,kmax,2 fac=dble(k*(k-1)) term=last_term*sign*(arg/fac)*(arg/fac) ber=ber+term p=dble(k)*2d0 dber=dber+term*p/x if (abs(term).LT.cvg_test) GOTO 100 last_term=term end do 100 CONTINUE bei=arg last_term=bei dbei=x/2d0 sign=-1d0 do k=3,kmax,2 fac=dble(k*(k-1)) term=last_term*sign*(arg/fac)*(arg/fac) bei=bei+term p=dble(k)*2d0 dbei=dbei+term*p/x if (abs(term).LT.cvg_test) GOTO 200 last_term=term end do 200 CONTINUE RETURN END SUBROUTINE ber_bei ! ! NAME ! deallocate_conductor_impedance_model ! ! AUTHORS ! Chris Smartt ! ! DESCRIPTION ! deallocate filters required for comnductor impedance models ! ! COMMENTS ! ! ! HISTORY ! ! started 12/5/2016 CJS ! ! SUBROUTINE deallocate_conductor_impedance_model(conductor_impedance) USE type_specifications IMPLICIT NONE ! variables passed to subroutine type(conductor_impedance_model),intent(INOUT) :: conductor_impedance ! local variables ! START CALL deallocate_Sfilter(conductor_impedance%ZT_filter) END SUBROUTINE deallocate_conductor_impedance_model