├── DielectricMaterial.py ├── PEC.png ├── TestCase.py ├── bessel.py ├── bessel_arbitrary_precision.py ├── data_output ├── _about.txt ├── bistatic_lossy_dielectric_example.txt ├── bistatic_perfect_dielectric_example.txt ├── lossy_dielectric.txt ├── perfect_dielectric.txt └── sigma1e3_eaefie_bRCS_f_1000000000_Hz.txt ├── figures ├── PEC.png ├── PEC_ratio.png ├── _about.txt ├── bistatic_lossy_dielectric_example.png ├── compare_bistatic_frequencies.png ├── compare_bistatic_frequencies_2.png ├── compare_bistatic_frequencies_3.png ├── compare_bistatic_materials.png ├── coord_system.png ├── example_2_material_comparison.png ├── figure2.png ├── figure3.png ├── lossy_dielectric.png ├── lossy_dielectric_mono_rcs.png ├── perfect_dielectric.png ├── plot_from_file_example.png ├── plot_from_file_example_2.png ├── sigma_sweep.png ├── sigma_sweep_kzhu_nmax.png └── validation_with_mom.png ├── getDielectricSphereFieldUnderPlaneWave.py ├── getNMax.py ├── getRCS.py ├── license.txt ├── misc └── MATLAB_Sphere_scattering_license.txt ├── output └── about.txt ├── paper.bib ├── paper.md ├── readme.md ├── src.py └── test_script.py /DielectricMaterial.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class DielectricMaterial: 4 | ''' Translation of KZHU Dielectric material Class 5 | G. Kevin Zhu (2021). Sphere scattering MATLAB Central File Exchange 6 | (https://www.mathworks.com/matlabcentral/fileexchange/31119-sphere-scattering) 7 | ''' 8 | 9 | 10 | def __init__(self, epsilon_r, sigma_e, mu_r=1, sigma_m=0, name=""): 11 | ''' 12 | epsilon_r: dielectric permittivity of material in steady state 13 | sigma_e: electronic conductivity of material 14 | mu_r: relative magnetic permeability in steady state 15 | (assumed to be 1) 16 | sigma_m: magnetic conductivity? 17 | (assumed to be 0) 18 | ''' 19 | self.epsilon_r = epsilon_r 20 | self.sigma_e = sigma_e 21 | self.mu_r = mu_r 22 | self.sigma_m = sigma_m 23 | self.eps_0 = 8.8541878176e-12 24 | self.mu_0 =4*np.pi*(1e-7) 25 | self.c_0 =2.997924580003452e+08 26 | self.name = name 27 | 28 | if self.getComplexRefractiveIndex(1) == 1: 29 | self.name = "vacuum" 30 | 31 | if (self.epsilon_r > 1e5 and self.mu_r < 1e-5 and \ 32 | self.epsilon_r * self.mu_r == 1): 33 | self.name = "PEC" 34 | 35 | 36 | def convertToAbsoptionDepth(self, distance, frequency): 37 | z = self.getAbsorptionDepth(frequency) 38 | z = distance/z 39 | return z 40 | 41 | def convertToLength(self, f, x): 42 | ''' 43 | f frequency, type np.array 44 | x length (skin depth) 45 | ''' 46 | z = x*self.getAbsorptionDepth(f) 47 | return z 48 | 49 | def getAbsorptionDepth(self, frequency): 50 | ''' 51 | x = getAbsorptionDepth(this, frequency) calculates the absorption 52 | depth from the wave number. The absorption depth is always 53 | positive regardless the choice of the time-harmonic factor. 54 | f frequency, type np.array 55 | ''' 56 | k = self.getWaveNumber(frequency) 57 | x = abs(np.real(1j*k)) 58 | return x 59 | 60 | def getComplexPermeability(self, frequency): 61 | ''' computes the relative complex permeability. 62 | Input: 63 | frequency Nx1 vector (Hz) type np.array 64 | 65 | Note: will fail for frequency = 0 66 | ''' 67 | mu_r = self.mu_r + self.sigma_m / (1j*2*np.pi*frequency * self.mu_0) 68 | return mu_r 69 | 70 | def getComplexPermittivity(self, frequency): 71 | ''' computes the relative complex permittivity. 72 | Input: 73 | frequency Nx1 vector (Hz) type np.array 74 | 75 | Note: will fail for frequency = 0 76 | ''' 77 | epsilon_r = self.epsilon_r + self.sigma_e / (1j*2*np.pi*frequency * self.eps_0) 78 | return epsilon_r 79 | 80 | def getComplexRefractiveIndex(self, frequency): 81 | eps_r = self.getComplexPermittivity(frequency) 82 | mu_r = self.getComplexPermeability(frequency) 83 | ref_idx = np.sqrt(eps_r*mu_r) 84 | return ref_idx 85 | 86 | def getGroupVelocity(self, frequency): 87 | ''' 88 | v_g = getGroupVelocity(this, frequency) evalutes the group velocity 89 | by numerically differentiating the angular frequency with respect to 90 | the wave number. 91 | ''' 92 | pass 93 | 94 | def getIntrinsicImpedance(self, frequency): 95 | 96 | eta_0 = np.sqrt(self.mu_0 / self.eps_0) 97 | eta = eta_0 * \ 98 | np.sqrt( self.getComplexPermeability(frequency) / self.getComplexPermittivity(frequency) ) 99 | return eta 100 | 101 | def getPermeability(self): 102 | ''' returns the object's magnetic permeability 103 | ''' 104 | return (self.mu_r, self.sigma_m) 105 | 106 | def getPermeability(self): 107 | ''' returns the object's dielectric permittivity 108 | ''' 109 | return (self.epsilon_r, self.sigma_e) 110 | 111 | 112 | def getPhaseVelocity(self, frequency): 113 | omega = 2*np.pi*frequency; 114 | k = self.getWaveNumber(frequency) 115 | v_p = omega/np.real(k); 116 | return v_p 117 | 118 | def getWavelength(self, frequency): 119 | k = self.getWaveNumber(frequency); 120 | wavelength = 2*np.pi/np.real(k); 121 | return wavelength 122 | 123 | def getWaveNumber(self, frequency): 124 | ''' 125 | f frequency, type np.array 126 | ''' 127 | permittivity = self.getComplexPermittivity( frequency); 128 | permeability = self.getComplexPermeability( frequency); 129 | k = 2*np.pi*(frequency/self.c_0)*np.sqrt((permittivity*permeability)); 130 | return k 131 | 132 | def getSkinDepth(self, frequency): 133 | omega = 2*np.pi*frequency; 134 | epsilon = self.epsilon_r * self.eps_0 135 | sigma = self.sigma_e 136 | mu = self.mu_r * self.mu_0 137 | 138 | skin_depth = np.sqrt( (2/(sigma*mu)) / omega) * \ 139 | np.sqrt( np.sqrt( 1 + ( (epsilon/sigma)*omega )^2 ) + (epsilon/sigma)*omega ) 140 | return skin_depth 141 | -------------------------------------------------------------------------------- /PEC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/PEC.png -------------------------------------------------------------------------------- /TestCase.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from DielectricMaterial import * 3 | from src import * 4 | 5 | class TestCase: 6 | ''' 7 | ''' 8 | 9 | def __init__(self, radius, sphere_material, background_material): 10 | self.radius = radius 11 | self.sphere_material = sphere_material 12 | self.background_material = background_material 13 | 14 | class TestParameters: 15 | ''' 16 | ''' 17 | 18 | def __init__(self, sensor_location, frequency): 19 | self.sensor_location = sensor_location 20 | self.frequency = frequency 21 | 22 | -------------------------------------------------------------------------------- /bessel.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.special as ss 3 | import mpmath as mp 4 | 5 | def ric_besselj(nu,x,scale = 1): 6 | ''' 7 | Implementation of riccatti bessel function 8 | Inputs: 9 | nu: column vector of integers from 1 to N inclusive 10 | x: rpw vector of M complex-valued arguments, M = len(frequency) 11 | scale: equals 1 by default, scales the output of bessel function 12 | by e**(-abs(imag(x))). if zero, does not scale. (not recommended) 13 | Output: 14 | sqrt(pi*x/2)* J(nu+1/2, x) 15 | returned as an N by M array for each N values of nu and each M values of x 16 | Notes: 17 | scale factors will cancel out in the end, and minimize numerical issues due to 18 | arguments with very large complex arguments. 19 | ''' 20 | M = max(np.shape(x)) 21 | N = max(np.shape(nu)) 22 | x = np.reshape(np.array(x), (1, M)) 23 | nu = np.reshape(np.array(nu), (N,1)) 24 | a = np.zeros((N, M), np.complex128) 25 | 26 | 27 | if (scale == 1): 28 | for i in range(0, N): 29 | a[i,:] = np.sqrt(np.pi*x/2) * ss.jve(nu[i]+0.5, x) 30 | elif (scale == 0): 31 | for i in range(0, N): 32 | a[i,:] = np.sqrt(np.pi*x/2) * ss.jv(nu[i]+0.5, x) 33 | else: 34 | print('incorrect input to ric_besselj') 35 | 36 | ''' 37 | for i in range(0, len(nu)): 38 | for j in range(0, len(x)): 39 | y = np.sqrt(np.pi * x[j] / 2) * mp.besselj(nu[i]+0.5, x[j]) * np.e**(-1*abs(np.imag(x[j]))) 40 | a[i,j] = complex(y.real, y.imag) 41 | ''' 42 | return a 43 | 44 | def ric_besselj_derivative(nu, x, flag = 1): 45 | ''' 46 | translation of KZHU ric_besselj_derivative(nu,x,flag) 47 | Inputs: 48 | nu: order of Riccati-Bessel Function, integer sequence from 1:N as an array 49 | x: arguments to Ric-Bessel Function, as a vector with M elements, where M is 50 | number of frequencies 51 | flag: 1 for first order derivative, 2 for second order derivative. 52 | ''' 53 | M = max(np.shape(x)) 54 | x = np.reshape(np.array(x), (1, M)) 55 | nu = np.reshape(np.array(nu), (len(nu), 1)) 56 | 57 | #debugging print statements 58 | #print(x) 59 | #print(np.shape(x)) 60 | #print(len(x)) 61 | 62 | temp = np.matmul(np.ones((len(nu), 1)), x) 63 | 64 | if (flag == 1): 65 | #J = 0.5*( ric_besselj(nu-1, x) + (1/temp)*ric_besselj(nu,x) - ric_besselj(nu+1, x) ) 66 | J0 = ric_besselj(nu-1, x) 67 | J1 = (1/temp)*ric_besselj(nu,x) 68 | J2 = ric_besselj(nu+1, x) 69 | J = 0.5*(J0+ J1 - J2) 70 | elif (flag == 2): 71 | J = 0.5 * ( ric_besselj_derivative(nu-1,x) + (1/temp)*ric_besselj_derivative(nu, x) \ 72 | - (1/(temp**2)) * ric_besselj(nu,x) - ric_besselj_derivative(nu+1, x) ) 73 | else: 74 | print('error: check third argument passed to ric_besselj_derivative (flag)') 75 | 76 | #removing all the zeros from inside the matrix... 77 | #f x*nu was 0, then it should become 0 after calculation 78 | temp1 = np.matmul(np.ones((len(nu), 1)), x) 79 | J[temp1 == 0] = 0 80 | 81 | temp2 = np.matmul(nu, np.ones((1,len(x)))) 82 | if (flag == 1): 83 | J[temp1+temp2 == 0] = 1; 84 | 85 | return J 86 | 87 | def ric_bessely(nu, x, scale = 1): 88 | ''' 89 | ''' 90 | M = max(np.shape(x)) 91 | N = max(np.shape(nu)) 92 | x = np.reshape(np.array(x), (1, M)) 93 | nu = np.reshape(np.array(nu), (N,1)) 94 | a = np.zeros((N, M), np.complex128) 95 | 96 | if (scale == 1): 97 | for i in range(0, N): 98 | #print(nu, type(nu), type(nu[0])) 99 | #print(x, type(x), type(x[0])) 100 | a[i,:] = np.sqrt(np.pi*x/2) * ss.yve(nu[i]+0.5, x) 101 | elif (scale == 0): 102 | for i in range(0, N): 103 | a[i,:] = np.sqrt(np.pi*x/2) * ss.yv(nu[i]+0.5, x) 104 | else: 105 | print('incorrect input to ric_besselj') 106 | 107 | # handling the case where x is zero because bessely is poorly defined 108 | temp = np.matmul(np.ones((N,1)), x) 109 | a[temp == 0] = float('-inf') 110 | 111 | temp1 = np.matmul(nu, np.ones((1,M))) 112 | a[temp+temp1 == 0] = -1 113 | 114 | return a 115 | 116 | def ric_bessely_derivative(nu, x, flag = 1): 117 | ''' 118 | Y = ric_bessely_derivative(nu, x, flag) using the recursive 119 | relationship to calculate the first derivative of the 120 | Riccati-Neumann's function. 121 | 122 | The Riccati-Neumann's function is defined as 123 | Y_{nu}(x) = \sqrt{\frac{\pi x}{2}} Y_{nu+1/2}(x) 124 | 125 | Inputs: 126 | nu order of the riccati Bessel's function. Must be a column vector. 127 | x row vector of size parameters at each frequency 128 | flag 1, first order derivative ; 2, second order derivative 129 | ''' 130 | M = max(np.shape(x)) 131 | N = max(np.shape(nu)) 132 | x = np.reshape(np.array(x), (1, M)) 133 | nu = np.reshape(np.array(nu), (N, 1)) 134 | 135 | temp = np.matmul(np.ones((N, 1)), x) 136 | if (flag == 1): 137 | Y = 0.5 * (ric_bessely(nu-1, x) + (1.0/temp)* ric_bessely(nu,x) - ric_bessely(nu+1, x) ) 138 | #Y0 = ric_bessely(nu-1, x); 139 | #Y1 = (1/temp)*ric_bessely(nu, x); 140 | #Y2 = ric_bessely(nu+1, x); 141 | #Y = 0.5*(Y0+ Y1- Y2); 142 | #print("Y0:\n", Y0,"\nY1:\n", Y1, "\nY2:\n", Y2, "\nY:\n", Y) 143 | elif (flag == 2): 144 | Y = 0.5 * ( ric_bessely_derivative(nu-1,x) + (1/temp)*ric_bessely_derivative(nu, x) \ 145 | - (1/(temp**2)) * ric_bessely(nu,x) - ric_bessely_derivative(nu+1, x) ) 146 | else: 147 | print('error: third argument passed to ric_bessely_derivative must be 1 or 2') 148 | 149 | temp2 = np.matmul(np.ones((N,1)), x) 150 | Y[temp2 == 0] = float('-inf') 151 | temp1 = np.matmul(nu, np.ones((1,M))) 152 | if (flag == 1): 153 | Y[temp1+temp2 == 0] = 1 154 | elif (flag == 2): 155 | Y[temp1+temp2 == 0] = -1 156 | 157 | return Y 158 | 159 | def ric_besselh(nu,x, K): 160 | ''' 161 | H = ric_besselh(nu, K, x) implement the Hankel function, 162 | which is defined as 163 | H_{nu}(x) = \sqrt{\frac{\pi x}{2}} H_{nu+1/2}(x) 164 | Inputs: 165 | nu order of the spherical Bessel's function. Must be a column vector. 166 | x row vector of size parameters at each frequency 167 | K 1 for Hankel's function of the first kind; 2 for Hankel's 168 | function of the second kind. 169 | ''' 170 | if (K == 1): 171 | H = ric_besselj(nu,x) + 1j*ric_bessely(nu,x) 172 | elif(K == 2): 173 | H = ric_besselj(nu,x) - 1j*ric_bessely(nu,x) 174 | else: 175 | print('error: third argument passed to ric_besselh must be 1 or 2') 176 | 177 | return H 178 | 179 | def ric_besselh_derivative(nu, x, K, flag = 1): 180 | ''' 181 | H = ric_besselh_derivative(nu, K, x) use the recursive relationship 182 | to calculate the first derivative of the Hankel function. 183 | H_{nu}(x) = \sqrt{\frac{\pi x}{2}} H_{nu+1/2}(x) 184 | 185 | Inputs: 186 | nu order of the riccati-Hankel's function. Must be a column vector 187 | 188 | K = 1 if it is Hankel's function of the first kind; K=2 if it is 189 | Hankel's function of the second kind. 190 | x Must be a row evector 191 | flag 1 for the first order derivative; 2 for the second order derivative 192 | ''' 193 | if (K == 1): 194 | H = ric_besselj_derivative(nu,x,flag) + 1j*ric_bessely_derivative(nu,x,flag) 195 | elif(K == 2): 196 | H = ric_besselj_derivative(nu,x,flag) - 1j*ric_bessely_derivative(nu,x,flag) 197 | else: 198 | print('error: argument K passed to ric_besselh_derivative must be 1 or 2') 199 | 200 | return H 201 | 202 | def spherical_besselj(nu,x, derivative = 0): 203 | ''' 204 | Compute spherical bessel function of the first kind, using formula 205 | given in: Abramowitz and Stegun, p. 437, 10.1.1 206 | Derivative calculated using recurrence relation in 207 | (https://dlmf.nist.gov/10.51) 208 | 209 | Inputs: 210 | nu order of the riccati Bessel's function. Must be a column vector. 211 | x row vector of size parameters at each frequency 212 | derivative 1, first order derivative ; 0, none. 213 | ''' 214 | M = max(np.shape(x)) 215 | N = max(np.shape(nu)) 216 | x = np.reshape(np.array(x), (1, M)) 217 | nu = np.reshape(np.array(nu), (N,1)) 218 | 219 | j = ss.spherical_jn(nu, x, derivative) 220 | 221 | return j 222 | 223 | def spherical_besselh(nu,x, derivative = 0): 224 | ''' 225 | Compute spherical hankel function of the first kind, using formula 226 | given in: Abramowitz and Stegun, p. 437, 10.1.1 227 | Derivative calculated using recurrence relation in 228 | (https://dlmf.nist.gov/10.51) 229 | 230 | Inputs: 231 | nu order of the riccati Bessel's function. Must be a column vector. 232 | x row vector of size parameters at each frequency 233 | derivative 1, first order derivative ; 0, none. 234 | ''' 235 | M = max(np.shape(x)) 236 | N = max(np.shape(nu)) 237 | x = np.reshape(np.array(x), (1, M)) 238 | nu = np.reshape(np.array(nu), (N,1)) 239 | 240 | J = ss.spherical_jn(nu, x, derivative) 241 | Y = ss.spherical_yn(nu, x, derivative) 242 | H = J + (1.0j)*Y 243 | return H 244 | 245 | if __name__ == "__main__": 246 | from DielectricMaterial import * 247 | radius = 0.5; 248 | sphere = DielectricMaterial(2.56,0.01) 249 | background = DielectricMaterial(1,0) 250 | sensor_location = [0,0,100]; 251 | frequency = [1e6, 1e7, 1e8] 252 | 253 | x = [] #size parameter 254 | for f in frequency: 255 | x += [radius * sphere.getWaveNumber(f)] 256 | nu = np.arange(1,5,1) 257 | #using kzhu ricatti bessel 258 | result1 = ric_besselj_derivative(nu,x,1) 259 | 260 | M = max(np.shape(x)) 261 | N = max(np.shape(nu)) 262 | x = np.reshape(np.array(x), (1, M)) 263 | nu = np.reshape(np.array(nu), (N,1)) 264 | #using recurrence relations and scipy special 265 | result2 = x*spherical_besselj(nu-1,x) - nu*spherical_besselj(nu,x) 266 | 267 | print(result1) 268 | print("") 269 | print(result2) 270 | 271 | -------------------------------------------------------------------------------- /bessel_arbitrary_precision.py: -------------------------------------------------------------------------------- 1 | # same functions as bessel.py 2 | # but using arbitrary precision library mpmath 3 | # (https://mpmath.org/doc/0.19/index.html) 4 | 5 | # Libraries that calculate bessel functions using fixed-precision 6 | # floating point variables may fail to evaluate besselj and bessely 7 | # functions accuratelly. 8 | # 9 | # For example, scipy.special 's jv(nu=0.5, x=9.4e14 + 1e-20j) 10 | # returns (nan+nanj). MATLAB builtin besselj(0.5, 9.4e14 + 1e-20j) 11 | # returns -1.7286e-08 + 1.6554e-24i. 12 | # For comparison, mpmath 's besselj(0.5, 9.4e14 + 1e-20j) returns 13 | # mpc(real='-1.7286313...e-8', imag='-1.945349...e-28'). 14 | # 15 | # Clearly, using mpmath is preffered over scipy.special since the former 16 | # can compute more extreme inputs, which arise at high frequencies 17 | # and high sphere conductivities. 18 | # 19 | # To reap the benefits of arbitrary precision arithmetic, it 20 | # is sufficient to evaluate only the bessel functions using mpmath 21 | # thereby avoiding scenarious where the result is (nan+nanj). 22 | 23 | import numpy as np 24 | import scipy.special as ss 25 | import mpmath as mp 26 | 27 | # set precision (default = 15 decimal places) 28 | # for example, let's set to 50 decimal place precision 29 | # this will be applied only to evaluate besselj,bessely functions 30 | mp.dps = 50 31 | 32 | def ric_besselj(nu,x,scale = 1): 33 | ''' 34 | Implementation of riccatti bessel function 35 | Inputs: 36 | nu: column vector of integers from 1 to N inclusive 37 | x: rpw vector of M complex-valued arguments, M = len(frequency) 38 | scale: equals 1 by default, scales the output of bessel function 39 | by e**(-abs(imag(x))). if zero, does not scale. (not recommended) 40 | Output: 41 | sqrt(pi*x/2)* J(nu+1/2, x) 42 | returned as an N by M array for each N values of nu and each M values of x 43 | Notes: 44 | scale factors will cancel out in the end, and minimize numerical issues due to 45 | arguments with very large complex arguments. 46 | ''' 47 | M = max(np.shape(x)) 48 | N = max(np.shape(nu)) 49 | a = np.zeros((N, M), np.complex128) 50 | 51 | if (scale != 0 and scale != 1): 52 | print("incorrect argument ric_besselj (scale)") 53 | return 54 | 55 | for i in range(0, len(nu)): 56 | for j in range(0, len(x)): 57 | if (scale == 1): 58 | y = np.sqrt(np.pi * x[j] / 2) * mp.besselj(nu[i]+0.5, x[j])* np.e**(-1*abs(np.imag(x[j]))) 59 | elif (scale == 0): 60 | y = np.sqrt(np.pi * (x[j]) / 2) * mp.besselj(nu[i]+0.5, x[j]) 61 | a[i,j] = complex(y.real, y.imag) 62 | 63 | return a 64 | 65 | def ric_besselj_derivative(nu, x, flag = 1): 66 | ''' 67 | translation of KZHU ric_besselj_derivative(nu,x,flag) 68 | Inputs: 69 | nu: order of Riccati-Bessel Function, integer sequence from 1:N as an array 70 | x: arguments to Ric-Bessel Function, as a vector with M elements, where M is 71 | number of frequencies 72 | flag: 1 for first order derivative, 2 for second order derivative. 73 | ''' 74 | M = max(np.shape(x)) 75 | M = max(np.shape(x)) 76 | 77 | 78 | #debugging print statements 79 | #print(x) 80 | #print(np.shape(x)) 81 | #print(len(x)) 82 | 83 | temp = np.matmul(np.ones((len(nu), 1)), np.reshape(np.array(x), (1, M))) 84 | 85 | if (flag == 1): 86 | J = 0.5*( ric_besselj(nu-1, x) + (1/temp)*ric_besselj(nu,x) - ric_besselj(nu+1, x) ) 87 | elif (flag == 2): 88 | J = 0.5 * ( ric_besselj_derivative(nu-1,x) + (1/temp)*ric_besselj_derivative(nu, x) \ 89 | - (1/(temp**2)) * ric_besselj(nu,x) - ric_besselj_derivative(nu+1, x) ) 90 | else: 91 | print('error: check third argument passed to ric_besselj_derivative (flag)') 92 | 93 | #removing all the zeros from inside the matrix... 94 | #f x*nu was 0, then it should become 0 after calculation 95 | x = np.reshape(np.array(x), (1, M)) 96 | nu = np.reshape(np.array(nu), (len(nu), 1)) 97 | 98 | temp1 = np.matmul(np.ones((len(nu), 1)), x) 99 | J[temp1 == 0] = 0 100 | 101 | temp2 = np.matmul(nu, np.ones((1,len(x)))) 102 | if (flag == 1): 103 | J[temp1+temp2 == 0] = 1; 104 | 105 | return J 106 | 107 | def ric_bessely(nu, x, scale = 1): 108 | ''' 109 | ''' 110 | M = max(np.shape(x)) 111 | N = max(np.shape(nu)) 112 | a = np.zeros((N, M), np.complex128) 113 | 114 | 115 | if (scale != 0 and scale != 1): 116 | print("incorrect argument ric_bessely (scale)") 117 | return 118 | 119 | for i in range(0, len(nu)): 120 | for j in range(0, len(x)): 121 | if (scale == 1): 122 | y = np.sqrt(np.pi * x[j] / 2) * mp.bessely(nu[i]+0.5, x[j]) * np.e**(-1*abs(np.imag(x[j]))) 123 | elif (scale == 0): 124 | y = np.sqrt(np.pi * (x[j]) / 2) * mp.bessely(nu[i]+0.5, x[j]) 125 | a[i,j] = complex(y.real, y.imag) 126 | 127 | # handling the case where x is zero because bessely is poorly defined 128 | temp = np.matmul(np.ones((N,1)), np.reshape(np.array(x), (1, M))) 129 | a[temp == 0] = float('-inf') 130 | 131 | return a 132 | 133 | def ric_bessely_derivative(nu, x, flag = 1): 134 | ''' 135 | Y = ric_bessely_derivative(nu, x, flag) using the recursive 136 | relationship to calculate the first derivative of the 137 | Riccati-Neumann's function. 138 | 139 | The Riccati-Neumann's function is defined as 140 | Y_{nu}(x) = \sqrt{\frac{\pi x}{2}} Y_{nu+1/2}(x) 141 | 142 | Inputs: 143 | nu: order of Riccati-Bessel Function, integer sequence from 1:N as an array 144 | x: arguments to Ric-Bessel Function, as a vector with M elements, where M is 145 | number of frequencies 146 | Note: if x == 0, then a ValueError is raised (because bessely(nu,0)= -inf) 147 | This should not happen because size parameters are non-zero 148 | flag: 1 for first order derivative, 2 for second order derivative. 149 | ''' 150 | M = max(np.shape(x)) 151 | N = max(np.shape(nu)) 152 | 153 | temp = np.matmul(np.ones((N, 1)), np.reshape(np.array(x), (1, M))) 154 | if (flag == 1): 155 | Y = 0.5 * (ric_bessely(nu-1, x) + (1.0/temp)* ric_bessely(nu,x) - ric_bessely(nu+1, x) ) 156 | elif (flag == 2): 157 | Y = 0.5 * ( ric_bessely_derivative(nu-1,x) + (1/temp)*ric_bessely_derivative(nu, x) \ 158 | - (1/(temp**2)) * ric_bessely(nu,x) - ric_bessely_derivative(nu+1, x) ) 159 | else: 160 | print('error: third argument passed to ric_bessely_derivative must be 1 or 2') 161 | 162 | x = np.reshape(np.array(x), (1, M)) 163 | nu = np.reshape(np.array(nu), (N, 1)) 164 | 165 | temp2 = np.matmul(np.ones((N,1)), x) 166 | Y[temp2 == 0] = float('-inf') 167 | temp1 = np.matmul(nu, np.ones((1,M))) 168 | if (flag == 1): 169 | Y[temp1+temp2 == 0] = 1 170 | elif (flag == 2): 171 | Y[temp1+temp2 == 0] = -1 172 | 173 | return Y 174 | 175 | def ric_besselh(nu,x, K): 176 | ''' 177 | H = ric_besselh(nu, K, x) implement the Hankel function, 178 | which is defined as 179 | H_{nu}(x) = \sqrt{\frac{\pi x}{2}} H_{nu+1/2}(x) 180 | Inputs: 181 | nu order of the spherical Bessel's function. Must be a column vector. 182 | x Must be a row vector. 183 | K 1 for Hankel's function of the first kind; 2 for Hankel's 184 | function of the second kind. 185 | ''' 186 | if (K == 1): 187 | H = ric_besselj(nu,x) + 1j*ric_bessely(nu,x) 188 | elif(K == 2): 189 | H = ric_besselj(nu,x) - 1j*ric_bessely(nu,x) 190 | else: 191 | print('error: third argument passed to ric_besselh must be 1 or 2') 192 | 193 | return H 194 | 195 | def ric_besselh_derivative(nu, x, K, flag = 1): 196 | ''' 197 | H = ric_besselh_derivative(nu, K, x) use the recursive relationship 198 | to calculate the first derivative of the Hankel function. 199 | H_{nu}(x) = \sqrt{\frac{\pi x}{2}} H_{nu+1/2}(x) 200 | 201 | Inputs: 202 | nu order of the riccati-Hankel's function. Must be a column vector 203 | 204 | K = 1 if it is Hankel's function of the first kind; K=2 if it is 205 | Hankel's function of the second kind. 206 | x Must be a row evector 207 | flag 1 for the first order derivative; 2 for the second order derivative 208 | ''' 209 | if (K == 1): 210 | H = ric_besselj_derivative(nu,x,flag) + 1j*ric_bessely_derivative(nu,x,flag) 211 | elif(K == 2): 212 | H = ric_besselj_derivative(nu,x,flag) - 1j*ric_bessely_derivative(nu,x,flag) 213 | else: 214 | print('error: argument K passed to ric_besselh_derivative must be 1 or 2') 215 | 216 | return H 217 | 218 | if __name__ == "__main__": 219 | #debugging test script 220 | ''' 221 | from DielectricMaterial import * 222 | radius = 0.5; 223 | sphere = DielectricMaterial(2.56,0.01) 224 | background = DielectricMaterial(1,0) 225 | sensor_location = [0,0,100]; 226 | frequency = [1e6, 1e7, 1e8] 227 | 228 | x = [] #size parameter 229 | for f in frequency: 230 | x += [radius * sphere.getWaveNumber(f)] 231 | print(x) 232 | print(type(x[0])) 233 | 234 | nu = np.arange(1,5,1) 235 | print(nu) 236 | a = ric_besselj_derivative(nu,x,flag=1) 237 | print(a) 238 | ''' -------------------------------------------------------------------------------- /data_output/_about.txt: -------------------------------------------------------------------------------- 1 | The code returns data in .txt files used to create plots of 2 | RCS vs frequency (monostatic) and RCS vs angle of observation 3 | (bistatic). 4 | 5 | To reduce clutter in the root directory, sample output files 6 | are moved here. 7 | -------------------------------------------------------------------------------- /data_output/bistatic_lossy_dielectric_example.txt: -------------------------------------------------------------------------------- 1 | freq(Hz) 1.00e+09 eps_r 2.56 mu_r 1 sigma 1.00e-02 2 | theta(rad) RCS(m^2) 3 | 0.000000000e+00 1.274832396e+02 4 | 3.173325913e-02 1.231648791e+02 5 | 6.346651825e-02 1.109345517e+02 6 | 9.519977738e-02 9.279618245e+01 7 | 1.269330365e-01 7.157045928e+01 8 | 1.586662956e-01 5.027031149e+01 9 | 1.903995548e-01 3.148375233e+01 10 | 2.221328139e-01 1.692019067e+01 11 | 2.538660730e-01 7.217344186e+00 12 | 2.855993321e-01 2.023443599e+00 13 | 3.173325913e-01 2.917094544e-01 14 | 3.490658504e-01 6.750191320e-01 15 | 3.807991095e-01 1.899972869e+00 16 | 4.125323687e-01 3.028052882e+00 17 | 4.442656278e-01 3.562244193e+00 18 | 4.759988869e-01 3.410418681e+00 19 | 5.077321460e-01 2.754816687e+00 20 | 5.394654052e-01 1.891179840e+00 21 | 5.711986643e-01 1.092370507e+00 22 | 6.029319234e-01 5.280249297e-01 23 | 6.346651825e-01 2.452243916e-01 24 | 6.663984417e-01 1.948948783e-01 25 | 6.981317008e-01 2.795254913e-01 26 | 7.298649599e-01 3.994822385e-01 27 | 7.615982191e-01 4.836870984e-01 28 | 7.933314782e-01 5.005966091e-01 29 | 8.250647373e-01 4.532136263e-01 30 | 8.567979964e-01 3.655092082e-01 31 | 8.885312556e-01 2.674781328e-01 32 | 9.202645147e-01 1.836902986e-01 33 | 9.519977738e-01 1.273524930e-01 34 | 9.837310329e-01 9.967529749e-02 35 | 1.015464292e+00 9.308246493e-02 36 | 1.047197551e+00 9.632381186e-02 37 | 1.078930810e+00 9.955961081e-02 38 | 1.110664069e+00 9.781543459e-02 39 | 1.142397329e+00 9.184658910e-02 40 | 1.174130588e+00 8.636799659e-02 41 | 1.205863847e+00 8.659653902e-02 42 | 1.237597106e+00 9.474991044e-02 43 | 1.269330365e+00 1.081893436e-01 44 | 1.301063624e+00 1.201682168e-01 45 | 1.332796883e+00 1.229170392e-01 46 | 1.364530142e+00 1.116200827e-01 47 | 1.396263402e+00 8.731400314e-02 48 | 1.427996661e+00 5.717101751e-02 49 | 1.459729920e+00 3.185034080e-02 50 | 1.491463179e+00 2.102790496e-02 51 | 1.523196438e+00 2.913468089e-02 52 | 1.554929697e+00 5.327759369e-02 53 | 1.586662956e+00 8.430385666e-02 54 | 1.618396215e+00 1.105037272e-01 55 | 1.650129475e+00 1.222551775e-01 56 | 1.681862734e+00 1.155691962e-01 57 | 1.713595993e+00 9.312396848e-02 58 | 1.745329252e+00 6.261342151e-02 59 | 1.777062511e+00 3.343231704e-02 60 | 1.808795770e+00 1.329828388e-02 61 | 1.840529029e+00 6.159528796e-03 62 | 1.872262289e+00 1.189265711e-02 63 | 1.903995548e+00 2.737738960e-02 64 | 1.935728807e+00 4.803598822e-02 65 | 1.967462066e+00 6.903868144e-02 66 | 1.999195325e+00 8.591724774e-02 67 | 2.030928584e+00 9.487891467e-02 68 | 2.062661843e+00 9.329523273e-02 69 | 2.094395102e+00 8.055496761e-02 70 | 2.126128362e+00 5.894524489e-02 71 | 2.157861621e+00 3.386395618e-02 72 | 2.189594880e+00 1.277943848e-02 73 | 2.221328139e+00 2.948416743e-03 74 | 2.253061398e+00 8.661408795e-03 75 | 2.284794657e+00 2.924308838e-02 76 | 2.316527916e+00 5.886684017e-02 77 | 2.348261175e+00 8.846847907e-02 78 | 2.379994435e+00 1.090419864e-01 79 | 2.411727694e+00 1.149033398e-01 80 | 2.443460953e+00 1.055041957e-01 81 | 2.475194212e+00 8.508154198e-02 82 | 2.506927471e+00 6.047213424e-02 83 | 2.538660730e+00 3.824987894e-02 84 | 2.570393989e+00 2.253613808e-02 85 | 2.602127248e+00 1.432484694e-02 86 | 2.633860508e+00 1.228080199e-02 87 | 2.665593767e+00 1.422501657e-02 88 | 2.697327026e+00 1.831886261e-02 89 | 2.729060285e+00 2.336204259e-02 90 | 2.760793544e+00 2.832857712e-02 91 | 2.792526803e+00 3.181042679e-02 92 | 2.824260062e+00 3.207188764e-02 93 | 2.855993321e+00 2.792605606e-02 94 | 2.887726581e+00 1.995586291e-02 95 | 2.919459840e+00 1.118282240e-02 96 | 2.951193099e+00 6.448925430e-03 97 | 2.982926358e+00 1.047562095e-02 98 | 3.014659617e+00 2.540676137e-02 99 | 3.046392876e+00 4.911573354e-02 100 | 3.078126135e+00 7.533204380e-02 101 | 3.109859394e+00 9.578436214e-02 102 | 3.141592654e+00 1.035062651e-01 103 | -------------------------------------------------------------------------------- /data_output/bistatic_perfect_dielectric_example.txt: -------------------------------------------------------------------------------- 1 | freq(Hz) 1.00e+09 eps_r 2.56 mu_r 1 sigma 0.00e+00 2 | theta(rad) RCS(m^2) 3 | 0.000000000e+00 1.700205541e+02 4 | 3.173325913e-02 1.641990506e+02 5 | 6.346651825e-02 1.477061469e+02 6 | 9.519977738e-02 1.232366472e+02 7 | 1.269330365e-01 9.460781465e+01 8 | 1.586662956e-01 6.593777117e+01 9 | 1.903995548e-01 4.081524678e+01 10 | 2.221328139e-01 2.166298475e+01 11 | 2.538660730e-01 9.431031380e+00 12 | 2.855993321e-01 3.657250332e+00 13 | 3.173325913e-01 2.832597002e+00 14 | 3.490658504e-01 4.937387418e+00 15 | 3.807991095e-01 7.989617123e+00 16 | 4.125323687e-01 1.046870488e+01 17 | 4.442656278e-01 1.153449815e+01 18 | 4.759988869e-01 1.103016610e+01 19 | 5.077321460e-01 9.316684137e+00 20 | 5.394654052e-01 7.020774702e+00 21 | 5.711986643e-01 4.782616870e+00 22 | 6.029319234e-01 3.069456063e+00 23 | 6.346651825e-01 2.087699767e+00 24 | 6.663984417e-01 1.791718367e+00 25 | 6.981317008e-01 1.962059605e+00 26 | 7.298649599e-01 2.313815286e+00 27 | 7.615982191e-01 2.597198552e+00 28 | 7.933314782e-01 2.663359852e+00 29 | 8.250647373e-01 2.484057778e+00 30 | 8.567979964e-01 2.129192118e+00 31 | 8.885312556e-01 1.717704006e+00 32 | 9.202645147e-01 1.362715561e+00 33 | 9.519977738e-01 1.130351337e+00 34 | 9.837310329e-01 1.024418147e+00 35 | 1.015464292e+00 9.985287301e-01 36 | 1.047197551e+00 9.869235587e-01 37 | 1.078930810e+00 9.388272351e-01 38 | 1.110664069e+00 8.410597345e-01 39 | 1.142397329e+00 7.198190485e-01 40 | 1.174130588e+00 6.224362212e-01 41 | 1.205863847e+00 5.891422161e-01 42 | 1.237597106e+00 6.292887014e-01 43 | 1.269330365e+00 7.139627296e-01 44 | 1.301063624e+00 7.886850898e-01 45 | 1.332796883e+00 7.998475386e-01 46 | 1.364530142e+00 7.216444137e-01 47 | 1.396263402e+00 5.699375078e-01 48 | 1.427996661e+00 3.959603139e-01 49 | 1.459729920e+00 2.628009511e-01 50 | 1.491463179e+00 2.161519059e-01 51 | 1.523196438e+00 2.635650567e-01 52 | 1.554929697e+00 3.720504977e-01 53 | 1.586662956e+00 4.846218816e-01 54 | 1.618396215e+00 5.470892237e-01 55 | 1.650129475e+00 5.317580773e-01 56 | 1.681862734e+00 4.469294595e-01 57 | 1.713595993e+00 3.288030750e-01 58 | 1.745329252e+00 2.213626312e-01 59 | 1.777062511e+00 1.553606879e-01 60 | 1.808795770e+00 1.369298576e-01 61 | 1.840529029e+00 1.503156539e-01 62 | 1.872262289e+00 1.713197886e-01 63 | 1.903995548e+00 1.826513504e-01 64 | 1.935728807e+00 1.822848808e-01 65 | 1.967462066e+00 1.808220309e-01 66 | 1.999195325e+00 1.906737040e-01 67 | 2.030928584e+00 2.146143490e-01 68 | 2.062661843e+00 2.412733138e-01 69 | 2.094395102e+00 2.506085920e-01 70 | 2.126128362e+00 2.261652702e-01 71 | 2.157861621e+00 1.666831232e-01 72 | 2.189594880e+00 8.984816488e-02 73 | 2.221328139e+00 2.548124740e-02 74 | 2.253061398e+00 1.538630279e-03 75 | 2.284794657e+00 3.041389680e-02 76 | 2.316527916e+00 1.028442273e-01 77 | 2.348261175e+00 1.924463651e-01 78 | 2.379994435e+00 2.680999334e-01 79 | 2.411727694e+00 3.074092339e-01 80 | 2.443460953e+00 3.044686091e-01 81 | 2.475194212e+00 2.688791596e-01 82 | 2.506927471e+00 2.180044623e-01 83 | 2.538660730e+00 1.677757294e-01 84 | 2.570393989e+00 1.271715120e-01 85 | 2.602127248e+00 9.830215674e-02 86 | 2.633860508e+00 8.020234679e-02 87 | 2.665593767e+00 7.263029415e-02 88 | 2.697327026e+00 7.753926103e-02 89 | 2.729060285e+00 9.925797238e-02 90 | 2.760793544e+00 1.470231543e-01 91 | 2.792526803e+00 2.428404296e-01 92 | 2.824260062e+00 4.333120825e-01 93 | 2.855993321e+00 7.984062507e-01 94 | 2.887726581e+00 1.447104952e+00 95 | 2.919459840e+00 2.492653127e+00 96 | 2.951193099e+00 4.008924067e+00 97 | 2.982926358e+00 5.980673228e+00 98 | 3.014659617e+00 8.268329563e+00 99 | 3.046392876e+00 1.060732792e+01 100 | 3.078126135e+00 1.265137402e+01 101 | 3.109859394e+00 1.405201151e+01 102 | 3.141592654e+00 1.455070693e+01 103 | -------------------------------------------------------------------------------- /data_output/lossy_dielectric.txt: -------------------------------------------------------------------------------- 1 | eps_r 2.56 mu_r 1 sigma 3.00e-02 radius 0.5 2 | frequency(Hz) RCS(m^2) 3 | 5.995849160e+06 4.903722639e-05 4 | 1.199169832e+07 7.879935140e-04 5 | 1.798754748e+07 4.014200594e-03 6 | 2.398339664e+07 1.277156713e-02 7 | 2.997924580e+07 3.132873586e-02 8 | 3.597509496e+07 6.493223957e-02 9 | 4.197094412e+07 1.190843683e-01 10 | 4.796679328e+07 1.980768804e-01 11 | 5.396264244e+07 3.027356763e-01 12 | 5.995849160e+07 4.279728996e-01 13 | 6.595434076e+07 5.616150373e-01 14 | 7.195018992e+07 6.861606876e-01 15 | 7.794603908e+07 7.836144908e-01 16 | 8.394188824e+07 8.410742484e-01 17 | 8.993773740e+07 8.539045656e-01 18 | 9.593358656e+07 8.252512886e-01 19 | 1.019294357e+08 7.631966931e-01 20 | 1.079252849e+08 6.776542182e-01 21 | 1.139211340e+08 5.782604687e-01 22 | 1.199169832e+08 4.734347101e-01 23 | 1.259128324e+08 3.702189345e-01 24 | 1.319086815e+08 2.744395551e-01 25 | 1.379045307e+08 1.908679884e-01 26 | 1.439003798e+08 1.232263203e-01 27 | 1.498962290e+08 7.402656632e-02 28 | 1.558920782e+08 4.433359731e-02 29 | 1.618879273e+08 3.359132011e-02 30 | 1.678837765e+08 3.963847289e-02 31 | 1.738796256e+08 5.897082036e-02 32 | 1.798754748e+08 8.721300467e-02 33 | 1.858713240e+08 1.196909761e-01 34 | 1.918671731e+08 1.519758754e-01 35 | 1.978630223e+08 1.803022020e-01 36 | 2.038588714e+08 2.018211364e-01 37 | 2.098547206e+08 2.147027695e-01 38 | 2.158505698e+08 2.181296076e-01 39 | 2.218464189e+08 2.122257004e-01 40 | 2.278422681e+08 1.979502192e-01 41 | 2.338381172e+08 1.769640276e-01 42 | 2.398339664e+08 1.514635164e-01 43 | 2.458298156e+08 1.239737204e-01 44 | 2.518256647e+08 9.710275849e-02 45 | 2.578215139e+08 7.327669553e-02 46 | 2.638173630e+08 5.448922549e-02 47 | 2.698132122e+08 4.210570536e-02 48 | 2.758090614e+08 3.675239887e-02 49 | 2.818049105e+08 3.830262608e-02 50 | 2.878007597e+08 4.595023235e-02 51 | 2.937966088e+08 5.834596495e-02 52 | 2.997924580e+08 7.376824904e-02 53 | 3.057883072e+08 9.030505767e-02 54 | 3.117841563e+08 1.060328408e-01 55 | 3.177800055e+08 1.191860851e-01 56 | 3.237758546e+08 1.283134592e-01 57 | 3.297717038e+08 1.324133962e-01 58 | 3.357675530e+08 1.310361523e-01 59 | 3.417634021e+08 1.243353120e-01 60 | 3.477592513e+08 1.130534949e-01 61 | 3.537551004e+08 9.843614870e-02 62 | 3.597509496e+08 8.208148578e-02 63 | 3.657467988e+08 6.574842688e-02 64 | 3.717426479e+08 5.115224649e-02 65 | 3.777384971e+08 3.977670949e-02 66 | 3.837343462e+08 3.272344828e-02 67 | 3.897301954e+08 3.060881371e-02 68 | 3.957260446e+08 3.351032727e-02 69 | 4.017218937e+08 4.096167911e-02 70 | 4.077177429e+08 5.199612704e-02 71 | 4.137135920e+08 6.523976962e-02 72 | 4.197094412e+08 7.905451041e-02 73 | 4.257052904e+08 9.172336726e-02 74 | 4.317011395e+08 1.016593598e-01 75 | 4.376969887e+08 1.076083108e-01 76 | 4.436928378e+08 1.088115622e-01 77 | 4.496886870e+08 1.051004735e-01 78 | 4.556845362e+08 9.690916767e-02 79 | 4.616803853e+08 8.520928931e-02 80 | 4.676762345e+08 7.138351781e-02 81 | 4.736720836e+08 5.705941865e-02 82 | 4.796679328e+08 4.392307492e-02 83 | 4.856637820e+08 3.352756301e-02 84 | 4.916596311e+08 2.710966206e-02 85 | 4.976554803e+08 2.543119171e-02 86 | 5.036513294e+08 2.866668633e-02 87 | 5.096471786e+08 3.636119816e-02 88 | 5.156430278e+08 4.747558667e-02 89 | 5.216388769e+08 6.052062964e-02 90 | 5.276347261e+08 7.376066384e-02 91 | 5.336305752e+08 8.545099185e-02 92 | 5.396264244e+08 9.406816793e-02 93 | 5.456222736e+08 9.849950082e-02 94 | 5.516181227e+08 9.817218162e-02 95 | 5.576139719e+08 9.311543364e-02 96 | 5.636098210e+08 8.395585839e-02 97 | 5.696056702e+08 7.184714581e-02 98 | 5.756015194e+08 5.833544527e-02 99 | 5.815973685e+08 4.516654866e-02 100 | 5.875932177e+08 3.405263640e-02 101 | 5.935890668e+08 2.643092749e-02 102 | 5.995849160e+08 2.325619744e-02 103 | 6.055807652e+08 2.486658408e-02 104 | 6.115766143e+08 3.094624706e-02 105 | 6.175724635e+08 4.058567543e-02 106 | 6.235683126e+08 5.242075225e-02 107 | 6.295641618e+08 6.482218806e-02 108 | 6.355600110e+08 7.610777646e-02 109 | 6.415558601e+08 8.475543105e-02 110 | 6.475517093e+08 8.959848896e-02 111 | 6.535475584e+08 8.998350548e-02 112 | 6.595434076e+08 8.586749291e-02 113 | 6.655392568e+08 7.783251913e-02 114 | 6.715351059e+08 6.700584482e-02 115 | 6.775309551e+08 5.489289233e-02 116 | 6.835268042e+08 4.315144200e-02 117 | 6.895226534e+08 3.334907590e-02 118 | 6.955185026e+08 2.674615233e-02 119 | 7.015143517e+08 2.413506095e-02 120 | 7.075102009e+08 2.575061730e-02 121 | 7.135060500e+08 3.125395933e-02 122 | 7.195018992e+08 3.978626949e-02 123 | 7.254977484e+08 5.008647229e-02 124 | 7.314935975e+08 6.066358911e-02 125 | 7.374894467e+08 7.000643899e-02 126 | 7.434852958e+08 7.680243640e-02 127 | 7.494811450e+08 8.012919254e-02 128 | 7.554769942e+08 7.958376231e-02 129 | 7.614728433e+08 7.532675671e-02 130 | 7.674686925e+08 6.803791826e-02 131 | 7.734645416e+08 5.879804644e-02 132 | 7.794603908e+08 4.892271813e-02 133 | 7.854562400e+08 3.977481918e-02 134 | 7.914520891e+08 3.257928755e-02 135 | 7.974479383e+08 2.825972808e-02 136 | 8.034437874e+08 2.731507762e-02 137 | 8.094396366e+08 2.975365827e-02 138 | 8.154354858e+08 3.509792703e-02 139 | 8.214313349e+08 4.246337250e-02 140 | 8.274271841e+08 5.070053631e-02 141 | 8.334230332e+08 5.857510366e-02 142 | 8.394188824e+08 6.495335388e-02 143 | 8.454147316e+08 6.896190771e-02 144 | 8.514105807e+08 7.009973766e-02 145 | 8.574064299e+08 6.829177955e-02 146 | 8.634022790e+08 6.388272007e-02 147 | 8.693981282e+08 5.757533982e-02 148 | 8.753939774e+08 5.032184984e-02 149 | 8.813898265e+08 4.318131563e-02 150 | 8.873856757e+08 3.716208607e-02 151 | 8.933815248e+08 3.307312934e-02 152 | 8.993773740e+08 3.140901240e-02 153 | 9.053732232e+08 3.228780565e-02 154 | 9.113690723e+08 3.545037199e-02 155 | 9.173649215e+08 4.031706767e-02 156 | 9.233607706e+08 4.608813898e-02 157 | 9.293566198e+08 5.186931618e-02 158 | 9.353524690e+08 5.680367907e-02 159 | 9.413483181e+08 6.019260687e-02 160 | 9.473441673e+08 6.159080415e-02 161 | 9.533400164e+08 6.086293046e-02 162 | 9.593358656e+08 5.819340002e-02 163 | -------------------------------------------------------------------------------- /data_output/perfect_dielectric.txt: -------------------------------------------------------------------------------- 1 | eps_r 2.56 mu_r 1 sigma 0.00e+00 radius 0.5 2 | frequency(Hz) RCS(m^2) 3 | 5.995849160e+06 5.722576666e-06 4 | 1.199169832e+07 9.118743529e-05 5 | 1.798754748e+07 4.584529217e-04 6 | 2.398339664e+07 1.434697240e-03 7 | 2.997924580e+07 3.457294665e-03 8 | 3.597509496e+07 7.051674053e-03 9 | 4.197094412e+07 1.280039434e-02 10 | 4.796679328e+07 2.130111673e-02 11 | 5.396264244e+07 3.311045912e-02 12 | 5.995849160e+07 4.867048888e-02 13 | 6.595434076e+07 6.821553853e-02 14 | 7.195018992e+07 9.166009911e-02 15 | 7.794603908e+07 1.184748343e-01 16 | 8.394188824e+07 1.475678565e-01 17 | 8.993773740e+07 1.772013776e-01 18 | 9.593358656e+07 2.049860267e-01 19 | 1.019294357e+08 2.279998158e-01 20 | 1.079252849e+08 2.430684682e-01 21 | 1.139211340e+08 2.472159056e-01 22 | 1.199169832e+08 2.382561461e-01 23 | 1.259128324e+08 2.154685000e-01 24 | 1.319086815e+08 1.802892856e-01 25 | 1.379045307e+08 1.369449949e-01 26 | 1.439003798e+08 9.286795919e-02 27 | 1.498962290e+08 5.847237738e-02 28 | 1.558920782e+08 4.547773630e-02 29 | 1.618879273e+08 6.305377689e-02 30 | 1.678837765e+08 1.127493621e-01 31 | 1.738796256e+08 1.860015129e-01 32 | 1.798754748e+08 2.677325503e-01 33 | 1.858713240e+08 3.437973717e-01 34 | 1.918671731e+08 4.059603248e-01 35 | 1.978630223e+08 4.515861076e-01 36 | 2.038588714e+08 4.804044280e-01 37 | 2.098547206e+08 4.915650892e-01 38 | 2.158505698e+08 4.825612634e-01 39 | 2.218464189e+08 4.505513064e-01 40 | 2.278422681e+08 3.963359326e-01 41 | 2.338381172e+08 3.299213126e-01 42 | 2.398339664e+08 2.727038637e-01 43 | 2.458298156e+08 2.494796342e-01 44 | 2.518256647e+08 2.736117627e-01 45 | 2.578215139e+08 3.408201026e-01 46 | 2.638173630e+08 4.369502544e-01 47 | 2.698132122e+08 5.485687134e-01 48 | 2.758090614e+08 6.679641885e-01 49 | 2.818049105e+08 7.930765731e-01 50 | 2.878007597e+08 9.242644772e-01 51 | 2.937966088e+08 1.057560156e+00 52 | 2.997924580e+08 1.174223324e+00 53 | 3.057883072e+08 1.233972114e+00 54 | 3.117841563e+08 1.192864673e+00 55 | 3.177800055e+08 1.050835067e+00 56 | 3.237758546e+08 8.697273168e-01 57 | 3.297717038e+08 7.236142571e-01 58 | 3.357675530e+08 6.520815350e-01 59 | 3.417634021e+08 6.622781082e-01 60 | 3.477592513e+08 7.500589312e-01 61 | 3.537551004e+08 9.152150996e-01 62 | 3.597509496e+08 1.168960515e+00 63 | 3.657467988e+08 1.534153932e+00 64 | 3.717426479e+08 2.024632135e+00 65 | 3.777384971e+08 2.575990276e+00 66 | 3.837343462e+08 2.974037313e+00 67 | 3.897301954e+08 2.994280194e+00 68 | 3.957260446e+08 2.667788892e+00 69 | 4.017218937e+08 2.208585407e+00 70 | 4.077177429e+08 1.786500199e+00 71 | 4.137135920e+08 1.475876110e+00 72 | 4.197094412e+08 1.299278762e+00 73 | 4.257052904e+08 1.267968180e+00 74 | 4.317011395e+08 1.409671406e+00 75 | 4.376969887e+08 1.793184622e+00 76 | 4.436928378e+08 2.531372858e+00 77 | 4.496886870e+08 3.642309928e+00 78 | 4.556845362e+08 4.713331987e+00 79 | 4.616803853e+08 5.143233104e+00 80 | 4.676762345e+08 4.925157535e+00 81 | 4.736720836e+08 4.397338739e+00 82 | 4.796679328e+08 3.796508470e+00 83 | 4.856637820e+08 3.247585237e+00 84 | 4.916596311e+08 2.826439357e+00 85 | 4.976554803e+08 2.588649794e+00 86 | 5.036513294e+08 2.598891843e+00 87 | 5.096471786e+08 2.979295122e+00 88 | 5.156430278e+08 3.924108150e+00 89 | 5.216388769e+08 5.346511472e+00 90 | 5.276347261e+08 6.288269353e+00 91 | 5.336305752e+08 6.296861098e+00 92 | 5.396264244e+08 5.948456840e+00 93 | 5.456222736e+08 5.525049138e+00 94 | 5.516181227e+08 5.040155972e+00 95 | 5.576139719e+08 4.542148871e+00 96 | 5.636098210e+08 4.152830968e+00 97 | 5.696056702e+08 4.006876793e+00 98 | 5.756015194e+08 4.267154255e+00 99 | 5.815973685e+08 5.258024472e+00 100 | 5.875932177e+08 7.430119226e+00 101 | 5.935890668e+08 9.539721503e+00 102 | 5.995849160e+08 8.976236121e+00 103 | 6.055807652e+08 7.523764786e+00 104 | 6.115766143e+08 6.482271757e+00 105 | 6.175724635e+08 5.693616297e+00 106 | 6.235683126e+08 4.923221585e+00 107 | 6.295641618e+08 4.225351015e+00 108 | 6.355600110e+08 3.812414336e+00 109 | 6.415558601e+08 3.847452860e+00 110 | 6.475517093e+08 4.562820424e+00 111 | 6.535475584e+08 6.766278136e+00 112 | 6.595434076e+08 1.165160562e+01 113 | 6.655392568e+08 1.368313628e+01 114 | 6.715351059e+08 1.147068165e+01 115 | 6.775309551e+08 9.775797841e+00 116 | 6.835268042e+08 8.575925546e+00 117 | 6.895226534e+08 7.115176446e+00 118 | 6.955185026e+08 5.232342174e+00 119 | 7.015143517e+08 3.674720246e+00 120 | 7.075102009e+08 2.931679984e+00 121 | 7.135060500e+08 2.951853805e+00 122 | 7.195018992e+08 3.957008839e+00 123 | 7.254977484e+08 7.800383095e+00 124 | 7.314935975e+08 1.400237789e+01 125 | 7.374894467e+08 1.234946976e+01 126 | 7.434852958e+08 1.104535001e+01 127 | 7.494811450e+08 1.101659133e+01 128 | 7.554769942e+08 1.108599349e+01 129 | 7.614728433e+08 9.553080430e+00 130 | 7.674686925e+08 6.278943508e+00 131 | 7.734645416e+08 4.012803254e+00 132 | 7.794603908e+08 3.253777461e+00 133 | 7.854562400e+08 3.470751980e+00 134 | 7.914520891e+08 5.402399329e+00 135 | 7.974479383e+08 1.262469609e+01 136 | 8.034437874e+08 1.057156147e+01 137 | 8.094396366e+08 8.389392466e+00 138 | 8.154354858e+08 8.563339387e+00 139 | 8.214313349e+08 9.868106908e+00 140 | 8.274271841e+08 1.143791768e+01 141 | 8.334230332e+08 9.652722365e+00 142 | 8.394188824e+08 5.639837124e+00 143 | 8.454147316e+08 4.080351398e+00 144 | 8.514105807e+08 3.992623990e+00 145 | 8.574064299e+08 5.053112421e+00 146 | 8.634022790e+08 1.188512670e+01 147 | 8.693981282e+08 1.212231841e+01 148 | 8.753939774e+08 7.831204428e+00 149 | 8.813898265e+08 7.168691831e+00 150 | 8.873856757e+08 7.593291978e+00 151 | 8.933815248e+08 9.077833020e+00 152 | 8.993773740e+08 1.048158414e+01 153 | 9.053732232e+08 5.857901617e+00 154 | 9.113690723e+08 3.260699409e+00 155 | 9.173649215e+08 3.016400163e+00 156 | 9.233607706e+08 3.594131166e+00 157 | 9.293566198e+08 7.223544675e+00 158 | 9.353524690e+08 1.389588423e+01 159 | 9.413483181e+08 8.327636927e+00 160 | 9.473441673e+08 7.858847217e+00 161 | 9.533400164e+08 8.188508178e+00 162 | 9.593358656e+08 9.071163061e+00 163 | -------------------------------------------------------------------------------- /data_output/sigma1e3_eaefie_bRCS_f_1000000000_Hz.txt: -------------------------------------------------------------------------------- 1 | freq(Hz) 1000000000 eps_r 2.00 mu_r 1 sigma 1000 2 | theta(rad) RCS(m^2) 3 | 0 0.801777377776518 0.801777377776518 4 | 0.0317332591271696 0.801794252170244 5 | 0.0634665182543393 0.798977071033323 6 | 0.0951997773815089 0.794664506659017 7 | 0.126933036508679 0.790753237296905 8 | 0.158666295635848 0.78920371889823 9 | 0.190399554763018 0.791531291589537 10 | 0.222132813890187 0.798397771654719 0.774423975228412 11 | 0.253866073017357 0.809384604357593 0.774703842028119 12 | 0.285599332144527 0.822982115278853 0.777404032342256 13 | 0.317332591271696 0.836786745370708 0.782415074567025 14 | 0.349065850398866 0.847869627280585 0.789325375319826 15 | 0.380799109526036 0.853266018957249 0.79745790482388 16 | 0.412532368653205 0.850528469788982 0.805945664963937 17 | 0.444265627780375 0.838277515878303 0.813839914002617 18 | 0.475998886907544 0.816667498596574 0.820239689560927 19 | 0.507732146034714 0.787666637409812 0.824426044104595 20 | 0.539465405161884 0.755043637399839 0.825980665386288 21 | 0.571198664289053 0.723974835688522 0.824867421448381 22 | 0.602931923416223 0.700247264642425 0.821457903060867 23 | 0.634665182543393 0.689131127644868 0.816488781391112 24 | 0.666398441670562 0.69410978362214 0.810949490234219 25 | 0.698131700797732 0.715752242366472 0.805912127646534 26 | 0.729864959924901 0.751054008399351 0.802329317176908 27 | 0.761598219052071 0.79352732454329 0.800837092489234 28 | 0.793331478179241 0.83418278304117 0.801605427204839 29 | 0.82506473730641 0.86333010910544 0.804276036737963 30 | 0.85679799643358 0.872883149866715 0.808014064937085 31 | 0.88853125556075 0.858647633511549 0.811677924984523 32 | 0.920264514687919 0.821968014188755 0.814083272186543 33 | 0.951997773815089 0.770163720089889 0.814308855204992 34 | 0.983731032942258 0.715413448510375 0.811971560114873 35 | 1.01546429206943 0.672120394667494 0.807393016372092 36 | 1.0471975511966 0.653234102566414 0.801595913463376 37 | 1.07893081032377 0.666400503780427 0.796105047574255 38 | 1.11066406945094 0.711031845359732 0.792579973707879 39 | 1.14239732857811 0.777326040953173 0.792360493917719 40 | 1.17413058770528 0.847875019561731 0.796046532995628 41 | 1.20586384683245 0.901830191768053 0.803244141180997 42 | 1.23759710595962 0.920788259712622 0.812579442428135 43 | 1.26933036508679 0.894851232900496 0.82201361259008 44 | 1.30106362421395 0.826956034534828 0.829399501644707 45 | 1.33279688334112 0.733763232259353 0.833131264476804 46 | 1.36453014246829 0.642204284270653 0.83268427666455 47 | 1.39626340159546 0.582076171198738 0.828849952559643 48 | 1.42799666072263 0.576500707386862 0.823548159445655 49 | 1.4597299198498 0.633157228114493 0.819233500233831 50 | 1.49146317897697 0.739481215050258 0.818061260322143 51 | 1.52319643810414 0.864211643899838 0.821090431571327 52 | 1.55492969723131 0.965822259934263 0.827825091370475 53 | 1.58666295635848 1.00595070165478 0.836306727428713 54 | 1.61839621548565 0.963738317193542 0.843784658281478 55 | 1.65012947461282 0.845904388898897 0.847767884226792 56 | 1.68186273373999 0.688058753181575 0.847084637422114 57 | 1.71359599286716 0.545308838481365 0.842526437374888 58 | 1.74532925199433 0.474016381173095 0.836772234829765 59 | 1.7770625111215 0.510342325445466 0.833549972739937 60 | 1.80879577024867 0.653460627490832 0.836305291014337 61 | 1.84052902937584 0.860811659203066 0.84688041114363 62 | 1.87226228850301 1.05918154669777 0.864746543590537 63 | 1.90399554763018 1.16962794596152 0.887138699582877 64 | 1.93572880675735 1.13830956452807 0.910075157738183 65 | 1.96746206588452 0.961569394114677 0.929858568826388 66 | 1.99919532501169 0.694133679174779 0.944434119009573 67 | 2.03092858413886 0.434548920842658 0.954044619966624 68 | 2.06266184326603 0.290573948708607 0.96096136426066 69 | 2.0943951023932 0.336065996038858 0.96852287206426 70 | 2.12612836152037 0.57619815853813 0.98003791340682 71 | 2.15786162064753 0.93676484829281 0.99810505552935 72 | 2.1895948797747 1.28533448700998 1.02454193225372 73 | 2.22132813890187 1.47951265298658 1.06060326943004 74 | 2.25306139802904 1.42536883941618 1.10684843564777 75 | 2.28479465715621 1.12254160632591 1.16220528759937 76 | 2.31652791628338 0.675323800806639 1.22250710065267 77 | 2.34826117541055 0.261149608682448 1.27970081238523 78 | 2.37999443453772 0.0651893942008384 1.32338592619094 79 | 2.41172769366489 0.205181501352151 1.34572133629383 80 | 2.44346095279206 0.677149069842345 1.3488777127433 81 | 2.47519421191923 1.34644124121077 1.35174509541566 82 | 2.5069274710464 1.99115660561216 1.39088685861219 83 | 2.53866073017357 2.38328149334567 1.51131566896412 84 | 2.57039398930074 2.37629166501175 1.74643134896616 85 | 2.60212724842791 1.96446707724285 2.09278269899339 86 | 2.63386050755508 1.29122107250452 2.49179750358957 87 | 2.66559376668225 0.606607763283213 2.83371492539402 88 | 2.69732702580942 0.197494507366227 2.99543243517187 89 | 2.72906028493659 0.326229197750723 2.91279143394283 90 | 2.76079354406376 1.20800695541438 2.67140034494571 91 | 2.79252680319093 3.03494682171262 2.58429949684484 92 | 2.8242600623181 6.02609717335249 3.21714478477852 93 | 2.85599332144527 10.4616718240765 5.32824477435577 94 | 2.88772658057244 16.6589903548488 9.71320334417484 95 | 2.91945983969961 24.8704291845289 16.9770806240871 96 | 2.95119309882678 35.12231997822 27.2900835694326 97 | 2.98292635795395 47.0513870283924 40.2026836766585 98 | 3.01465961708111 59.8134504835002 54.5923610267935 99 | 3.04639287620828 72.1261151269873 68.7840851668034 100 | 3.07812613533545 82.4645072829572 80.8372141338038 101 | 3.10985939446262 89.3719538914169 88.9380934765578 102 | 3.14159265358979 91.7988165435977 91.7988165435977 103 | -------------------------------------------------------------------------------- /figures/PEC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/PEC.png -------------------------------------------------------------------------------- /figures/PEC_ratio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/PEC_ratio.png -------------------------------------------------------------------------------- /figures/_about.txt: -------------------------------------------------------------------------------- 1 | This file folder contains example output figures generated by the code. 2 | These are referenced in the readme.md file, along with code used to 3 | generate these plots. 4 | -------------------------------------------------------------------------------- /figures/bistatic_lossy_dielectric_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/bistatic_lossy_dielectric_example.png -------------------------------------------------------------------------------- /figures/compare_bistatic_frequencies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/compare_bistatic_frequencies.png -------------------------------------------------------------------------------- /figures/compare_bistatic_frequencies_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/compare_bistatic_frequencies_2.png -------------------------------------------------------------------------------- /figures/compare_bistatic_frequencies_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/compare_bistatic_frequencies_3.png -------------------------------------------------------------------------------- /figures/compare_bistatic_materials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/compare_bistatic_materials.png -------------------------------------------------------------------------------- /figures/coord_system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/coord_system.png -------------------------------------------------------------------------------- /figures/example_2_material_comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/example_2_material_comparison.png -------------------------------------------------------------------------------- /figures/figure2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/figure2.png -------------------------------------------------------------------------------- /figures/figure3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/figure3.png -------------------------------------------------------------------------------- /figures/lossy_dielectric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/lossy_dielectric.png -------------------------------------------------------------------------------- /figures/lossy_dielectric_mono_rcs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/lossy_dielectric_mono_rcs.png -------------------------------------------------------------------------------- /figures/perfect_dielectric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/perfect_dielectric.png -------------------------------------------------------------------------------- /figures/plot_from_file_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/plot_from_file_example.png -------------------------------------------------------------------------------- /figures/plot_from_file_example_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/plot_from_file_example_2.png -------------------------------------------------------------------------------- /figures/sigma_sweep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/sigma_sweep.png -------------------------------------------------------------------------------- /figures/sigma_sweep_kzhu_nmax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/sigma_sweep_kzhu_nmax.png -------------------------------------------------------------------------------- /figures/validation_with_mom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modelics/Python-Sphere-RCS/d0167085722502582cff3c92ba706321a43c4540/figures/validation_with_mom.png -------------------------------------------------------------------------------- /getDielectricSphereFieldUnderPlaneWave.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from DielectricMaterial import DielectricMaterial as DM 3 | from src import * 4 | from bessel import * 5 | from getNMax import * 6 | 7 | def getDielectricSphereFieldUnderPlaneWave(radius, sphere, background, sensor_location, frequency): 8 | ''' 9 | Calculate the field as a plane wave is scattered by a dielectric 10 | sphere centered at the origin. The incident plane wave is 11 | polarized in the +x direction propagating in the +z 12 | direction. 13 | 14 | Inputs: 15 | radius Scalar to denote the radius of the sphere (m) 16 | sphere Object of DielectricMaterial 17 | background Object of DielectricMaterial 18 | sensor_location 3x1 vector (m) 19 | frequency Nx1 vector (Hz) 20 | 21 | Outputs: 22 | E_r, E_phi, E_theta Nx1 vector (V/m) 23 | H_r, H_phi, H_theta Nx1 vector (A/m) 24 | 25 | ''' 26 | [r, theta, phi] = cartToSph(sensor_location[0],sensor_location[1],sensor_location[2]) 27 | 28 | # number of mie terms to evaluate 29 | #based off wiscombe recommendation 30 | N = getNMax(radius, sphere, background, frequency) 31 | #print("NMax: ", N) 32 | 33 | nu = np.arange(1,N+1,1) 34 | 35 | 36 | #need to convert frequency into numpy array 37 | if (type(frequency) == int or type(frequency) == float): 38 | frequency = [frequency] 39 | if (type(frequency) == list or type(frequency) == np.ndarray): 40 | frequency = np.array(frequency) 41 | frequency = frequency.flatten() 42 | M = len(frequency) 43 | else: 44 | print("wrong data type for frequency (in getDielectricSphereFieldUnderPlaneWave)") 45 | 46 | EPS_0 = 8.8541878176*1e-12 47 | MU_0 = 4*np.pi*1e-7 48 | 49 | #all these values are of class 'numpy.ndarray' 50 | eta_m = DM.getIntrinsicImpedance(background, frequency) 51 | k_m = DM.getWaveNumber(background, frequency) 52 | mu_m = DM.getComplexPermeability(background, frequency)*MU_0 53 | eps_m = DM.getComplexPermittivity(background, frequency)*EPS_0 54 | 55 | eta_s = DM.getIntrinsicImpedance(sphere, frequency) 56 | k_s = DM.getWaveNumber(sphere, frequency) 57 | mu_s = DM.getComplexPermeability(sphere, frequency)*MU_0 58 | eps_s = DM.getComplexPermittivity(sphere, frequency)*EPS_0 59 | 60 | #debugging prints 61 | ''' 62 | print(eta_m) 63 | print(k_m) 64 | print(mu_m) 65 | print(eps_m) 66 | 67 | print(eta_s) 68 | print(k_s) 69 | print(mu_s) 70 | print(eps_s) 71 | ''' 72 | 73 | 74 | a_n = np.ones((len(frequency), len(nu)), np.complex128) 75 | for c in range(0, len(nu)): 76 | n = nu[c] 77 | a_n[:,c] = (1j ** (-1*n)) * (2*n + 1) / (n * (n+1) ) 78 | 79 | #range iterates through same numbers 80 | #math n not modified, index n adjusted for python zero-indexing 81 | aux0 = np.zeros((len(nu), 1), np.complex128); 82 | aux0[0] = -1; 83 | aux0[1] = -3*np.cos(theta) 84 | for n in range(2, N): 85 | aux0[n] = (2*n+1)/n*np.cos(theta)*aux0[n-1] - (n+1)/n*aux0[n-2] 86 | 87 | aux1 = np.zeros((len(nu), 1), np.complex128); 88 | aux1[0] = np.cos(theta); 89 | for n in range(2, N+1): 90 | aux1[n-1] = (n+1)*aux0[n-2] -n*np.cos(theta)*aux0[n-1] 91 | 92 | aux0 = np.matmul(np.ones((len(frequency),1)),np.reshape(aux0, (1, len(aux0)))) 93 | aux1 = np.matmul(np.ones((len(frequency),1)),np.reshape(aux1, (1, len(aux1)))) 94 | 95 | #print("aux0:\n", aux0, "\naux1:\n", aux1) 96 | ''' 97 | x = k_m*r 98 | print("nu:\n",nu,"\nx:\n",x) 99 | print(ric_bessely_derivative(nu,x,1)) 100 | print("\nric_bessely(nu-1,x)):\n",ric_bessely(nu-1,x)) 101 | print("\nric_bessely(0,1)):\n",ric_bessely([0],[1])) 102 | ''' 103 | if r < radius: 104 | #not yet ready to transcribe this 105 | pass 106 | elif r > radius: 107 | ####calculating b_n series 108 | #num = + sqrt(mu_s.*eps_m)*ones(1,N).*transpose(ric_besselj(nu,k_m*radius)).*transpose(ric_besselj_derivative(nu,k_s*radius)) \ 109 | # - sqrt(mu_m.*eps_s)*ones(1,N).*transpose(ric_besselj(nu,k_s*radius)).*transpose(ric_besselj_derivative(nu,k_m*radius)) 110 | #den = + sqrt(mu_m.*eps_s)*ones(1,N).*transpose(ric_besselj(nu,k_s*radius)).*transpose(ric_besselh_derivative(nu,2,k_m*radius))... 111 | # - sqrt(mu_s.*eps_m)*ones(1,N).*transpose(ric_besselh(nu,2,k_m*radius)).*transpose(ric_besselj_derivative(nu,k_s*radius)); 112 | 113 | A = np.matmul( np.reshape(np.sqrt(mu_s*eps_m), (M,1)), np.ones((1,N))) 114 | B = np.transpose(ric_besselj(nu,k_m*radius)) 115 | C = np.transpose(ric_besselj_derivative(nu,k_s*radius)) 116 | 117 | #print(A, "\n\n", B, "\n\n", C, "\n\n") 118 | 119 | D = np.matmul( np.reshape(np.sqrt(mu_m*eps_s), (M,1)), np.ones((1,N))) 120 | E = np.transpose(ric_besselj(nu,k_s*radius)) 121 | F = np.transpose(ric_besselj_derivative(nu,k_m*radius)) 122 | num = A*B*C - D*E*F 123 | 124 | G = np.transpose(ric_besselh_derivative(nu, k_m*radius, 2,1)) 125 | H = np.transpose(ric_besselh(nu,k_m*radius,2)); 126 | den = D*E*G - A*H*C; 127 | 128 | b_n = (num/den)*a_n 129 | ####calculating b_n series 130 | num = A*E*F - D*B*C 131 | den = D*H*C - A*E*G 132 | c_n = (num/den)*a_n 133 | 134 | #print(k_m*radius) 135 | #print("b_n : \n", b_n, "\n\n", "c_n : \n", c_n) 136 | 137 | #cleaning the b_n, c_n matrices to remove inf, nan 138 | # that come after values become very small 139 | for i in range(1, M): 140 | num_zeros = 0 141 | for j in range(0,N): 142 | if (abs( b_n[i,j]) < 1e-300 ): 143 | num_zeros += 1 144 | if (num_zeros > 4): 145 | b_n[i, j:] = 0 146 | num_zeros = 0 147 | break 148 | for i in range(1, M): 149 | num_zeros = 0 150 | for j in range(0,N): 151 | if (abs( c_n[i,j]) < 1e-300 ): 152 | num_zeros += 1 153 | if (num_zeros > 4): 154 | b_n[i, j:] = 0 155 | num_zeros = 0 156 | break 157 | 158 | #alpha = ( transpose (ric_besselh_derivative (nu,2,x,2) ) +transpose(ric_besselh(nu,2,x)) )... 159 | # .*transpose( assoc_legendre(nu,1,cos(theta)) *ones(1,nFreq) ); 160 | x = k_m*r 161 | alpha00 = np.transpose(ric_besselh_derivative(nu,x,2,2)); 162 | alpha01 = np.transpose(ric_besselh(nu,x,2)); 163 | alpha10 = np.array(get_legendre(nu,1, np.cos(theta))) 164 | alpha11 = np.transpose( np.matmul( np.reshape(alpha10, (N,1)), np.ones((1,M)) ) ) 165 | alpha = (alpha00 + alpha01) * alpha11 166 | 167 | E_r = -1j * np.cos(phi) * np.sum( (b_n * alpha) , 1) 168 | H_r = -1j * np.sin(phi) * np.sum( (c_n * alpha), 1) / eta_m 169 | 170 | alpha = np.transpose(ric_besselh_derivative(nu,x,2))* aux1 171 | beta = np.transpose(ric_besselh(nu,x,2)) * aux0 172 | summation1 = 1j*b_n*alpha - c_n*beta 173 | summation2 = 1j*c_n*alpha - b_n*beta 174 | E_theta = (np.cos(phi)/ x) * np.sum(summation1,1) 175 | H_theta = (np.sin(phi)/x ) * np.sum(summation2,1) / eta_m 176 | 177 | #print(ric_besselh_derivative(nu,x,2)) 178 | #print(ric_besselj_derivative(nu,x,1)) 179 | #print(ric_bessely_derivative(nu,x,1)) 180 | #print("\n") 181 | #print(ric_bessely(nu,x,1)) 182 | #print("theta\nalpha:\n", alpha, "\nbeta:\n", beta) 183 | 184 | alpha = np.transpose(ric_besselh_derivative(nu,x,2)) * aux0 185 | beta = np.transpose(ric_besselh(nu,x,2)) * aux1; 186 | summation1 = 1j*b_n*alpha - c_n*beta 187 | summation2 = 1j*c_n*alpha - b_n*beta 188 | E_phi = (np.sin(phi)/x) * np.sum(summation1,1) 189 | H_phi = (-1* np.cos(phi)/x) * np.sum(summation2,1) / eta_m 190 | 191 | #print("phi\nalpha:\n", alpha, "\nbeta:\n", beta) 192 | 193 | #print("E_r:\n", E_r, "\nE_theta:\n", E_theta, "\nE_phi:\n", E_phi) 194 | #print("H_r:\n", H_r, "\nH_theta:\n", H_theta, "\nH_phi:\n", H_phi) 195 | 196 | return [E_r, E_theta, E_phi, H_r, H_theta, H_phi] 197 | 198 | 199 | if __name__ == '__main__': 200 | getDielectricSphereFieldUnderPlaneWave(0.5, DM(2.56,0.5), DM(1,0), [0,0,100], [1e6, 1e7, 1e8]) 201 | -------------------------------------------------------------------------------- /getNMax.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | from DielectricMaterial import DielectricMaterial as DM 4 | from src import * 5 | from bessel import * 6 | 7 | def getNMax(radius, sphere, background, frequency): 8 | ''' 9 | determines the appropriate number of mie terms to evaluate 10 | Based on the wiscombe 1980 recommendation (which was deternined through 11 | convergence behavior bessel functions at high orders that were 12 | calculated recursivelly). 13 | 14 | Designed to work for single-layered (monolithic) sphere. 15 | ''' 16 | #check that frequency input is correct 17 | if (type(frequency) == int or type(frequency) == float): 18 | frequency = np.array([frequency]) 19 | if (type(frequency) == list or type(frequency) == np.ndarray): 20 | frequency = np.array(frequency).flatten() 21 | M = len(frequency) 22 | else: 23 | print("wrong data type for frequency (in getNMax)") 24 | 25 | 26 | k_m = DM.getWaveNumber(background, frequency) 27 | x = abs(k_m * radius) 28 | #print(x) 29 | 30 | N_m = DM.getComplexRefractiveIndex(background, frequency) 31 | m = DM.getComplexRefractiveIndex(sphere, frequency) / N_m #relative refractive index 32 | 33 | N_max = np.ones((M,)) 34 | for k in range(0,M): 35 | if (x[k] < 0.02): 36 | print("WARNING: it is better to use Rayleigh Scattering models for low frequencies.") 37 | print("\tNo less than 3 Mie series terms will be used in this calculation") 38 | #this comes from Wiscombe 1980: for size parameter = 0.02 or less, the number of terms 39 | #recommended will be 3 or less. 40 | N_stop = 3 41 | elif (0.02 <= x[k] and x[k] <= 8): 42 | N_stop = x[k] + 4.*x[k]**(1/3) + 1 43 | elif (8 < x[k] and x[k] < 4200): 44 | N_stop = x[k] + 4.05*x[k]**(1/3) + 2 45 | elif (4200 <= x[k] and x[k] <= 20000): 46 | N_stop = x[k] + 4.*x[k]**(1/3) + 2 47 | else: 48 | print("WARNING: it is better to use Physical Optics models for high frequencies.") 49 | N_stop = 20000 + 4.*20000**(1/3) + 2 50 | 51 | #this is the KZHU original nmax formula (adapted for single sphere) 52 | #it recommends 100's of terms for real metals 53 | N_max[k] = max(N_stop, abs(m[k] * x[k]) )+15 54 | 55 | #this is the Wiscombe-only implementation, seems to be accurate enough 56 | #N_max[k] = N_stop 57 | 58 | return math.ceil(max(N_max)) 59 | 60 | 61 | if __name__ == "__main__": 62 | radius = 0.5 63 | #sphere = DM(5,100) 64 | sphere = DM(2.56,0.5) 65 | background = DM(1,0) 66 | frequency = np.logspace(5,9,5) 67 | print(frequency) 68 | print(getNMax(radius, sphere, background, frequency)) 69 | 70 | print(sphere.getComplexRefractiveIndex(1e9)) 71 | 72 | -------------------------------------------------------------------------------- /getRCS.py: -------------------------------------------------------------------------------- 1 | from getDielectricSphereFieldUnderPlaneWave import * 2 | from DielectricMaterial import * 3 | from src import * 4 | from TestCase import * 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | def RCS_vs_freq(radius, ratio, background_material, sphere_material, sensor_location, save_file=None, show_plot=1): 9 | ''' 10 | Calculates the RCS vs frequency for a sphere defined by 'radius' and 'sphere_material' 11 | located at the origin. The incident wavelengths are defined using argument 'ratio', 12 | where ratio is radius / wavelength. 13 | 14 | Saves the plot of RCS vs freqency along with the data as a text file to 'save_file'. 15 | 16 | ''' 17 | wavelength = radius / ratio 18 | frequency = background_material.getPhaseVelocity(3e8 / wavelength) / wavelength 19 | 20 | [E_r, E_theta, E_phi, H_r, H_theta, H_phi] = \ 21 | getDielectricSphereFieldUnderPlaneWave(radius, sphere_material, background_material, sensor_location, frequency) 22 | E = (np.stack((E_r,E_theta,E_phi), axis=0)) 23 | mono_RCS = 4*np.pi* ( norm(sensor_location)**2 ) * np.sum( (E * np.conj(E)) , 0) 24 | 25 | #plotting and saving plot 26 | if show_plot: 27 | plotOneMonoRCS(radius, sphere_material, background_material, mono_RCS, frequency=frequency, savefile = save_file) 28 | 29 | #writing mono RCS data to text file, if filename is given 30 | if save_file: 31 | saveMonoRCSData(save_file, mono_RCS, frequency, sphere_material, radius) 32 | 33 | return (frequency, mono_RCS) 34 | 35 | def Bistatic_RCS(radius, frequency, background_material, sphere_material, distance, phi, save_filename =None, show_plot = 1): 36 | ''' 37 | Calculates the bistatic RCS of a spherical object at the origin, defined by 38 | sphere (DielectricMaterial) and radius, at a certain frequency. 39 | 40 | Inputs: 41 | radius: radius of sphere (float, meters) 42 | frequency: frequency of incident wave (float, Hz) 43 | background_material: background medium (class DielectricMaterial) 44 | sphere_material: sphere material (class DielectricMaterial) 45 | distance: distance of observer from origin (float, meters) 46 | phi: angle of azimuth. 47 | save_filename: name of file to save the plot and data (string) 48 | 49 | Outputs: 50 | plot of bistatic RCS and the corresponding data. 51 | 52 | Notes: 53 | Assumes incident wave is travelling in the +z direction. 54 | Theta = pi is the radial direction to the source point. 55 | Plot saved as a .png file, data saved to .txt file. 56 | ''' 57 | nang = 100 58 | theta = np.linspace(0,np.pi,nang) 59 | #distance = 2000 60 | #phi = 0 61 | 62 | bi_RCS = np.zeros((nang,), np.complex128) 63 | for k in range(0,nang): 64 | sensor_location = sphToCart(distance, theta[k], phi) 65 | if (type(frequency) == int or type(frequency) == float): 66 | frequency = np.array([frequency]) 67 | 68 | [E_r, E_theta, E_phi, H_r, H_theta, H_phi] = \ 69 | getDielectricSphereFieldUnderPlaneWave(radius, sphere_material, background_material, sensor_location, frequency) 70 | E = (np.stack((E_r,E_theta,E_phi), axis=0)) 71 | bi_RCS[k] = 4*np.pi* ( norm(sensor_location)**2 ) * np.sum( (E * np.conj(E))) 72 | 73 | #plotting and saving plot 74 | if save_filename: 75 | save_file = save_filename + ".png" 76 | if show_plot: 77 | plotBiRCS(radius, sphere_material, frequency, bi_RCS, theta, savefile = save_filename) 78 | 79 | #writing mono RCS data to text file, if filename is given 80 | if save_filename: 81 | data_file = save_filename + ".txt" 82 | saveBiRCSData(data_file, bi_RCS, theta, frequency, sphere_material) 83 | 84 | return (theta,bi_RCS) 85 | 86 | def plotOneMonoRCS(radius, sphere, background, mono_RCS, *args, **kwargs): 87 | ''' 88 | Plots the monostatic RCS for a single test sphere. 89 | Option of saving plot to a file if specified. 90 | Can select different x-axis plotting presets: 91 | frequency (logarithmic) 92 | wavelength (logarigthmic) 93 | ratio (normal) 94 | 95 | example usage: 96 | sphere = DielectricMaterial(2.56,0.1, name="silicon") 97 | vacuum = DielectricMaterial(1,0) #background_material 98 | plotOneMonoRCS(radius, sphere, vacuum, my_mono_RCS_data, frequency = my_frequency_values) 99 | plotOneMonoRCS(radius, sphere, vacuum, my_mono_RCS_data, ratio = my_ratio, savefile = 'figure1.png') 100 | ''' 101 | frequency = np.atleast_1d(kwargs.get('frequency', [])) 102 | ratio = np.atleast_1d(kwargs.get('ratio', [])) 103 | wavelength = np.atleast_1d(kwargs.get('wavelength', [])) 104 | savefile = kwargs.get('savefile', '') 105 | 106 | if ( frequency.size > 0 ): 107 | xseries = frequency 108 | elif ( ratio.size > 0 ): 109 | xseries = ratio 110 | elif ( wavelength.size > 0 ): 111 | xseries = wavelength 112 | else: 113 | print("wrong input (in plotOneMonoRCS") 114 | return 115 | 116 | 117 | plt.grid(True, which="both", ls="--") 118 | plt.ylabel(r'Mono-Static RCS ($m^2$)') 119 | 120 | if ( frequency.size > 0 ): 121 | plt.loglog(xseries, mono_RCS) 122 | plt.xlabel("Frequency (Hz)") 123 | elif ( ratio.size > 0 ): 124 | plt.semilogy(xseries, mono_RCS) 125 | plt.xlabel("Sphere radius in wavelengths") 126 | elif ( wavelength.size > 0 ): 127 | plt.loglog(xseries, mono_RCS) 128 | plt.xlabel("Wavelength (m)") 129 | 130 | 131 | title_str = "" 132 | 133 | if (sphere.sigma_e == 0): 134 | material = "Perfect Dielectric" 135 | elif (sphere.sigma_e <= 1e4): 136 | material = "Lossy Dielectric" 137 | else: 138 | material = "Conductor" 139 | 140 | if sphere.name: 141 | material = sphere.name + " Sphere" 142 | title_str += material 143 | else: 144 | material_params = r'$\epsilon_r$ = ' + str(round(sphere.epsilon_r,2)) + \ 145 | r', $\mu_r$ = ' + str(round(sphere.mu_r,2)) + \ 146 | r', $\sigma$ = ' + "{0:.2f}".format(sphere.sigma_e) + " S/m" + \ 147 | ", radius = " + str(round(radius,2)) + " m" 148 | title_str += material + " (" + material_params + ")" 149 | 150 | if (background and background.name): 151 | title_str += " in " + background.name 152 | 153 | plt.title(title_str) 154 | 155 | if (savefile): 156 | if not (savefile.endswith(".png")): 157 | savefile += ".png" 158 | plt.savefig(savefile, dpi=80) 159 | plt.show() 160 | 161 | def plotBiRCS(radius, sphere, frequency, bi_RCS, theta, savefile =None): 162 | ''' 163 | plots the bistatic RCS for a spherical object, defined by 164 | sphere (DielectricMaterial) and radius, at a certain frequency. 165 | Saving the plot as an option. 166 | ''' 167 | fig, ax = plt.subplots() 168 | plt.semilogy(theta, bi_RCS) 169 | plt.grid(True, which="both", ls="--") 170 | 171 | plt.ylabel(r'Bi-Static RCS ($m^2$)') 172 | plt.xlabel(r'Angle $\theta$ (rad)') 173 | 174 | if (sphere.sigma_e == 0): 175 | material = "Perfect Dielectric" 176 | elif (sphere.sigma_e <= 1e4): 177 | material = "Lossy Dielectric" 178 | else: 179 | material = "Conductor" 180 | 181 | plt.title( "Bi-Static RCS for " + material + " Sphere at " + \ 182 | "{0:.2e}".format(frequency[0]) + " Hz \n(" + \ 183 | r' $\epsilon_r$ = ' + str(round(sphere.epsilon_r,2)) + \ 184 | r', $\mu_r$ = ' + str(round(sphere.mu_r,2)) + \ 185 | r', $\sigma$ = ' + '{:.2e}'.format(sphere.sigma_e) + " S/m" + \ 186 | ", radius = " + str(round(radius,2))+ " m)" ) 187 | 188 | if (savefile): 189 | plt.savefig(savefile, figsize=(8,6)) 190 | plt.show() 191 | 192 | def saveMonoRCSData(savefile, mono_RCS, frequency, sphere, radius): 193 | ''' 194 | Writes monostatic RCS data to a text file formatted as following. 195 | All data is delimited with tabs or newlines 196 | 197 | eps_r #### mu_r #### sigma #### 198 | frequency(Hz) RCS(m^2) 199 | ##### ##### 200 | ##### ##### 201 | ''' 202 | if (not savefile.endswith(".txt")): 203 | savefile += ".txt" 204 | data_file = open(savefile, "w") 205 | header_line = "eps_r\t" + str(round(sphere.epsilon_r,2))+ \ 206 | "\tmu_r\t" + str(round(sphere.mu_r,2)) + \ 207 | "\tsigma\t" + "{0:.2e}".format(sphere.sigma_e) + \ 208 | "\tradius\t" + str(round(radius,2)) + "\n" 209 | data_file.write(header_line) 210 | 211 | column_headers = "frequency(Hz)\tRCS(m^2)\n" 212 | data_file.write(column_headers) 213 | 214 | mono_RCS = mono_RCS.flatten() 215 | frequency = frequency.flatten() 216 | n = min(len(frequency), len(mono_RCS)) 217 | 218 | for i in range(0,n): 219 | line = "{:.9e}".format(frequency[i]) + "\t" + "{:.9e}".format(np.real(mono_RCS[i])) + "\n" 220 | data_file.write(line) 221 | 222 | data_file.close() 223 | 224 | def saveBiRCSData(savefile, bi_RCS, theta, frequency, sphere): 225 | ''' 226 | Writes bistatic RCS data to a text file formatted as following. 227 | All data is delimited with tabs or newlines 228 | 229 | freq(Hz) #### eps_r #### mu_r #### sigma #### 230 | theta(rad) RCS(m^2) 231 | ##### ##### 232 | ##### ##### 233 | ''' 234 | if (not savefile.endswith(".txt")): 235 | savefile += ".txt" 236 | 237 | if (type(frequency) == list or type(frequency) == np.ndarray): 238 | frequency = np.array(frequency).flatten() 239 | frequency = float(frequency[0]) 240 | 241 | 242 | data_file = open(savefile, "w") 243 | header_line = "freq(Hz)\t" + "{0:.2e}".format(frequency) + \ 244 | "\teps_r\t" + str(round(sphere.epsilon_r,2))+ \ 245 | "\tmu_r\t" + str(round(sphere.mu_r,2)) + \ 246 | "\tsigma\t" + "{0:.2e}".format(sphere.sigma_e) + "\n" 247 | data_file.write(header_line) 248 | 249 | column_headers = "theta(rad)\tRCS(m^2)\n" 250 | data_file.write(column_headers) 251 | 252 | bi_RCS = np.reshape(bi_RCS, (bi_RCS.size,1)).flatten() 253 | theta = np.reshape(theta, (theta.size,1)).flatten() 254 | n = min(theta.size, bi_RCS.size) 255 | 256 | for i in range(0,n): 257 | line = "{:.9e}".format(theta[i]) + "\t" + "{:.9e}".format(np.real(bi_RCS[i])) + "\n" 258 | data_file.write(line) 259 | 260 | data_file.close() 261 | 262 | def convertToRatio(radius, background_material, *args, **kwargs): 263 | ''' 264 | given a sphere's radius and background_material 265 | convert from frequency or wavelength to ratio 266 | return the ratio. 267 | 268 | Inputs: 269 | radius: scalar 270 | background_material: of DIelectricMaterial class 271 | frequency: numpy array 272 | wavelength: numpy array 273 | 274 | Example: 275 | input_freq = np.logspace(1,3,100) 276 | vacuum = DielectricMaterial(1,0) 277 | ratio = convertToRatio(1, vacuum, frequency = input_freq ) 278 | ''' 279 | c = 299792458 #speed of light 280 | freq = kwargs.get('frequency', 'None') 281 | lambd = kwargs.get('wavelength', 'None') 282 | rat = kwargs.get('ratio', 'None') 283 | if (type(rat) is not str): 284 | return rat 285 | if (type(freq) is not str): 286 | return freq*(radius / (background_material.getPhaseVelocity(freq)) ) 287 | if (type(lambd) is not str): 288 | return radius / lambd 289 | 290 | def Compare_RCS_vs_freq(test_cases, test_parameters, save_file = None): 291 | ''' 292 | Plots several different monostatic RCS vs frequency series on the same figure. 293 | 294 | Inputs: 295 | test_cases: list of TestCase objects which define 296 | sphere and background material, sphere radius 297 | test_parameters: an object of TestParameters class 298 | which contains information specific to the test 299 | such as frequency and sensor position 300 | save_file: filename to which to save the plot (optional) 301 | ''' 302 | fig, ax = plt.subplots() 303 | legend_entries = [] 304 | for case in test_cases: 305 | #calcilating mono RCS as usual 306 | [E_r, E_theta, E_phi, H_r, H_theta, H_phi] = \ 307 | getDielectricSphereFieldUnderPlaneWave(case.radius, case.sphere_material, case.background_material, \ 308 | test_parameters.sensor_location, test_parameters.frequency) 309 | E = (np.stack((E_r,E_theta,E_phi), axis=0)) 310 | mono_RCS = 4*np.pi* ( norm(test_parameters.sensor_location)**2 ) * np.sum( (E * np.conj(E)) , 0) 311 | 312 | #print(mono_RCS) 313 | #print(test_parameters.frequency) 314 | #plotting as usual 315 | plt.loglog(test_parameters.frequency, mono_RCS) 316 | 317 | series_name = "Sphere" 318 | if case.sphere_material.name: 319 | series_name = case.sphere_material.name + " " + series_name 320 | else: 321 | series_name += r'($\epsilon_r$ = ' + str(round(case.sphere_material.epsilon_r,2)) + \ 322 | r', $\sigma$ = ' + "{0:.2f}".format(case.sphere_material.sigma_e) + " S/m)" 323 | if case.background_material.name: 324 | series_name += " in " + case.background_material.name 325 | 326 | legend_entries.append(series_name) 327 | 328 | plt.grid(True, which="both", ls="--") 329 | 330 | plt.ylabel(r'Mono-Static RCS ($m^2$)') 331 | plt.xlabel("Frequency (Hz)") 332 | plt.legend(legend_entries, loc='best') 333 | plt.title("Monostatic RCS Comparison for Different Materias") 334 | 335 | if (save_file): 336 | save_filename = save_file + ".png" 337 | plt.savefig(save_filename, figsize=(8,6)) 338 | plt.show() 339 | 340 | def Compare_Bistatic_RCS(test_cases, test_parameters, save_file = None): 341 | ''' 342 | Plots the RCS versus angle from theta = 0 to pi 343 | Inputs: 344 | test_cases: array of TestCase objects, length of array >=1 345 | *The various spheres (with different radius, 346 | material for example) are specified within 347 | test_cases (class TestCase) 348 | 349 | test_parameters: a single TestParameters object. 350 | *The frequency, radius, and angle of azimuth phi 351 | are specified within test_parameters 352 | (class TestParameters) 353 | save_file: a string denoting filename of resulting plot. 354 | *Plot will be automatically saved in ".png" format 355 | *If save_file not given, won't save (it is optional) 356 | Notes: 357 | * If one TestCase is given and test_parameter has only one frequency, 358 | the code returns the same plot as plotBiRCS() 359 | * If multiple TestCase objects are given within test_cases and 360 | test_parameters has one frequency, 361 | the code returns bistatic RCS of multiple spheres at one frequency 362 | * If one TestCase is given and test_parameter has multiple frequencies, 363 | the code performs comparison for same sphere at various frequencies 364 | 365 | Example Usage: 366 | vacuum = DielectricMaterial(1,0) 367 | case1 = TestCase(0.5, DielectricMaterial(2.56,0), vacuum) 368 | case2 = TestCase(0.5, DielectricMaterial(2.56,0.1, name = "Silicon"), vacuum) 369 | 370 | distance = 2000 371 | phi = np.pi/2 372 | sensor_location = cartToSph(distance, theta=0, phi) 373 | frequency = 1e9 374 | param1 = TestParameters(sensor_location, frequency) 375 | 376 | Compare_RCS_vs_freq([case1,case2], param1, "two_material_comparison_example") 377 | ''' 378 | #checking the frequency input 379 | frequency = test_parameters.frequency 380 | if (type(frequency) == int or type(frequency) == float): 381 | frequency = np.array([frequency]) 382 | if (type(frequency) == list or type(frequency) == np.ndarray): 383 | frequency = np.array(frequency).flatten() 384 | 385 | #just a single bistatic RCS plot 386 | if (len(test_cases) == 1 and frequency.size == 1 ): 387 | print("\tCompare_Bistatic_RCS cases 1, frequency 1") 388 | case = test_cases[0] 389 | param = test_parameters[0] 390 | radius = case.radius 391 | background = case.background_material 392 | sphere = case.sphere_material 393 | sphere_location = param.sensor_location 394 | frequency = param.frequency 395 | 396 | [distance, theta, phi] = sphToCart(sensor_location) 397 | #generate RCS vs theta data 398 | (theta, bi_RCS) = Bistatic_RCS(radius, frequency, background, sphere, distance, phi, save_filename =None, show_plot=0) 399 | # plot the data 400 | plotBiRCS(radius, sphere, frequency, bi_RCS, theta, savefile =save_file) 401 | 402 | #multiple spheres, one frequency 403 | if (len(test_cases) >= 1 and frequency.size == 1): 404 | print("\tCompare_Bistatic_RCS cases many, frequency 1") 405 | fig, ax = plt.subplots() 406 | legend_entries = [] 407 | 408 | for case in test_cases: 409 | radius = case.radius 410 | background = case.background_material 411 | sphere = case.sphere_material 412 | 413 | x = test_parameters.sensor_location[0] 414 | y = test_parameters.sensor_location[1] 415 | z = test_parameters.sensor_location[2] 416 | [distance, phi, theta] = cartToSph(x,y,z) 417 | 418 | (theta, bi_RCS) = Bistatic_RCS(radius, frequency, background, sphere, distance, phi, show_plot=0) 419 | plt.semilogy(theta, bi_RCS) 420 | 421 | series_name = "Sphere" 422 | if case.sphere_material.name: 423 | series_name = case.sphere_material.name + " " + series_name 424 | else: 425 | series_name += r'($\epsilon_r$ = ' + str(round(case.sphere_material.epsilon_r,2)) + \ 426 | r', $\sigma$ = ' + "{0:.2f}".format(case.sphere_material.sigma_e) + " S/m)" 427 | if case.background_material.name: 428 | series_name += " in " + case.background_material.name 429 | 430 | legend_entries.append(series_name) 431 | 432 | plt.ylabel(r'Bi-Static RCS ($m^2$)') 433 | plt.xlabel(r'Angle $\theta$ (rad)') 434 | plt.grid(True, which="both", ls="--") 435 | 436 | plt.legend(legend_entries, loc='best') 437 | plt.title("Bistatic RCS Comparison for Different Materias at " + "{0:.2e}".format(frequency[0]) + " Hz") 438 | 439 | if (save_file): 440 | save_filename = save_file + ".png" 441 | plt.savefig(save_filename) 442 | plt.show() 443 | 444 | #one sphere, multiple frequency 445 | elif(len(test_cases) == 1 and frequency.size > 1): 446 | print("\tCompare_Bistatic_RCS cases 1, frequency many") 447 | case = test_cases[0] 448 | radius = case.radius 449 | background = case.background_material 450 | sphere = case.sphere_material 451 | 452 | x = test_parameters.sensor_location[0] 453 | y = test_parameters.sensor_location[1] 454 | z = test_parameters.sensor_location[2] 455 | [distance, phi, theta] = cartToSph(x,y,z) 456 | 457 | fig, ax = plt.subplots() 458 | legend_entries = [] 459 | 460 | for k in range(frequency.size): 461 | #print("frequency: " , frequency) 462 | #print("frequency[k]: ", frequency[k], type(frequency[k])) 463 | (theta, bi_RCS) = Bistatic_RCS(radius, frequency[k:k+1], background, sphere, distance, phi, show_plot=0) 464 | plt.semilogy(theta, bi_RCS) 465 | 466 | series_name = "Sphere" 467 | if case.sphere_material.name: 468 | series_name = case.sphere_material.name + " " + series_name 469 | else: 470 | series_name += r'($\epsilon_r$ = ' + str(round(case.sphere_material.epsilon_r,2)) + \ 471 | r', $\sigma$ = ' + "{0:.2f}".format(case.sphere_material.sigma_e) + " S/m)" 472 | if case.background_material.name: 473 | series_name += " in " + case.background_material.name 474 | series_name += " at "+ "{0:.2e}".format(frequency[k]) + " Hz" 475 | 476 | legend_entries.append(series_name) 477 | 478 | plt.ylabel(r'Bi-Static RCS ($m^2$)') 479 | plt.xlabel(r'Angle $\theta$ (rad)') 480 | plt.grid(True, which="both", ls="--") 481 | 482 | plt.legend(legend_entries, loc='best') 483 | plt.title("Bistatic RCS Comparison for Different Frequencies") 484 | 485 | if (save_file): 486 | save_filename = save_file + ".png" 487 | plt.savefig(save_filename) 488 | plt.show() 489 | 490 | #extra: catching errors 491 | elif (len(test_cases) > 1 and frequency.size > 1): 492 | print("inputs not supported") 493 | else: 494 | print("error in compare_bistatic_rcs") 495 | 496 | def plotFromFile(filenames, plt_type, save_file=''): 497 | ''' 498 | Reads RCS data from filenames and displays on the same plot. 499 | 500 | Inputs: 501 | filenames: a list of strings. strings are the file name 502 | of the RCS data with file extension ".txt" 503 | plt_type: string. if type = 'bi' or 'bistatic', returns 504 | bistatic RCS plot. otherwise, if 'mono', or 505 | 'monostatic', returns monostatic plot. 506 | save_file: If given, saves plot to this filename as png 507 | 508 | Note: 509 | * Data files are assumed to be in the same format as this 510 | code exports. See saveMonoRCSData() and saveBiRCSData() 511 | for details. 512 | ''' 513 | plt_type = plt_type.replace(" ", "").lower() 514 | 515 | if (plt_type == 'mono' or plt_type == 'monostatic'): 516 | fig, ax = plt.subplots() 517 | legend_entries = [] 518 | 519 | for filename in filenames: 520 | data_file = open(filename, "r") 521 | line_1 = data_file.readline() 522 | # line 1: 523 | #eps_r 2.56 mu_r 1 sigma 3.00e-02 524 | [eps_r, mu_r, sigma, radius] = line_1.split()[1::2] 525 | sphere = DielectricMaterial(float(eps_r), float(sigma), float(mu_r),0) 526 | radius = float(radius) 527 | 528 | #skip next line which is column header 529 | #frequency(Hz) RCS(m^2) 530 | data_file.readline() 531 | 532 | frequency, monoRCS = [],[] 533 | lines = data_file.readlines() 534 | for line in lines: 535 | values = line.split() 536 | frequency.append(float(values[0])) 537 | monoRCS.append(float(values[1])) 538 | 539 | frequency = np.array(frequency).flatten() 540 | monoRCS = np.array(monoRCS).flatten() 541 | data_file.close() 542 | 543 | #print("frequency: \n", frequency) 544 | #print("\nmonoRCS: \n", monoRCS) 545 | #print("\n just before plot") 546 | 547 | plt.loglog(frequency, monoRCS) 548 | 549 | series_name = "" 550 | if sphere.name: 551 | material = sphere.name 552 | series_name += material + "radius = " + str(round(radius,2)) + " m)" 553 | else: 554 | descriptor = r'($\epsilon_r$ = ' + str(round(sphere.epsilon_r,2)) + \ 555 | r', $\sigma$ = ' + "{0:.2f}".format(sphere.sigma_e) + " S/m" + \ 556 | ", radius = " + str(round(radius,2)) + " m)" 557 | series_name += descriptor 558 | 559 | legend_entries.append(series_name) 560 | 561 | plt.grid(True, which="both", ls="--") 562 | plt.ylabel(r'Mono-Static RCS ($m^2$)') 563 | plt.xlabel("Frequency (Hz)") 564 | plt.legend(legend_entries, loc='best') 565 | plt.title("Monostatic RCS Comparison for Different Materias") 566 | 567 | if save_file: 568 | save_file += ".png" 569 | plt.savefig(save_file, figsize=(8,6)) 570 | plt.show() 571 | 572 | elif (plt_type == 'bi' or plt_type == 'bistatic'): 573 | fig, ax = plt.subplots() 574 | legend_entries = [] 575 | 576 | for filename in filenames: 577 | data_file = open(filename, "r") 578 | line_1 = data_file.readline() 579 | # line 1: 580 | #eps_r 2.56 mu_r 1 sigma 3.00e-02 581 | [frequency, eps_r, mu_r, sigma] = line_1.split()[1::2] 582 | sphere = DielectricMaterial(float(eps_r), float(sigma), float(mu_r),0) 583 | frequency = float(frequency) 584 | 585 | #skip next line which is column header 586 | #frequency(Hz) RCS(m^2) 587 | data_file.readline() 588 | 589 | theta, biRCS = [],[] 590 | lines = data_file.readlines() 591 | for line in lines: 592 | values = line.split() 593 | theta.append(float(values[0])) 594 | biRCS.append(float(values[1])) 595 | 596 | theta = np.array(theta).flatten() 597 | biRCS = np.array(biRCS).flatten() 598 | data_file.close() 599 | 600 | #print("theta: \n", theta) 601 | #print("\nbiRCS: \n", biRCS) 602 | #print("\n just before plot") 603 | 604 | plt.semilogy(theta, biRCS) 605 | 606 | series_name = "" 607 | if sphere.name: 608 | material = sphere.name 609 | series_name += material #+ "radius = " + str(round(radius,2)) + " m)" 610 | else: 611 | descriptor = r'Sphere ($\epsilon_r$ = ' + str(round(sphere.epsilon_r,2)) + \ 612 | r', $\sigma$ = ' + "{0:.2f}".format(sphere.sigma_e) + " S/m)" +\ 613 | " at " + "{0:.2e}".format(frequency) + "Hz" 614 | #", radius = " + str(round(radius,2)) + " m)" 615 | series_name += descriptor 616 | 617 | legend_entries.append(series_name) 618 | 619 | plt.grid(True, which="both", ls="--") 620 | plt.ylabel(r'Bi-Static RCS ($m^2$)') 621 | plt.xlabel(r'Angle $\theta$ (rad)') 622 | plt.legend(legend_entries, loc='best') 623 | plt.title("Bistatic RCS Comparison from Data Files") 624 | 625 | if save_file: 626 | save_file += ".png" 627 | plt.savefig(save_file, figsize=(8,6)) 628 | plt.show() 629 | else: 630 | print("incorrect plt_type input to plotFromFile()") 631 | 632 | 633 | if __name__ == '__main__': 634 | 635 | ''' 636 | radius = 0.5 #meters 637 | ratio = np.arange(0.01,1.61,0.01) 638 | wavelength = radius / ratio 639 | 640 | background = DielectricMaterial(1,0) 641 | frequency = background.getPhaseVelocity(3e8 / wavelength) / wavelength 642 | 643 | sensor_location = [0,0,-1000] 644 | sphere = DielectricMaterial(2.56, 0.0) 645 | sphere = DielectricMaterial(1e8,0,1e-8,0) 646 | 647 | [E_r, E_theta, E_phi, H_r, H_theta, H_phi] = \ 648 | getDielectricSphereFieldUnderPlaneWave(radius, sphere, background, sensor_location, frequency) 649 | E = (np.stack((E_r,E_theta,E_phi), axis=0)) 650 | mono_RCS = 4*np.pi* ( norm(sensor_location)**2 ) * np.sum( (E * np.conj(E)) , 0) 651 | ''' 652 | 653 | 654 | #print(mono_RCS) 655 | 656 | #plotOneMonoRCS(radius, sphere, background, mono_RCS, ratio = ratio, savefile="PEC_ratio") 657 | 658 | #(theta, bi_RCS) = Bistatic_RCS(radius, 1e9, background, sphere, 2000, 0, show_plot=0) 659 | #saveBiRCSData("bistatic_perfect_dielectric_example", bi_RCS, theta, 1e9, sphere) 660 | 661 | #print(convertToRatio(radius, background, wavelength = wavelength)) 662 | 663 | #print(background.name) 664 | 665 | #testing sigma sweep, or material comparison 666 | ''' 667 | case1 = TestCase(0.5, DielectricMaterial(2.56,0), DielectricMaterial(1,0)) 668 | case2 = TestCase(0.5, DielectricMaterial(2.56,0.1, name = "Silicon"), DielectricMaterial(1,0)) 669 | param1 = TestParameters([0,0,-2000], np.logspace(7,9,100)) 670 | Compare_RCS_vs_freq([case1,case2], param1, "example_2_material_comparison") 671 | ''' 672 | 673 | #testing PEC sphere 674 | #(freq, mono_RCS) = RCS_vs_freq(radius = 0.5, ratio = np.arange(0.01,1.61,0.01), background_material = DielectricMaterial(1,0), sphere_material = DielectricMaterial(1e8,0,1e-8,0), sensor_location = [0,0,-2000], save_file = None, show_plot = 1) 675 | 676 | #testing plot with ratio on x axis 677 | ''' 678 | radius = 0.5 #meters 679 | ratio = np.arange(0.01,1.61,0.01) 680 | background = DielectricMaterial(1,0) 681 | sphere_material = DielectricMaterial(2.56,0.003) 682 | sensor_location = [0,0,-2000] 683 | 684 | (freq, mono_RCS) = RCS_vs_freq(radius, ratio, background, sphere_material, \ 685 | sensor_location , save_file = 'PEC', show_plot = 0) 686 | plotOneMonoRCS(radius, sphere_material, background, mono_RCS, ratio = ratio, \ 687 | savefile = "lossy_dielectric_mono_rcs") 688 | ''' 689 | 690 | #testing perfect dieelctric sphere 691 | #RCS_vs_freq(radius = 0.5, ratio = np.arange(0.01,1.61,0.01), background_material = DielectricMaterial(1,0), sphere_material = DielectricMaterial(2.56,0), sensor_location = [0,0,-2000], save_file = 'perfect_dielectric') 692 | 693 | #testing lossy dielectric sphere 694 | #RCS_vs_freq(radius = 0.5, ratio = np.arange(0.01,1.61,0.01), background_material = DielectricMaterial(1,0), sphere_material = DielectricMaterial(2.56,0.03), sensor_location = [0,0,-2000], save_file = 'lossy_dielectric') 695 | 696 | #stress-testing getNMax function: full sigma sweep 697 | ''' 698 | #auto-generating test cases from list of conductivities 699 | vacuum = DielectricMaterial(1,0) 700 | radius = 0.5 701 | conductivities = [0, 1e-5, 1e-3, 1e-2, 1e0, 1e3, 1e6] 702 | names = ["0", "1e-5", "1e-3", "1e-2", "1e0", "1e3", "1e6"] 703 | #conductivities = [0,1e0,1e6] 704 | #names = ["0", "1e0", "1e6"] 705 | eps_r = 2.56 706 | mu_r = 1 707 | cases = [] 708 | for i in range(0, len(conductivities)): 709 | sphere = DielectricMaterial(eps_r, conductivities[i], mu_r, name = names[i]) 710 | test_case = TestCase(radius, sphere, vacuum) 711 | cases.append(test_case) 712 | 713 | #formalizing test parameters 714 | sensor_location = [0,0,-2000] 715 | frequency = np.logspace(7,9,1000) 716 | param1 = TestParameters(sensor_location, frequency) 717 | 718 | Compare_RCS_vs_freq(cases, param1, save_file = "sigma_sweep") 719 | ''' 720 | 721 | #testing Compare_Bistatic_RCS 722 | ''' 723 | vacuum = DielectricMaterial(1,0) 724 | radius = 0.5 725 | sphere1 = DielectricMaterial(2.56,0, 1,0, name = "Loss-less") 726 | sphere2 = DielectricMaterial(2.56,1, 1,0, name = "Lossy") 727 | test_cases = [TestCase(radius, sphere1, vacuum), TestCase(radius, sphere2, vacuum)] 728 | 729 | sensor_location = [0,0,-2000] 730 | frequency = 1e9 731 | test_parameters = TestParameters(sensor_location, frequency) 732 | 733 | #bistatic RCS for two spheres, one frequency 734 | # Compare_Bistatic_RCS(test_cases, test_parameters, save_file = "compare_bistatic_materials") 735 | 736 | #bistatic RCS for one sphere, two frequencies 737 | vacuum = DielectricMaterial(1,0) 738 | radius = 0.5 739 | sphere3 = DielectricMaterial(2.56,3.3, 1,0, name = "Lossy") 740 | test_cases = [TestCase(radius, sphere3, vacuum)] 741 | 742 | sensor_location = [0,0,-2000] 743 | frequency = [1e9, 3e9, 5e9] 744 | test_parameters = TestParameters(sensor_location, frequency) 745 | 746 | Compare_Bistatic_RCS(test_cases, test_parameters, save_file = "compare_bistatic_frequencies") 747 | ''' 748 | 749 | 750 | #DEFAULT PLOTTING CODE 751 | ''' 752 | plt.loglog(frequency,mono_RCS) 753 | plt.grid(True, which="both", ls="--") 754 | 755 | plt.ylabel(r'Mono-Static RCS ($m^2$)') 756 | plt.xlabel("Frequency (Hz)") 757 | 758 | if (sphere.sigma_e == 0): 759 | material = "Perfect Dielectric" 760 | elif (sphere.sigma_e <= 1e4): 761 | material = "Lossy Dielectric" 762 | else: 763 | material = "Conductor" 764 | 765 | plt.title(material + r' $\epsilon_r$ = ' + str(round(sphere.epsilon_r,2)) + \ 766 | r', $\mu_r$ = ' + str(round(sphere.mu_r,2)) + \ 767 | r', $\sigma$ = ' + "{0:.2f}".format(sphere.sigma_e) + " S/m" + \ 768 | ", radius = " + str(round(radius,2)) + " m" ) 769 | plt.show() 770 | ''' 771 | 772 | #testing plot from file 773 | #plotFromFile(['lossy_dielectric.txt', 'perfect_dielectric.txt'], 'monostatic', save_file='plot_from_file_example') 774 | #plotFromFile(['bistatic_lossy_dielectric_example.txt', "bistatic_perfect_dielectric_example.txt"], 'bi', save_file='plot_from_file_example_2') 775 | 776 | #validating with MoM Solver Results 777 | ''' 778 | radius = 0.5 779 | frequency = 1000000000 780 | background = DielectricMaterial(1,0) 781 | sphere = DielectricMaterial(2,1000) 782 | distance = 2000 783 | phi = 0 784 | 785 | Bistatic_RCS(radius, frequency, background, sphere, distance, phi, save_filename ="calculations", show_plot = 0) 786 | plotFromFile(['sigma1e3_eaefie_bRCS_f_1000000000_Hz.txt', 'calculations.txt'], 'bi') 787 | ''' 788 | #old debugging inputs 789 | ''' 790 | radius = 0.5; 791 | sphere = DielectricMaterial(2.56,0.5) 792 | background = DielectricMaterial(1,0) 793 | sensor_location = [0,0,100]; 794 | frequency = [1e6, 1e7, 1e8] 795 | ''' -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2021 Iliya Shofman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 4 | software and associated documentation files (the "Software"), to deal in the Software 5 | without restriction, including without limitation the rights to use, copy, modify, 6 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 7 | permit persons to whom the Software is furnished to do so, subject to the following 8 | conditions: 9 | 10 | 11 | (1) The above copyright notice and this permission notice shall be included in all copies 12 | or substantial portions of the Software. 13 | 14 | (2) If scientific work derived from or using the Software is published, the authors must 15 | cite the Copyright Holders as follows: 16 | 17 | I. Shofman, D. Marek, S. Sharma, P. Triverio, "Python Sphere RCS: An Open-Source 18 | Library for Computing Radar Cross Section of Lossy Dielectric Spheres.", 2021. 19 | 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 22 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 23 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 26 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /misc/MATLAB_Sphere_scattering_license.txt: -------------------------------------------------------------------------------- 1 | This code is based on the MATLAB "Sphere scattering" authored by Kevin Zhu. 2 | The original license notice is reproduced below. Redistribution of this 3 | library with and without modifications is permitted as long as 4 | 5 | (1) the copyright notice (below) is included, 6 | (2) the authors of the work are cited as follows: 7 | G. Kevin Zhu (2021). Sphere scattering, MATLAB Central File Exchange. 8 | (https://www.mathworks.com/matlabcentral/fileexchange/31119-sphere-scattering) 9 | I. Shofman, D. Marek, S. Sharma, P. Triverio, Python Sphere RCS, 10 | (https://github.com/modelics/Sphere-RCS/) 11 | 12 | 13 | ---------- 14 | From Matlab File Exchange, Sphere scattering. 15 | (https://www.mathworks.com/matlabcentral/fileexchange/31119-sphere-scattering) 16 | 17 | Copyright (c) 2011, Kevin Zhu 18 | All rights reserved. 19 | 20 | Redistribution and use in source and binary forms, with or without 21 | modification, are permitted provided that the following conditions are met: 22 | 23 | * Redistributions of source code must retain the above copyright notice, this 24 | list of conditions and the following disclaimer. 25 | 26 | * Redistributions in binary form must reproduce the above copyright notice, 27 | this list of conditions and the following disclaimer in the documentation 28 | and/or other materials provided with the distribution 29 | * Neither the name of nor the names of its 30 | contributors may be used to endorse or promote products derived from this 31 | software without specific prior written permission. 32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 33 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 36 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 38 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 39 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 40 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | -------------------------------------------------------------------------------- /output/about.txt: -------------------------------------------------------------------------------- 1 | This folder will contain the plot and data produced by the `run_diagnostic.py` file. 2 | -------------------------------------------------------------------------------- /paper.bib: -------------------------------------------------------------------------------- 1 | @book{Bohren-Huffman:1983, 2 | Author = {{Bohren}, C. and {Huffman}, D.}, 3 | Booktitle = {Absorption and Scattering of Light by Small Particles: by Craig Bohren and Donald Huffman.~ISBN 0-471-29340-7.~Published by John Wiley & Sons, 1983.}, 4 | Publisher = {John Wiley & Sons}, 5 | Title = {{Absorption and Scattering of Light by Small Particles}}, 6 | Year = 1983 7 | } 8 | 9 | @book{Balanis:1989, 10 | Author = {{Balanis}, C.}, 11 | Booktitle = {Advanced Engineering Electromagnetics: by Constantine A. Balanis.~ISBN 0471621943.~Published by John Wiley & Sons, 1989.}, 12 | Publisher = {John Wiley & Sons}, 13 | Title = {{Advanced Engineering Electromagnetics}}, 14 | Year = 1989 15 | } 16 | 17 | @book{Abramowitz-Stegun:1964, 18 | Author = {{Abramowitz}, M. and {Stegun}, I.}, 19 | Booktitle = {Handbook of Mathematical Functions With Formulas, Graphs, and Mathematical Tables. ~Edited by Milton Abramowitz and Irene A. Stegun.~ISBN 9780486612720.~Published by United States Department of Commerce, National Bureau of Standards 1964.}, 20 | Publisher = {John Wiley & Sons}, 21 | Title = {{Handbook of Mathematical Functions With Formulas, Graphs, and Mathematical Tables.}}, 22 | Year = 1964 23 | } 24 | 25 | @article{Convergence-Mie-Series, 26 | author = {Allardice, J. R., & Le Ru, E. C.}, 27 | title = "{Convergence of Mie theory series: criteria for far-field and near-field properties}", 28 | journal = {Applied Optics}, 29 | archivePrefix = "Appl. Opt.", 30 | year = 2014, 31 | volume = 53, 32 | doi = {doi:10.1364/ao.53.007224}, 33 | url = {https://www.osapublishing.org/ao/abstract.cfm?uri=ao-53-31-7224}, 34 | } 35 | 36 | @article{Wiscombe-1980, 37 | author = {{W. J. Wiscombe}}, 38 | title = "{Improved Mie scattering algorithms}", 39 | journal = {Apploed Optics}, 40 | archivePrefix = "Appl. Opt.", 41 | year = 1980, 42 | volume = 19, 43 | doi = {doi.org/10.1364/AO.19.001505}, 44 | url = {https://www.osapublishing.org/ao/fulltext.cfm?uri=ao-19-9-1505&id=23949} 45 | } 46 | 47 | @misc{MATLAB-Sphere-Scattering, 48 | author = {G. K. Zhu}, 49 | title = {Sphere scattering}, 50 | year = {2020}, 51 | publisher = {MATLAB Central File Exchange}, 52 | url = {https://www.mathworks.com/matlabcentral/fileexchange/31119-sphere-scattering} 53 | } -------------------------------------------------------------------------------- /paper.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Python Sphere RCS: a Library to Compute Mie Series Scattering of Lossy Dielectric Spheres' 3 | tags: 4 | - Python 5 | - computational electromagnetics 6 | - mie series 7 | - scattering 8 | - dielectric spheres 9 | - Radar Cross Section 10 | authors: 11 | - name: Iliya Shofman # note this makes a footnote saying 'co-first author' 12 | orcid: 0000-0003-1798-8337 13 | affiliation: 1 # (Multiple affiliations must be quoted) 14 | - name: Damian Marek # note this makes a footnote saying 'co-first author' 15 | affiliation: 1 16 | - name: Shashwat Sharma # note this makes a footnote saying 'co-first author' 17 | affiliation: 1 18 | - name: Piero Triverio # note this makes a footnote saying 'co-first author' 19 | affiliation: 1 20 | affiliations: 21 | - name: Dept. of Electrical & Computer Engineering, University of Toronto 22 | index: 1 23 | 24 | date: 11 November 2021 25 | bibliography: paper.bib 26 | 27 | 28 | --- 29 | 30 | # Summary 31 | 32 | Mie series provide an analytic solution to the problem of scattering of a plane electromagnetic wave by a homogenous sphere. The aggregate result of this calculation is known as the Radar Cross Section (RCS), which is a pattern of the relative intensity of the scattered electromagnetic wave. Knowledge of the Radar Cross Section, and its dependence on frequency, angle, sphere material, etc., are useful in many engineering and scientific applications ranging from Radar Imaging to atmospheric science. Furthermore, RCS values obtained from the analytic results from the Mie series are used to verify the correctness of numerical results from computational electromagnetic solvers. 33 | 34 | ![Pattern of scattered electric field intensity for different angles of observation.](compare_bistatic_materials.png) 35 | 36 | # Statement of need 37 | 38 | While several open-source libraries for Mie series RCS calculations exist, those codes suffer from a lack of robustness for highly conductive objects. A literature review revealed that several existing libraries were unable to yield results for lossy dielectrics and at high frequencies – a significant problem considering the importance of these regimes for a wide variety of electromagnetic engineering problems. 39 | 40 | `Python Sphere RCS` can perform calculations in the high-frequency high-conductivity regime by incorporating arbitrary precision mathematics in the critical portions of the calculation, while solving several computational issues that beset the existing publicly available solvers. Results from this solver were cross validated with numerical solvers to good visual agreement (see plot below). 41 | 42 | ![Validation Plot against Results obtained with Method of Moments Solver.](bistatic_validation.png) 43 | 44 | The focus of this code is producing and plotting RCS through easy-to-use interface functions. Examples of various plots that can be made are provided along with the code used to generate them. The `Python Sphere RCS` library can benefit the broader scientific community to enable research and educational endeavors. 45 | 46 | 47 | # Acknowledgements 48 | We acknowledge the support of the Natural Sciences and Engineering Research Council of Canada (NSERC). 49 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Python Sphere RCS Calculator 2 | 3 | ### This library uses the Mie Series to compute the Radar Cross Section for a lossy dielectric sphere. The Radar Cross Section (RCS) can be plotted for a variety of test scenarios, such as: 4 | * mono-static RCS versus frequency for one or many spheres 5 | * bi-static RCS for one or many spheres with different materials 6 | * bi-static RCS for one sphere at multiple frequencies 7 | 8 | 9 | ### The code is supplemented by several functions for generating, saving, and plotting RCS data. Since the Mie Series produces an analytical result, this code can be used to verify results obtained using numerical computational electromagnetic solvers. 10 | 11 | 12 | ### This code is primarily based on the following works: 13 | 1. C. A. Balanis, Advanced Engineering Electromagnetics. New York, NY: John Wiley & Sons, Inc., 1989. 14 | 2. G. Kevin Zhu (2021). Sphere scattering (https://www.mathworks.com/matlabcentral/fileexchange/31119-sphere-scattering), MATLAB Central File Exchange. 15 | 3. W. J. Wiscombe, "Improved Mie scattering algorithms," Appl. Opt. 19, 1505-1509 (1980) 16 | 4. Allardice, J. R., & Le Ru, E. C. (2014). Convergence of Mie theory series: criteria for far-field and near-field properties. Applied Optics, 53(31), 7224. doi:10.1364/ao.53.007224 17 | 18 | 19 | ### Contributors to this library: 20 | * Iliya Shofman, Damian Marek, Shaswat Sharma, Piero Triverio 21 | 22 |   23 | 24 | # Overview of Library 25 | ## Code Requirements 26 | * Python version 3.x 27 | * `numpy`, `matplotlib`, `scipy.special`, `mpmath` 28 | 29 | ## Coordinate System 30 | The calculations in this library assume that an x-polarized wave travels in the positive z- direction. Theta (the polar angle) is zero at the positive z-axis, reaches maximum value of pi at the negative z-axis. Phi (the angle of azimuth) is zero at the positive x-axis. 31 | 32 | To observe differences caused by plane wave polarization in the bistatic case, change the phi variable. For example, to see RCS from y-polarized waves, set phi = pi/2. For circularly polarized waves, compute as a linear superposition of two modes. 33 | 34 | Coordinate System 35 | 36 | ## List of Function Arguments 37 | This library makes use of the following parameters when computing the Radar Cross Section of dielectric spheres: 38 | * `radius` (meters) - the radius of the sphere 39 | * `ratio` (unitless) - ratio of sphere radius to wavelength 40 | * `frequency` (Hertz) - the frequency of impinging plane wave 41 | * `sensor location` - an (x,y,z) coordinate in meters at which the RCS is evaluated. The sphere is positioned at the origin. 42 | * `sphere_material` and `background_material` - objects of class `DielectricMaterial` 43 | * `save_file` (string) - output file names for saving data 44 | 45 | ## Class Definitions 46 | This library makes use of several classes to organize the process of passing arguments to functions: 47 | * `DielectricMaterial`: defines a medium by its electric permittivity, electric conductivity, and magnetic permeability as `DielectricMaterial(eps_r, sigma_e=0, mu_r=1, sigma_m=0, name=None)`. For example, a silicon nanoparticle with a conductivity of 10 S/cm can be defined as `doped_silicon = DielectricMaterial(11.7, 10, 1)`. Note: a Perfect Electric Conductor can be defined by setting electric permettivity to a large value and magnetic permeability to a small value such that their product equals 1, for example, `PEC = DielectricMaterial(1e8,0,1e-8,0)` (See Balanis referene). 48 | 49 | For comparing the RCS between multiple spheres or positions, the use of the `TestCase` and `TestParameters` classes are encouraged. 50 | * `TestCase` - defines a sphere of some radius and material immersed in a specified medium as, for example, `PEC_nanoparticle_in_silicon = TestCase(radius = 1e-7, sphere_material = PEC, background_material = doped_silicon)` 51 | * `TestParameters` - groups together the sensor location and frequencies at which the RCS is to be tested for. Following the earlier example, we could call `test_1 = TestParameters([0,0,-1e-5], 2.4e9)`. 52 | 53 | 54 | ## List of Functions 55 | Using these parameters, the following functions are defined for this library: 56 | 57 | (Monostatic RCS) 58 | * `RCS_vs_freq (radius, ratio, background_material, sphere_material, sensor_location, save_file)` 59 | * `plotOneMonoRCS (radius, sphere_material, background, mono_RCS, ratio, savefile)` 60 | * `saveMonoRCSData (savefile, mono_RCS, frequency, sphere, radius)` 61 | * `Compare_RCS_vs_freq (test_cases, test_parameters, save_file)` 62 | 63 |   (Bistatic RCS) 64 | * `Bistatic_RCS (radius, frequency, background, sphere, distance, phi)` 65 | * `plotBiRCS (radius, sphere, frequency, bi_RCS, theta, savefile)` 66 | * `saveBiRCSData (savefile, bi_RCS, theta, frequency, sphere)` 67 | * `Compare_Bistatic_RCS (test_cases, test_parameters, save_file)` 68 | 69 | 70 | 71 | 72 | 73 | 74 | # Example Usage 75 | 76 | This section will show example code for creating frequently-used plots. This code can be pasted into the `main` function in the file `getRCS.py`. For questions about individual functions, please see the docstrings. 77 | 78 | ## Mono-Static RCS vs Frequency for One Sphere 79 | This example computes the monostatic RCS for a Perfect Electric Conductor. The material definition for the PEC comes from Balanis 1989. The code produces a plot (`PEC.png`) and saves the data to a text file (`PEC.txt`). 80 | ``` 81 | RCS_vs_freq(radius = 0.5, ratio = np.arange(0.01,1.61,0.01), \ 82 | background_material = DielectricMaterial(1,0), \ 83 | sphere_material = DielectricMaterial(1e8,0,1e-8,0), \ 84 | sensor_location = [0,0,-2000], save_file = 'PEC') 85 | ``` 86 | ![PEC Sphere in vacuum](figures/PEC.png) 87 | 88 | Note: the variable `ratio` is defined as `radius / wavelength`. To have the x-axis be in terms of `ratio`, use function `plotOneMonoRCS()`. This function accepts either `ratio`, `frequency`, or `wavelength`, and plots it on the x axis. : 89 | ``` 90 | radius = 0.5 #meters 91 | ratio = np.arange(0.01,1.61,0.01) 92 | background = DielectricMaterial(1,0) 93 | sphere_material = DielectricMaterial(2.56,0.003) 94 | sensor_location = [0,0,-2000] #meters 95 | 96 | (freq, mono_RCS) = RCS_vs_freq(radius, ratio, background, sphere_material, \ 97 | sensor_location , save_file = 'PEC', show_plot = 0) 98 | plotOneMonoRCS(radius, sphere_material, background, mono_RCS, ratio = ratio, \ 99 | savefile = "lossy_dielectric_mono_rcs") 100 | ``` 101 | ![Lossy Dielectric Monostatic RCS](figures/lossy_dielectric_mono_rcs.png) 102 | 103 |   104 | 105 | ## Bi-Static RCS (vs angle) for One Sphere 106 | The code sample below displays a plot of Bistatic RCS for a lossy dielectric sphere, and saves this data to a text file. The first function calculates and returns a numpy array with Bistatic RCS data, along with displaying the plot. The second function saves the data to a file, without saving the plot. To not display the plot, set `show_plot=0`. 107 | ``` 108 | radius = 0.5 109 | background = DielectricMaterial(1,0) 110 | sphere = DielectricMaterial(2.56,0.01) 111 | distance = 2000 112 | phi = 0 113 | (theta, bi_RCS) = Bistatic_RCS(radius, 1e9, background, sphere, distance, phi, show_plot=1) 114 | saveBiRCSData("bistatic_perfect_dielectric_example", bi_RCS, theta, 1e9, sphere) 115 | ``` 116 | ![Bistatic RCS for Lossy Dielectric](figures/bistatic_lossy_dielectric_example.png) 117 | 118 |   119 | 120 | ## Mono-Static RCS vs Frequency for Multiple Spheres 121 | For plotting multiple spheres, use the `Compare_RCS_vs_freq()` function, or the `plotFromFile` function. Each plot line represents RCS data for one `TestCase`, in which a sphere of size `radius` and material `sphere_material` is immersed in a `background_material`. Each `TestCase` can be evaluated under one or many `TestParameters`, which include `sensor_location` and `frequency`. 122 | 123 | ``` 124 | #class TestCase(radius, sphere_material, background_material) 125 | case1 = TestCase(0.5, DielectricMaterial(2.56,0), DielectricMaterial(1,0)) 126 | case2 = TestCase(0.5, DielectricMaterial(2.56,0.1, name = "Silicon"), DielectricMaterial(1,0)) 127 | 128 | #class TestParameters(cartesian_sensor_location, frequency) 129 | param1 = TestParameters([0,0,-2000], np.logspace(7,9,100)) 130 | 131 | Compare_RCS_vs_freq([case1,case2], param1, "example_2_material_comparison") 132 | ``` 133 | 134 | ![Example 2 Material Comparison](figures/example_2_material_comparison.png) 135 | 136 | ### Conductivity Sweep 137 | To plot the RCS of a sphere at many different conductivities, one can automate the process of creating `TestCase` objects like this: 138 | ``` 139 | vacuum = DielectricMaterial(1,0) 140 | radius = 0.5 141 | conductivities = [0, 1e-5, 1e-3, 1e-2, 1e0, 1e3, 1e6] 142 | names = ["0", "1e-5", "1e-3", "1e-2", "1e0", "1e3", "1e6"] 143 | eps_r, mu_r = 2.56, 1 144 | 145 | cases = [] 146 | for i in range(0, len(conductivities)): 147 | sphere = DielectricMaterial(eps_r, conductivities[i], mu_r, name = names[i]) 148 | test_case = TestCase(radius, sphere, vacuum) 149 | cases.append(test_case) 150 | 151 | sensor_location = [0,0,-2000] #[x,y,z], all in meters 152 | frequency = np.logspace(7,9,1000) 153 | param1 = TestParameters(sensor_location, frequency) 154 | 155 | Compare_RCS_vs_freq(cases, param1, save_file = "sigma_sweep_kzhu_nmax") 156 | ``` 157 | ![Sigma Sweep](figures/sigma_sweep.png) 158 | 159 |   160 | 161 | ## Bi-Static RCS for one Sphere at Multiple Frequencies 162 | Using the function `Compare_Bistatic_RCS`, one can compare the RCS of multiple spheres at the same frequency, or one sphere at multiple frequencies. This example shows both. 163 | ### Bistatic RCS for two spheres, one frequency 164 | ``` 165 | vacuum = DielectricMaterial(1,0) 166 | radius = 0.5 167 | sphere1 = DielectricMaterial(2.56,0, 1,0, name = "Loss-less") 168 | sphere2 = DielectricMaterial(2.56,1, 1,0, name = "Lossy") 169 | test_cases = [TestCase(radius, sphere1, vacuum), TestCase(radius, sphere2, vacuum)] 170 | 171 | sensor_location = [0,0,-2000] 172 | frequency = 1e9 173 | test_parameters = TestParameters(sensor_location, frequency) 174 | 175 | Compare_Bistatic_RCS(test_cases, test_parameters, save_file = "compare_bistatic_materials") 176 | ``` 177 | ![Bistatic RCS for Different Materials](figures/compare_bistatic_materials.png) 178 | 179 | ### Bistatic RCS for one sphere, two frequencies 180 | ``` 181 | vacuum = DielectricMaterial(1,0) 182 | radius = 0.5 183 | sphere3 = DielectricMaterial(2.56,3.3, 1,0, name = "Lossy") 184 | test_cases = [TestCase(radius, sphere3, vacuum)] 185 | 186 | sensor_location = [0,0,-2000] 187 | frequency = [1e9, 3e9, 5e9] 188 | test_parameters = TestParameters(sensor_location, frequency) 189 | 190 | Compare_Bistatic_RCS(test_cases, test_parameters, save_file = "compare_bistatic_frequencies") 191 | ``` 192 | ![Bistatic RCS for Different Frequencies](figures/compare_bistatic_frequencies.png) 193 | 194 | -------------------------------------------------------------------------------- /src.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.special as ss 3 | 4 | def cartToSph(x,y,z): 5 | ''' 6 | [r, theta, phi] = cartToSph(x, y, z) converts the cartesian 7 | coordinate system to the spherical coordinate system according to 8 | the following definition: 9 | r distance from the origin to the point in the interval 10 | [0, \infty) 11 | theta elevation angle measured between the positive z-axis and 12 | the vector in the interval [0, pi] 13 | phi azimuth angle measured between the positive x-axis and 14 | the vector in the interval [0, 2*pi) 15 | ''' 16 | 17 | r = np.sqrt(x**2 + y**2 + z**2) 18 | theta = np.arctan2(np.sqrt(x**2 + y**2), z) 19 | phi = np.arctan2(y , x) 20 | 21 | return [r, theta, phi] 22 | 23 | def sphToCart(r,theta,phi): 24 | ''' 25 | [x,y,z] = sphToCart(r,theta,phi) 26 | for converting from spherical to cartesian coordinates 27 | r is radius, 28 | theta is angle of elevation (0 at positive z axis, pi at negative z axis) 29 | phi is angle of azimuth (0 at positive x axis, increase counterclockwise) 30 | ''' 31 | x = r*np.sin(theta)*np.cos(phi) 32 | y = r*np.sin(theta)*np.sin(phi) 33 | z = r*np.cos(theta) 34 | 35 | return [x,y,z] 36 | 37 | def get_legendre(n,m,x): 38 | ''' 39 | Returns an array dimensions len(N) by 1 with the 40 | value of the m-th degree term of the n-th order 41 | associated legendre polynomial evaluated at x. 42 | 43 | Inputs: 44 | n: a sequence of integers 45 | m: a single integer, for now. 46 | x: the argument to legenre polynomial 47 | Output: 48 | P 49 | ''' 50 | P = [] 51 | for i in range(0,len(n)): 52 | # use scipy.special to computePmn(x) 53 | #into an m+1 x n+1 array for every value 54 | #0...m, 0...n. 55 | a,b = ss.lpmn(m,n[i],x) 56 | #select the value at the m,n of interest 57 | P.append(a[m,n[i]]) 58 | return P 59 | 60 | def norm(sensor_location): 61 | ''' 62 | return the pythagorean distance from the sensor location 63 | to the origin. 64 | ''' 65 | x = sensor_location[0] 66 | y = sensor_location[1] 67 | z = sensor_location[2] 68 | return np.sqrt(x**2 + y**2 + z**2) 69 | 70 | 71 | 72 | if __name__ == "__main__": 73 | sensor_location = [0,0,-2000] 74 | [r,theta,phi] = cartToSph(sensor_location) 75 | print(r,theta,phi) 76 | -------------------------------------------------------------------------------- /test_script.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Purpose of document: run this in the terminal to confirm 3 | that all functions in this library work as expected. 4 | ''' 5 | 6 | from getRCS import * 7 | import warnings 8 | 9 | if __name__ == "__main__": 10 | print("------------------\nPYTHON SPHERE RCS\n------------------\n") 11 | print("this script will confirm that all functions work as expected.") 12 | print("It will display plots and save them to the \"output\" folder \n") 13 | confirm = input("As you see plots appearing, close the Matplotlib window to proceed. Hit Enter to Continue:") 14 | print("------\nBEGIN\n------\n") 15 | 16 | #PART 1: PLOT ONE MONOSTATIC RCS FOR LOSSY DIELECTRIC 17 | radius = 0.5 #meters 18 | ratio = np.arange(0.01,1.61,0.01) 19 | background = DielectricMaterial(1,0) 20 | sphere_material = DielectricMaterial(2.56,0.003) 21 | sensor_location = [0,0,-2000] 22 | 23 | with warnings.catch_warnings(): 24 | warnings.simplefilter("ignore") 25 | (freq, mono_RCS) = RCS_vs_freq(radius, ratio, background, sphere_material, \ 26 | sensor_location , save_file = 'PEC', show_plot = 0) 27 | plotOneMonoRCS(radius, sphere_material, background, mono_RCS, ratio = ratio, \ 28 | savefile = "output/lossy_dielectric_mono_rcs") 29 | 30 | print("Finished Part 1: Plot Monostatic RCS for Losy Dielectric Sphere as lossy_dielectric_mono_rcs.png\n") 31 | 32 | #PART 2: PLOT ONE MONOSTATIC RCS FOR PERFECT DIELECTRIC 33 | with warnings.catch_warnings(): 34 | warnings.simplefilter("ignore") 35 | RCS_vs_freq(radius = 0.5, ratio = np.arange(0.01,1.61,0.01), \ 36 | background_material = DielectricMaterial(1,0), sphere_material = DielectricMaterial(2.56,0), \ 37 | sensor_location = [0,0,-2000], save_file = 'output/perfect_dielectric') 38 | 39 | print("Finished Part 2: Plot Monostatic RCS for Perfect Dielectric Sphere as perfect_dielectric.png\n") 40 | 41 | #PART 3A: PLOT BISTATIC RCS COMPARISON 42 | #bistatic RCS for two spheres, one frequency 43 | vacuum = DielectricMaterial(1,0) 44 | radius = 0.5 45 | sphere1 = DielectricMaterial(2.56,0, 1,0, name = "Loss-less") 46 | sphere2 = DielectricMaterial(2.56,1, 1,0, name = "Lossy") 47 | test_cases = [TestCase(radius, sphere1, vacuum), TestCase(radius, sphere2, vacuum)] 48 | 49 | sensor_location = [0,0,-2000] 50 | frequency = 1e9 51 | test_parameters = TestParameters(sensor_location, frequency) 52 | 53 | with warnings.catch_warnings(): 54 | warnings.simplefilter("ignore") 55 | Compare_Bistatic_RCS(test_cases, test_parameters, save_file = "output/compare_bistatic_materials") 56 | 57 | #PART 3B: PLOT BISTATIC RCS COMPARISON 58 | #bistatic RCS for one sphere, two frequencies 59 | vacuum = DielectricMaterial(1,0) 60 | radius = 0.5 61 | sphere3 = DielectricMaterial(2.56,3.3, 1,0, name = "Lossy") 62 | test_cases = [TestCase(radius, sphere3, vacuum)] 63 | 64 | sensor_location = [0,0,-2000] 65 | frequency = [1e9, 3e9, 5e9] 66 | test_parameters = TestParameters(sensor_location, frequency) 67 | 68 | with warnings.catch_warnings(): 69 | warnings.simplefilter("ignore") 70 | Compare_Bistatic_RCS(test_cases, test_parameters, save_file = "output/compare_bistatic_frequencies") 71 | 72 | print("Finished Part 3: Compare Bistatic RCS for Perfect Dielectric Spheres, parts A and B\n") 73 | 74 | print("------\nFINISHED\n------\n") --------------------------------------------------------------------------------