├── .gitignore ├── README.md ├── arrayinfo.py ├── beamforming.py ├── hornpattern.py ├── multitests.py ├── rasolver.py ├── ratasks.py ├── rautils.py └── sources.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | __pycache__/ 3 | *.pyc 4 | experiment/ 5 | experiment.py -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RAAnalysis-py 2 | ## Reflectarray antenna analysis tool python version 3 | -------------------------------------------------------------------------------- /arrayinfo.py: -------------------------------------------------------------------------------- 1 | from rautils import create_array_pos, ideal_ref_unit, distance, make_v_mtx, R2F, F2R 2 | from sources import Source 3 | from hornpattern import get_default_pyramidal_horn 4 | from beamforming import BeamForming 5 | import numpy as np 6 | import threading 7 | 8 | import matplotlib.pyplot as plt 9 | 10 | class RAInfo: 11 | 12 | def get_pxy(self): 13 | return self.px, self.py 14 | 15 | def get_Nxy(self): 16 | return self.Nx, self.Ny 17 | 18 | def get_dxy(self): 19 | return self.dx, self.dy 20 | 21 | def get_k0(self): 22 | return self.k0 23 | 24 | def __init__(self, src, cell_sz, scalexy, kv, func, shape='rect'): 25 | scalex, scaley = scalexy 26 | self.efield = [] 27 | self.idx = 0 28 | self.px, self.py = cell_sz, cell_sz 29 | self.Nx, self.Ny = scalex, scaley 30 | self.dx, self.dy = cell_sz, cell_sz 31 | self.k0 = src.k0() 32 | 33 | xl, yl = create_array_pos(cell_sz, scalex, scaley, False) 34 | if shape == 'circle': 35 | if scalex != scaley: 36 | raise ValueError 37 | cpos = [] 38 | for y in yl: 39 | for x in xl: 40 | if np.sqrt(x**2 + y**2) <= scalex: 41 | cpos.append((x, y)) 42 | else: 43 | cpos = [(x, y) for y in yl for x in xl] 44 | 45 | key, val = kv 46 | fpos = [p for _, _, p, _ in src] if src.is_horn() else None 47 | bf = BeamForming(src.frequency(), xl, yl, fpos) 48 | if key == 'file': 49 | ret = [] 50 | distro = open(val) 51 | for line in distro.readlines(): 52 | sline = line.split() 53 | #v = [int(x) for x in sline] 54 | v = [] 55 | for num in sline: 56 | if int(num) == 1: 57 | v.append(np.pi) 58 | else: 59 | v.append(0.0) 60 | ret.append(v) 61 | distro.close() 62 | phase = np.array(ret) 63 | elif key == 'selfdefine': 64 | phase = val 65 | elif key == 'pencil': 66 | phase = bf.form_pencil_beam(val, fpos != None) 67 | elif key == 'oam': 68 | tpm, beta = val 69 | phase = bf.form_oam_beam(tpm, beta, fpos != None) 70 | elif key == 'foci': 71 | phase = bf.form_focal_beam(val, fpos != None) 72 | else: 73 | print('Error phase distribution') 74 | raise ValueError 75 | 76 | allp = phase.flatten() 77 | #TODO: circle board 78 | 79 | sp = func(allp) 80 | 81 | # iter on sources 82 | for (i, (x, y)) in list(enumerate(cpos)): 83 | erx, ery = 0j, 0j 84 | for s, abg, pos, dir in src: 85 | dis = distance(pos, (0., 0., 0.)) 86 | fpt = R2F(*abg) * make_v_mtx(x, y, 0.0) 87 | 88 | if dir == 'origin': 89 | fpt[2][0] += dis 90 | elif dir == 'parallel': 91 | fpt[0][0] -= pos[0] 92 | fpt[1][0] -= pos[1] 93 | fpt[2][0] += pos[2] 94 | 95 | Exyz, _, _ = s.efield_at_xyz(fpt.item(0), fpt.item(1), fpt.item(2)) 96 | in_efield = F2R(*abg) * Exyz 97 | erx += in_efield.item(0) 98 | ery += in_efield.item(1) 99 | tc = np.matrix([ 100 | [1, 0], 101 | [0, 1] 102 | ]) 103 | s11, s12, s21, s22 = sp[i] 104 | d12 = tc*np.matrix([[erx], [ery]]) 105 | a1 = s11*d12.item(0) + s12*d12.item(1) 106 | a2 = s21*d12.item(0) + s22*d12.item(1) 107 | axy = tc*np.matrix([[a1], [a2]]) 108 | self.efield.append((axy.item(0), axy.item(1))) 109 | 110 | self.lock = threading.Lock() 111 | 112 | def __len__(self): 113 | return len(self.efield) 114 | 115 | def __iter__(self): 116 | with self.lock: 117 | self.idx = 0 118 | return self 119 | 120 | def __next__(self): 121 | with self.lock: 122 | if self.idx == len(self): 123 | raise StopIteration 124 | ret = self.efield[self.idx] 125 | self.idx += 1 126 | return ret 127 | 128 | 129 | if __name__ == '__main__': 130 | freq = 5e9 131 | cell_sz = 30. / 1000. 132 | scale = 20 133 | 134 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 135 | src = Source() 136 | src.append(get_default_pyramidal_horn(freq), abg, (0., 0., 0.5)) 137 | tp = [(np.deg2rad(0), np.deg2rad(0))] 138 | tpm = [(np.deg2rad(0), np.deg2rad(0), 1)] 139 | foci = [(0, 0, 0.8, 1.0)] 140 | 141 | arr = RAInfo(src, cell_sz, (scale, scale), ('oam', (tpm, np.deg2rad(10))), ideal_ref_unit) 142 | for (ex, ey) in arr: 143 | print(ex, ey) -------------------------------------------------------------------------------- /beamforming.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from rautils import sol, distance, create_array_pos 3 | import matplotlib.pyplot as plt 4 | 5 | 6 | class BeamForming: 7 | def __init__(self, freq, xpos, ypos, fpos): 8 | """ 9 | Parameters: 10 | freq unit:Hz 11 | xpos x-axis element position list unit:m 12 | ypos y-axis element position list unit:m 13 | fpos feed position tuple, list etc. or None for plane wave unit:m 14 | """ 15 | self.freq = freq 16 | self.k0 = 2 * np.pi / (sol / freq) 17 | self.xpos = xpos 18 | self.ypos = ypos 19 | self.fpos = fpos 20 | 21 | def frequency(self): 22 | return self.freq 23 | 24 | def __get_phi_n(self, theta, phi, x, y): 25 | return -self.k0 * np.sin(theta) * np.cos(phi) * x - self.k0 * np.sin(theta) * np.sin(phi) * y 26 | 27 | def __feed_phase(self, x, y): 28 | sum = 0.0j 29 | for (fx, fy, fz) in self.fpos: 30 | df = distance((fx, fy, fz), (x, y, 0.0)) 31 | sum += np.exp(1j*df*self.k0) 32 | return np.angle(sum) + np.pi*2 33 | 34 | def __get_phi_k(self, theta, phi, x, y): 35 | return np.arctan2(-np.cos(theta)*np.sin(phi)*x + np.cos(theta)*np.cos(phi)*y, np.cos(phi)*x + np.sin(phi)*y) 36 | 37 | def form_pencil_beam(self, tp, haskd=True): 38 | """ 39 | :param tp: theta phi [(t1, p1), (t1, p1), ...], unit rad 40 | :param haskd: use kd with fpos 41 | :return: np.ndarray unit rad 42 | """ 43 | ret = np.ndarray((len(self.ypos), len(self.xpos))) 44 | for (yidx, y) in list(enumerate(self.ypos)): 45 | for (xidx, x) in list(enumerate(self.xpos)): 46 | sum = 0.0j 47 | for(t, p) in tp: 48 | phi_n = self.__get_phi_n(t, p, x, y) 49 | sum += np.exp(1j*phi_n) 50 | if haskd: 51 | ret[yidx][xidx] = (np.angle(sum) + self.__feed_phase(x, y)) % (2*np.pi) 52 | else: 53 | ret[yidx][xidx] = (np.angle(sum) + 2*np.pi) % (2*np.pi) 54 | return ret 55 | 56 | def form_focal_beam(self, focals, haskd=True): 57 | """ 58 | :param focals: [(dx1, dy1, dz1, D1), (dx2, dy2, dz2, D2), ...] 59 | :param haskd: use kd with fpos 60 | :return: np.ndarray unit rad 61 | """ 62 | ret = np.ndarray((len(self.ypos), len(self.xpos))) 63 | for (yidx, y) in list(enumerate(self.ypos)): 64 | for (xidx, x) in list(enumerate(self.xpos)): 65 | sum = 0.0j 66 | for (dx, dy, dz, D) in focals: 67 | sum += D * np.exp(1j*self.k0*distance((dx, dy, dz), (x, y, 0.0))) 68 | if haskd: 69 | ret[yidx][xidx] = (np.angle(sum) + self.__feed_phase(x, y)) % (2*np.pi) 70 | else: 71 | ret[yidx][xidx] = (np.angle(sum) + 2*np.pi) % (2*np.pi) 72 | return ret 73 | 74 | def form_oam_beam(self, tpm, beta=0.0, haskd=True): 75 | """ 76 | :param tpm: [(t1, p1, m1), (t2, p2, m2), ...] 77 | :beta: no diffraction OAM angle unit: rad 78 | :param haskd: use kd with fpos 79 | :return: np.ndarray unit rad 80 | """ 81 | ret = np.ndarray((len(self.ypos), len(self.xpos))) 82 | for (yidx, y) in list(enumerate(self.ypos)): 83 | for (xidx, x) in list(enumerate(self.xpos)): 84 | sum = 0.0j 85 | for (t, p, mode) in tpm: 86 | pn = self.__get_phi_n(t, p, x, y) 87 | pk = self.__get_phi_k(t, p, x, y) * mode 88 | big_phi = pn + pk 89 | sum += np.exp(1j*(big_phi)) 90 | if haskd: 91 | ret[yidx][xidx] = (np.angle(sum) + self.__feed_phase(x, y) + np.sqrt(x*x+y*y)*np.sin(beta)*self.k0)\ 92 | % (2*np.pi) 93 | else: 94 | ret[yidx][xidx] = (np.angle(sum) + 2*np.pi + np.sqrt(x*x+y*y)*np.sin(beta)*self.k0) % (2*np.pi) 95 | return ret 96 | 97 | 98 | def multi_test(): 99 | f = 10.0e9 100 | cell_sz = 15.0 / 1000. 101 | scale = 20 102 | fdr = 0.8 103 | oa = np.deg2rad(0) 104 | fp1 = (0., -cell_sz*scale*fdr*np.sin(oa), cell_sz*scale*fdr*np.cos(oa)) 105 | fp2 = (0., cell_sz*scale*fdr*np.sin(oa), cell_sz*scale*fdr*np.cos(oa)) 106 | fpos = [fp1] 107 | xlex, ylex = create_array_pos(cell_sz, scale, scale, True) 108 | bf = BeamForming(f, xlex, ylex, fpos) 109 | 110 | beam_dir = [(np.deg2rad(0), np.deg2rad(0))] 111 | pb = bf.form_pencil_beam(beam_dir, True) 112 | plt.figure() 113 | plt.pcolor(xlex, ylex, np.rad2deg(pb), cmap='jet') 114 | plt.colorbar() 115 | 116 | focals = [(0.0, 0.0, 0.5, 1)] 117 | fb = bf.form_focal_beam(focals) 118 | plt.figure() 119 | plt.pcolor(xlex, ylex, np.rad2deg(fb), cmap='jet') 120 | plt.colorbar() 121 | 122 | tpm = [(np.deg2rad(0), np.deg2rad(0), 2)] 123 | ob = bf.form_oam_beam(tpm, beta=np.deg2rad(10)) 124 | plt.figure() 125 | plt.pcolor(xlex, ylex, np.rad2deg(ob), cmap='jet') 126 | plt.colorbar() 127 | plt.show() 128 | 129 | 130 | if __name__ == '__main__': 131 | multi_test() 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /hornpattern.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from rautils import dB, distance, sol, create_array_pos, car2sph, waveimpd 4 | from scipy import integrate 5 | 6 | 7 | class PyramidalHorn: 8 | def __init__(self, r1, r2, a, b, a1, b1, E0, freq, initp=0.0): 9 | k0 = 2 * np.pi / (sol / freq) 10 | 11 | self.r1 = r1 12 | self.r2 = r2 13 | self.a = a 14 | self.b = b 15 | self.a1 = a1 16 | self.b1 = b1 17 | self.E0 = E0 18 | self.k0 = k0 19 | self.rz = 1 20 | self.freq = freq 21 | self.initp = initp 22 | 23 | def have_input_power(self): 24 | return True 25 | 26 | def frequency(self): 27 | return self.freq 28 | 29 | def get_k0(self): 30 | return self.k0 31 | 32 | def integ_func(self, t, p): 33 | R = 100. # any R would be ok 34 | _, et, ep = self.efield_at_rtp(R, t, p) 35 | etp = np.sqrt(et**2 + ep**2) 36 | return np.abs(etp)**2 *R*R*np.sin(t) / (2*waveimpd) 37 | 38 | def efield_at_xyz(self, x, y, z): 39 | r, theta, phi = car2sph(x, y, z) 40 | return self.efield_at_rtp(r, theta, phi) 41 | 42 | 43 | def efield_at_rtp(self, r, theta, phi): 44 | k = 2*np.pi 45 | ky = k * np.sin(theta)*np.sin(phi) 46 | t1 = np.sqrt(1/(np.pi*k*self.r1)) * (-k*self.b1/2-ky*self.r1) 47 | t2 = np.sqrt(1/(np.pi*k*self.r1)) * (k*self.b1/2-ky*self.r1) 48 | 49 | kxp = k*np.sin(theta)*np.cos(phi) + np.pi/self.a1 50 | kxdp = k*np.sin(theta)*np.cos(phi) - np.pi/self.a1 51 | t1p = np.sqrt(1/(np.pi*k*self.r2)) * (-k*self.a1/2-kxp*self.r2) 52 | t2p = np.sqrt(1/(np.pi*k*self.r2)) * (k*self.a1/2-kxp*self.r2) 53 | 54 | t1dp = np.sqrt(1/(np.pi*k*self.r2)) * (-k*self.a1/2-kxdp*self.r2) 55 | t2dp = np.sqrt(1/(np.pi*k*self.r2)) * (k*self.a1/2-kxdp*self.r2) 56 | 57 | I1 = .5*np.sqrt(np.pi*self.r2/k) * (np.exp(1j*kxp**2*self.r2/(2*k)) * (self.Fresnel(t2p)-self.Fresnel(t1p)) 58 | + np.exp(1j*kxdp**2*self.r2/(2*k)) * (self.Fresnel(t2dp) - self.Fresnel(t1dp))) 59 | I2 = np.sqrt(np.pi*self.r1/k) * np.exp(1j*ky**2*self.r1/(2*k)) * (self.Fresnel(t2) - self.Fresnel(t1)) 60 | 61 | k = self.k0 62 | Etheta = 1j*k*self.E0*np.exp(-1j*(k*r + self.initp))/(4*np.pi*r) * (np.sin(phi) * (1+np.cos(theta)) * I1 * I2) 63 | Ephi = 1j*k*self.E0*np.exp(-1j*(k*r + self.initp))/(4*np.pi*r) * (np.cos(phi) * (1+np.cos(theta)) * I1 * I2) 64 | 65 | tmtx = np.matrix( 66 | [ 67 | [np.sin(theta)*np.cos(phi), np.cos(theta)*np.cos(phi), -np.sin(phi)], 68 | [np.sin(theta)*np.sin(phi), np.cos(theta)*np.sin(phi), np.cos(phi)], 69 | [np.cos(theta), -np.sin(theta), 0] 70 | ] 71 | ) 72 | 73 | emtx = np.matrix([ 74 | [0], 75 | [Etheta], 76 | [Ephi] 77 | ]) 78 | return tmtx * emtx, Etheta, Ephi 79 | 80 | 81 | def Fresnel(self, x): 82 | A = [ 83 | 1.595769140, 84 | -0.000001702, 85 | -6.808508854, 86 | -0.000576361, 87 | 6.920691902, 88 | -0.016898657, 89 | -3.050485660, 90 | -0.075752419, 91 | 0.850663781, 92 | -0.025639041, 93 | -0.150230960, 94 | 0.034404779 95 | ] 96 | 97 | B = [ 98 | -0.000000033, 99 | 4.255387524, 100 | -0.000092810, 101 | -7.780020400, 102 | -0.009520895, 103 | 5.075161298, 104 | -0.138341947, 105 | -1.363729124, 106 | -0.403349276, 107 | 0.702222016, 108 | -0.216195929, 109 | 0.019547031 110 | ] 111 | 112 | C = [ 113 | 0, 114 | -0.024933975, 115 | 0.000003936, 116 | 0.005770956, 117 | 0.000689892, 118 | -0.009497136, 119 | 0.011948809, 120 | -0.006748873, 121 | 0.000246420, 122 | 0.002102967, 123 | -0.001217930, 124 | 0.000233939 125 | ] 126 | 127 | D = [ 128 | 0.199471140, 129 | 0.000000023, 130 | -0.009351341, 131 | 0.000023006, 132 | 0.004851466, 133 | 0.001903218, 134 | -0.017122914, 135 | 0.029064067, 136 | -0.027928955, 137 | 0.016497308, 138 | -0.005598515, 139 | 0.000838386 140 | ] 141 | 142 | if x == 0: 143 | return 0 144 | elif x < 0: 145 | x = np.abs(x) 146 | x = (np.pi/2) * (x**2) 147 | F = 0 148 | if x < 4: 149 | for k in range(12): 150 | F += (A[k] + 1j*B[k]) * ((x/4) ** k) 151 | return -(F*np.sqrt(x/4) * np.exp(-1j*x)) 152 | else: 153 | for k in range(12): 154 | F += (C[k] + 1j*D[k]) * ((4/x) ** k) 155 | return -(F*np.sqrt(4/x) * np.exp(-1j*x) + (1-1j)/2) 156 | else: 157 | x = (np.pi/2) * (x**2) 158 | F = 0 159 | if x < 4: 160 | for k in range(12): 161 | F += (A[k] + 1j*B[k]) * ((x/4) ** k) 162 | return F*np.sqrt(x/4) * np.exp(-1j*x) 163 | else: 164 | for k in range(12): 165 | F += (C[k] + 1j*D[k]) * ((4/x) ** k) 166 | return F*np.sqrt(4/x) * np.exp(-1j*x) + (1-1j)/2 167 | 168 | 169 | def get_horn_input_power(horn): 170 | if not isinstance(horn, PyramidalHorn): 171 | raise ValueError 172 | ret = integrate.nquad(horn.integ_func, [[0, np.pi/2.], [0, np.pi*2]]) 173 | return ret[0] 174 | 175 | def get_default_pyramidal_horn(freq, E0=10.0, initp=0.0): 176 | return PyramidalHorn(3.56, 5.08, 0.762, 0.3386, 1.524, 1.1854, E0, freq, initp) 177 | 178 | 179 | def test_horn(): 180 | f = 6.0e9 181 | cell_sz = 25. / 1000. 182 | scale = 20 183 | z = cell_sz*scale*2.0 184 | 185 | phorn = PyramidalHorn(3.56, 5.08, 0.762, 0.3386, 1.524, 1.1854, 10, f, initp=np.deg2rad(0)) 186 | xl, yl = create_array_pos(cell_sz, scale, scale, ex=True) 187 | magE = np.ndarray((len(yl), len(xl))) 188 | pE = np.ndarray((len(yl), len(xl))) 189 | for (yi, y) in list(enumerate(yl)): 190 | for (xi, x) in list(enumerate(xl)): 191 | Exyz, _, _ = phorn.efield_at_xyz(x, y, z) 192 | mag = np.sqrt(Exyz.item(0)**2 + Exyz.item(1)**2 + Exyz.item(2)**2) 193 | pha = np.angle(Exyz.item(1)) 194 | magE[yi, xi] = np.abs(mag) 195 | pE[yi, xi] = pha 196 | 197 | plt.figure() 198 | plt.pcolor(xl, yl, magE, cmap='jet') 199 | 200 | plt.figure() 201 | plt.pcolor(xl, yl, pE, cmap='jet') 202 | 203 | plt.show() 204 | 205 | if __name__ == '__main__': 206 | test_horn() 207 | -------------------------------------------------------------------------------- /multitests.py: -------------------------------------------------------------------------------- 1 | from hornpattern import get_horn_input_power, get_default_pyramidal_horn, PyramidalHorn 2 | import numpy as np 3 | from sources import Source 4 | from arrayinfo import RAInfo 5 | from rautils import ideal_ref_unit, waveimpd, dB, sph2car, R2F, make_v_mtx 6 | from rasolver import RASolver 7 | from ratasks import Gain2D, Gain3D, FresnelPlane, OnAxisLine, PhiCutPlane 8 | import matplotlib.pyplot as plt 9 | import csv 10 | 11 | 12 | def test_offset_feed(): 13 | freq = 6.0e9 14 | cell_sz = 25 / 1000. 15 | scale = 20 16 | horn = get_default_pyramidal_horn(freq, E0=1.0) 17 | integ = 0.07083 18 | showFig = True 19 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 20 | src = Source() 21 | fdr = 1.0 22 | fpos_offset = (0, cell_sz*2, cell_sz*scale*fdr) 23 | fpos = (0, 0, cell_sz*scale*fdr) 24 | src.append(horn, abg, fpos_offset, dir='parallel') 25 | 26 | tp = [(np.deg2rad(30), 0)] 27 | bs = 2 28 | arr = RAInfo(src, cell_sz, (scale, scale), ('pencil', tp), lambda p:ideal_ref_unit(p, bits=bs)) 29 | solver = RASolver(arr) 30 | phi = np.deg2rad(0) 31 | tsk1 = Gain2D(phi, 300) 32 | #tsk1 = Gain3D(150, 150) 33 | solver.append_task(tsk1) 34 | solver.run() 35 | tsk1.post_process(integ, showFig) 36 | 37 | def line_feed_array(): 38 | freq = 10.0e9 39 | cell_sz = 15 / 1000. 40 | scale = 10 41 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 42 | integ = 1.2068 43 | showFig = True 44 | 45 | hz = cell_sz*scale*0.6 46 | 47 | fd_list = [(0.0, -cell_sz*2, hz), 48 | (0.0, -cell_sz, hz), 49 | (0.0, 0.0, hz), 50 | (0.0, cell_sz, hz), 51 | (0.0, cell_sz*2, hz)] 52 | 53 | src = Source() 54 | for i in range(len(fd_list)): 55 | src.append(get_default_pyramidal_horn(freq, E0=1.0, initp=0.0), abg, fd_list[i], dir='parallel') 56 | 57 | tp = [(0, 0)] 58 | bs = 1 59 | arr = RAInfo(src, cell_sz, (scale, scale), ('pencil', tp), lambda p:ideal_ref_unit(p, bits=bs)) 60 | solver = RASolver(arr) 61 | phi = np.deg2rad(90) 62 | tsk1 = Gain2D(phi, 300) 63 | #tsk1 = Gain3D(200, 200) 64 | solver.append_task(tsk1) 65 | solver.run() 66 | tsk1.post_process(integ*5, showFig) 67 | 68 | def linear_feed_pattern(): 69 | freq = 10e9 70 | #plist = [ 71 | #0, 45, 135, 202.5, 270, 270, 236.25, 247.5, 270, 247.5, 191.25, 112.5, 33.75, 348.75 72 | #] 73 | plist = np.zeros(1) 74 | hlist = [ 75 | PyramidalHorn(3.56, 5.08, 0.762, 0.3386, 1.524, 1.1854, 10.0, freq, initp) for initp in np.deg2rad(plist) 76 | ] 77 | 78 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 79 | ts = np.linspace(-np.pi/2, np.pi/2, 300) 80 | ps = np.deg2rad(0) 81 | R = 1.0 82 | 83 | cell_sz = 180 / 1000. 84 | #pos = np.linspace(-cell_sz*6.5, cell_sz*6.5, 14) 85 | #pos = [-cell_sz/2, cell_sz/2] 86 | pos = [0.0] 87 | 88 | ds = [] 89 | for t in ts: 90 | #Et, Ep = 0j, 0j 91 | """ 92 | #for (i, h) in list(enumerate(hlist)): 93 | x, y, z = sph2car(R, t, ps) 94 | fpt = R2F(*abg) * make_v_mtx(x, y, 0.0) 95 | fpos = (0.0, pos[i], z) 96 | fpt[0][0] -= fpos[0] 97 | fpt[1][0] -= fpos[1] 98 | fpt[2][0] += fpos[2] 99 | _, et, ep = h.efield_at_xyz(fpt.item(0), fpt.item(1), fpt.item(2)) 100 | #_, et, ep = h.efield_at_rtp(R, t, ps) 101 | #Et += et 102 | #Ep += Ep 103 | """ 104 | x, y, z = sph2car(R, t, ps) 105 | #_, Et1, Ep1 = hlist[0].efield_at_xyz(x-pos[0], y, z) 106 | #_, Et2, Ep2 = hlist[1].efield_at_xyz(x-pos[1], y, z) 107 | #Et = Et1 + Et2 108 | #Ep = Ep1 + Ep2 109 | _, Et, Ep = hlist[0].efield_at_xyz(x, y, z) 110 | Etotal = np.sqrt(Et*Et + Ep*Ep) 111 | d = np.abs(Etotal)*np.abs(Etotal)*R*R/(2*waveimpd) 112 | ds.append(d) 113 | 114 | ds = dB(ds) 115 | plt.figure() 116 | plt.plot(np.rad2deg(ts), ds) 117 | plt.show() 118 | 119 | def focal_2bit_calculation(): 120 | freq = 5.8e9 121 | cell_sz = 30 / 1000. 122 | scale = 10 123 | fdr = 0.9 124 | hz = cell_sz*scale*fdr 125 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 126 | showFig = True 127 | 128 | integ = 1.039 # 1.6, 5.8e9 129 | horn = get_default_pyramidal_horn(freq, E0=1.6) 130 | pos = (0.0, 0.0, hz) 131 | src = Source() 132 | src.append(horn, abg, pos) 133 | 134 | focuses = ( 135 | [(1.0, 1.0, 1.0, 1.0)], 136 | [(-0.3, 0.3, 1.5, 1.0), (0.3, -0.3, 1.5, 1.0)], 137 | [(0.3, 0.3, 2.0, 1.0)] 138 | ) 139 | hs = ( 140 | 1.0, 141 | 1.5, 142 | 2.0 143 | ) 144 | planes = ( 145 | (3.0, 3.0), 146 | (1.2, 1.2), 147 | (1.2, 1.2) 148 | ) 149 | points = ( 150 | (301, 301), 151 | (121, 121), 152 | (121, 121) 153 | ) 154 | ps = ( 155 | np.deg2rad(45), 156 | np.deg2rad(135), 157 | np.deg2rad(45) 158 | ) 159 | 160 | Nt, Np = 181, 181 161 | 162 | for idx in range(3): 163 | bs = 2 164 | arr = RAInfo(src, cell_sz, (scale, scale), ('foci', focuses[idx]), lambda p:ideal_ref_unit(p, bits=bs)) 165 | 166 | solver = RASolver(arr) 167 | tsk1 = FresnelPlane(0, 'xx', hs[idx], planes[idx], points[idx]) 168 | tsk2 = Gain2D(ps[idx], Nt, freq) 169 | tsk3 = Gain3D(Np, Nt) 170 | 171 | solver.append_task(tsk1) 172 | solver.append_task(tsk2) 173 | solver.append_task(tsk3) 174 | 175 | solver.run() 176 | 177 | tsk1.post_process(integ, showFig, exfn='experiment/2bit/case{}_plane_theo.fld'.format(idx+1)) 178 | tsk2.post_process(integ, showFig, exfn='experiment/2bit/case{}_2d_theo.csv'.format(idx+1)) 179 | tsk3.post_process(integ, showFig, exfn='experiment/2bit/case{}_3d_theo.csv'.format(idx+1)) 180 | 181 | 182 | def my_unit(pha, amp=1.0, bits=None, pol='Y'): 183 | ret = [] 184 | for i in range(len(pha)): 185 | sp = pha[i] 186 | if bits != None: 187 | step = np.pi*2/(2**bits) 188 | sp = int(pha[i]/step) * step 189 | 190 | if pol == 'X': 191 | sparam = (amp*np.exp(1j*sp), 0j, 0j, 1+0j) 192 | elif pol == 'Y': 193 | sparam = (1+0j, 0j, 0j, amp*np.exp(1j*sp)) 194 | elif pol == 'XY': 195 | sparam = (amp*np.exp(1j*sp), 0j, 0j, amp*np.exp(1j*sp)) 196 | else: 197 | sparam = (amp*np.exp(1j*sp), 0j, 0j, amp*np.exp(1j*(sp-np.pi/2.0))) 198 | 199 | ret.append(sparam) 200 | 201 | return ret 202 | 203 | 204 | def RA_12x12(): 205 | freq = 5.0e9 206 | cell_sz = 33 / 1000. 207 | scale = 12 208 | fdr = 0.9 209 | hz = cell_sz*scale*fdr 210 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 211 | showFig = True 212 | 213 | integ = 30.17114 # 10.0, 5.0e9 214 | horn = get_default_pyramidal_horn(freq) 215 | pos = (0.0, 0.0, hz) 216 | src = Source() 217 | src.append(horn, abg, pos) 218 | 219 | bs = 2 220 | tmp = [(np.deg2rad(0), np.deg2rad(0))] 221 | arr = RAInfo(src, cell_sz, (scale, scale), ('pencil', tmp), lambda p:ideal_ref_unit(p, bits=bs, amp=0.8)) 222 | 223 | solver = RASolver(arr) 224 | tsk1 = Gain2D(np.deg2rad(0), 181) 225 | 226 | solver.append_task(tsk1) 227 | 228 | solver.run() 229 | 230 | tsk1.post_process(integ, showFig, exfn='experiment/12x12/xoz-theo.csv') 231 | 232 | 233 | def circle_unit_data_table(): 234 | fn = 'experiment/s11tetm-circle.csv' 235 | data_table = [] 236 | csvf = open(fn) 237 | sparam = csv.reader(csvf) 238 | for row in sparam: 239 | row = [float(s) for s in row] 240 | d = [] 241 | for i in range(4): 242 | d.append(row[i*2] + 1j*row[i*2+1]) 243 | data_table.append(d) 244 | #print(d) 245 | rad_list = [] 246 | for s in data_table: 247 | rad_list.append(np.angle(s[0])) 248 | #print(rad_list) 249 | csvf.close() 250 | return data_table, rad_list 251 | 252 | sparam_dt, s11_rads = circle_unit_data_table() 253 | 254 | def get_sparam_line_idx(rad): 255 | rad -= np.pi 256 | if rad > s11_rads[0]: 257 | return 0 258 | elif rad < s11_rads[-1]: 259 | return len(s11_rads) - 1 260 | for i in range(len(s11_rads)-1): 261 | if rad < s11_rads[i] and rad > s11_rads[i+1]: 262 | mid = (s11_rads[i] + s11_rads[i+1]) / 2.0 263 | if rad >= (mid): 264 | return i 265 | else: 266 | return i+1 267 | 268 | def circle_unit(pha): 269 | ret = [] 270 | for i in range(len(pha)): 271 | p = pha[i] 272 | idx = get_sparam_line_idx(p) 273 | ret.append(sparam_dt[idx]) 274 | 275 | return ret 276 | 277 | 278 | 279 | def test_fresnel_plane(): 280 | freq = 6.0e9 281 | cell_sz = 25 / 1000. 282 | lmbd = 3e8 / freq 283 | scale = 20 284 | fdr = 0.8 285 | hz = cell_sz*scale*fdr 286 | horn = get_default_pyramidal_horn(freq) 287 | pos = (0.0, 0.0, hz) 288 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 289 | showFig = True 290 | 291 | far_z = 2 * (scale*cell_sz*np.sqrt(2)) ** 2 / lmbd 292 | focal = [(0.0, 0.0, 5.0, 1.0)] 293 | 294 | src = Source() 295 | src.append(horn, abg, pos) 296 | 297 | arr = RAInfo(src, cell_sz, (scale, scale), ('foci', focal), circle_unit) 298 | 299 | solver = RASolver(arr, type='fresnel') 300 | 301 | tsk = FresnelPlane(0, 'xx', 5.0, (1.0, 1.0), (41, 41)) 302 | solver.append_task(tsk) 303 | 304 | solver.run() 305 | 306 | tsk.post_process(showFig, None) 307 | 308 | 309 | def test_fresnel_onaxis(): 310 | freq = 6.0e9 311 | cell_sz = 25 / 1000. 312 | lmbd = 3e8 / freq 313 | scale = 20 314 | fdr = 0.8 315 | hz = cell_sz*scale*fdr 316 | horn = get_default_pyramidal_horn(freq) 317 | pos = (0.0, 0.0, hz) 318 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 319 | showFig = True 320 | far_z = 2 * (scale*cell_sz*np.sqrt(2)) ** 2 / lmbd 321 | 322 | focal_rio = 0.1 323 | focal = [(0.0, 0.0, focal_rio*far_z, 1.0)] 324 | 325 | src = Source() 326 | src.append(horn, abg, pos) 327 | 328 | arr = RAInfo(src, cell_sz, (scale, scale), ('foci', focal), circle_unit) 329 | 330 | solver = RASolver(arr, type='fresnel') 331 | 332 | plane_rio = np.linspace(0.01, 0.5, 200) 333 | zlist = [pr*far_z for pr in plane_rio] 334 | 335 | tsk = OnAxisLine(zlist, plane_rio) 336 | solver.append_task(tsk) 337 | 338 | solver.run() 339 | 340 | tsk.post_process(showFig, None) 341 | 342 | 343 | def test_fresnel_phicut(): 344 | freq = 6.0e9 345 | cell_sz = 25 / 1000. 346 | lmbd = 3e8 / freq 347 | scale = 20 348 | fdr = 0.8 349 | hz = cell_sz*scale*fdr 350 | horn = get_default_pyramidal_horn(freq) 351 | pos = (0.0, 0.0, hz) 352 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 353 | showFig = True 354 | 355 | far_z = 2 * (scale*cell_sz*np.sqrt(2)) ** 2 / lmbd 356 | focal = [(0.5, 0.5, 1.0, 1.0), (-0.5, -0.5, 1.0, 1.0)] 357 | 358 | src = Source() 359 | src.append(horn, abg, pos) 360 | 361 | arr = RAInfo(src, cell_sz, (scale, scale), ('foci', focal), circle_unit) 362 | 363 | solver = RASolver(arr, type='fresnel') 364 | 365 | tsk = PhiCutPlane((2.0, 1.5), (21, 21), phi=np.deg2rad(45)) 366 | 367 | solver.append_task(tsk) 368 | 369 | solver.run() 370 | 371 | tsk.post_process(showFig, None) 372 | 373 | 374 | if __name__ == '__main__': 375 | test_fresnel_phicut() 376 | #test_fresnel_plane() 377 | #test_fresnel_onaxis() 378 | #test_offset_feed() 379 | #line_feed_array() 380 | #linear_feed_pattern() 381 | #focal_2bit_calculation() 382 | #RA_12x12() 383 | 384 | -------------------------------------------------------------------------------- /rasolver.py: -------------------------------------------------------------------------------- 1 | from hornpattern import PyramidalHorn, get_default_pyramidal_horn, get_horn_input_power 2 | from arrayinfo import RAInfo 3 | from sources import PlaneWave, Source 4 | from rautils import gsinc, ideal_ref_unit, dB, sph2car_mtx, make_v_mtx, farR, Fresnel 5 | from ratasks import Gain2D, Gain3D, EfieldResult, NearFieldResult 6 | import numpy as np 7 | import matplotlib.pyplot as plt 8 | import time 9 | import concurrent.futures 10 | import threading 11 | 12 | 13 | """ 14 | 1. array info (cell size scale | horns) 15 | 2. get phase 16 | 3. get tetm 17 | 4. add task 18 | 5. calc 19 | """ 20 | 21 | class RASolver: 22 | 23 | def __init__(self, rainfo, type='far'): 24 | self.rainfo = rainfo 25 | self.tasks = [] 26 | self.lock = threading.Lock() 27 | self.type = type 28 | 29 | def __erxy_fft(self, u, v): 30 | px, py = self.rainfo.get_pxy() 31 | Nx, Ny = self.rainfo.get_Nxy() 32 | dx, dy = self.rainfo.get_dxy() 33 | k0 = self.rainfo.get_k0() 34 | K1 = np.exp(-1j*k0/2.0 * (u*(Nx-1)*dx + v*(Ny-1)*dy)) 35 | 36 | d_sumx, d_sumy = 0.0, 0.0 37 | for (i, (Exmn, Eymn)) in list(enumerate(self.rainfo)): 38 | n, m = int(i / Nx), int(i % Nx) 39 | ejk = np.exp(1j*k0*(u*m*dx+v*n*dy)) 40 | d_sumx += (Exmn * ejk) 41 | d_sumy += (Eymn * ejk) 42 | 43 | A = K1 * px *py * gsinc(k0*u*px/2.0) * gsinc(k0*v*py/2.0) 44 | return A*d_sumx, A*d_sumy 45 | 46 | def __calc_one_point(self, r, t, p): 47 | u = np.sin(t) * np.cos(p) 48 | v = np.sin(t) * np.sin(p) 49 | 50 | Erx, Ery = self.__erxy_fft(u, v) 51 | 52 | k0 = self.rainfo.get_k0() 53 | R = r 54 | E_phi = -1j*k0*np.exp(-1j*k0*R)/(2*np.pi*R)*np.cos(t) * (Erx * np.sin(p) - Ery * np.cos(p)) 55 | E_theta = 1j*k0*np.exp(-1j*k0*R)/(2*np.pi*R) * (Erx * np.cos(p) + Ery * np.sin(p)) 56 | 57 | return EfieldResult(E_theta, E_phi, (r, t, p)) 58 | 59 | def __calc_fresnel_point(self, x, y, z): 60 | Ex, Ey, Ez = 0j, 0j, 0j 61 | px, py = self.rainfo.get_pxy() 62 | Nx, Ny = self.rainfo.get_Nxy() 63 | 64 | k0 = self.rainfo.get_k0() 65 | 66 | integ_sum = 0j 67 | 68 | for (i, (Exmn, Eymn)) in list(enumerate(self.rainfo)): 69 | m, n = int(i / Nx), int(i % Nx) 70 | A = m*px - (Nx-1)*px/2 71 | B = n*py - (Ny-1)*py/2 72 | t2 = (-px/2+x-A) * np.sqrt(k0/(np.pi*z)) 73 | t1 = (px/2+x-A) * np.sqrt(k0/(np.pi*z)) 74 | t2p = (-py/2+y-B) * np.sqrt(k0/(np.pi*z)) 75 | t1p = (py/2+y-B) * np.sqrt(k0/(np.pi*z)) 76 | Ix = Fresnel(t2) - Fresnel(t1) 77 | Iy = Fresnel(t2p) - Fresnel(t1p) 78 | integ_sum += Eymn * Ix * Iy 79 | 80 | Ey = 1j/2.0 * np.exp(-1j*k0*z) * integ_sum 81 | 82 | return NearFieldResult(Ex, Ey, Ez, (x, y, z)) 83 | 84 | # add far zone task 85 | def append_task(self, tsk): 86 | self.tasks.append(tsk) 87 | 88 | # calc a task in a thread 89 | def __calc_one_task__(self, tsk): 90 | #with self.lock: 91 | for (a, b, c) in tsk: 92 | if self.type == 'far': 93 | tsk.set_current_result(self.__calc_one_point(a, b, c)) 94 | elif self.type == 'fresnel': 95 | tsk.set_current_result(self.__calc_fresnel_point(a, b, c)) # this is x y z actually 96 | else: 97 | raise ValueError('type error') 98 | return tsk 99 | 100 | # iterate on tasks, each task use multi-threading 101 | def run(self): 102 | for task in self.tasks: 103 | field_task = task.assign_task() 104 | start_time = time.clock() 105 | for tsk in field_task: 106 | ret = self.__calc_one_task__(tsk) 107 | task.set_results(ret) 108 | print(time.clock()-start_time, "sec") 109 | 110 | # FixMe bug with concurrency 111 | def run_concurrency(self): 112 | for task in self.tasks: 113 | field_task = task.assign_task() 114 | start_time = time.clock() 115 | 116 | #t_num = int(len(field_task)) 117 | t_num = 4 118 | with concurrent.futures.ThreadPoolExecutor(max_workers=t_num) as e: 119 | futs = [e.submit(self.__calc_one_task__, tsk) for tsk in field_task] 120 | 121 | for fut in concurrent.futures.as_completed(futs): 122 | #task.set_results(futs[fut]) 123 | task.set_results(fut.result()) 124 | 125 | print(time.clock()-start_time, "sec") 126 | 127 | 128 | def test_multi(): 129 | freq = 5e9 130 | cell_sz = 30. / 1000. 131 | scale = 30 132 | 133 | # pre calculated horn power integration at 5GHz 134 | horn_integ = 22732.769823328235 135 | 136 | abg = (np.deg2rad(180), np.deg2rad(180), np.deg2rad(0)) 137 | src = Source() 138 | horn = get_default_pyramidal_horn(freq) 139 | src.append(horn, abg, (0., 0., cell_sz*scale)) 140 | tp = [(np.deg2rad(20), np.deg2rad(0)), (np.deg2rad(20), np.deg2rad(90)), 141 | (np.deg2rad(20), np.deg2rad(180)), (np.deg2rad(20), np.deg2rad(270))] 142 | #tp = [(np.deg2rad(0), np.deg2rad(0))] 143 | tpm = [(np.deg2rad(0), np.deg2rad(0), 1)] 144 | 145 | arr = RAInfo(src, cell_sz, (scale, scale), ('pencil', (tp)), ideal_ref_unit) 146 | #arr = RAInfo(src, cell_sz, (scale, scale), ('oam', (tpm, np.deg2rad(0))), ideal_ref_unit) 147 | solver = RASolver(arr) 148 | tsk1 = Gain2D(np.deg2rad(0), 999) 149 | tsk2 = Gain2D(np.deg2rad(90), 600) 150 | tsk3 = Gain3D(100, 100) 151 | solver.append_task(tsk1) 152 | #solver.append_task(tsk2) 153 | #solver.append_task(tsk3) 154 | #solver.run() 155 | solver.run_concurrency() 156 | tsk1.post_process(horn_integ, True) 157 | #tsk2.post_process(horn_integ, True) 158 | #tsk3.post_process(horn_integ, True) 159 | 160 | 161 | if __name__ == '__main__': 162 | test_multi() 163 | -------------------------------------------------------------------------------- /ratasks.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from rautils import farR, sph2car_mtx, make_v_mtx, dB, car2sph, waveimpd 3 | import threading 4 | import matplotlib.pyplot as plt 5 | from matplotlib import cm 6 | import cmath 7 | 8 | class EfieldResult: 9 | def __init__(self, Etheta, Ephi, pos): 10 | (r, t, p) = pos 11 | self.Etheta = Etheta 12 | self.Ephi = Ephi 13 | self.Pos = pos 14 | self.Etotal = np.sqrt(Etheta*Etheta + Ephi*Ephi) 15 | xyz_mtx = sph2car_mtx(t, p) * make_v_mtx(0j, Etheta, Ephi) 16 | self.Ex = xyz_mtx.item(0) 17 | self.Ey = xyz_mtx.item(1) 18 | self.Ez = xyz_mtx.item(2) 19 | 20 | def get_etotal(self): 21 | return self.Etotal 22 | 23 | def get_sph_field(self): 24 | return 0j, self.Etheta, self.Ephi 25 | 26 | def get_car_field(self): 27 | return self.Ex, self.Ey, self.Ez 28 | 29 | def get_directivity(self): 30 | (r, t, p) = self.Pos 31 | return np.abs(self.Etotal)*np.abs(self.Etotal)*r*r/(2*waveimpd) 32 | 33 | def get_gain(self, ipower): 34 | return 4*np.pi*np.abs(self.Etotal)*np.abs(self.Etotal) * farR * farR / (ipower * 2 * waveimpd) 35 | 36 | def get_rE(self, type='total'): 37 | (r, t, p) = self.Pos 38 | if type == 'total': 39 | return self.Etotal * r 40 | elif type == 'theta': 41 | return self.Etheta * r 42 | elif type == 'phi': 43 | return self.Ephi * r 44 | 45 | class NearFieldResult: 46 | def __init__(self, Ex, Ey, Ez, pos): 47 | self.Ex = Ex 48 | self.Ey = Ey 49 | self.Ez = Ez 50 | self.Pos = pos 51 | self.Etotal = np.sqrt(Ex*Ex + Ey*Ey + Ez*Ez) 52 | 53 | def get_etotal(self): 54 | return self.Etotal 55 | 56 | 57 | def get_car_field(self): 58 | return self.Ex, self.Ey, self.Ez 59 | 60 | 61 | class Task: 62 | def __init__(self, oid, pos): 63 | self.oid = oid 64 | self.pos = pos 65 | self.results = np.empty(len(pos), dtype=EfieldResult) 66 | self.cnt = 0 67 | self.lock = threading.Lock() 68 | 69 | def __len__(self): 70 | return len(self.pos) 71 | 72 | def __iter__(self): 73 | with self.lock: 74 | self.cnt = 0 75 | return self 76 | 77 | def __next__(self): 78 | with self.lock: 79 | if self.cnt == len(self): 80 | raise StopIteration 81 | ret = self.pos[self.cnt] 82 | self.cnt += 1 83 | return ret 84 | 85 | def set_current_result(self, efield): 86 | with self.lock: 87 | self.results[self.cnt-1] = efield 88 | 89 | def get_old_idx(self): 90 | return self.oid 91 | 92 | def get_results(self): 93 | return self.results 94 | 95 | 96 | class FarZone: 97 | def __init__(self, row, col, freq=10e9): 98 | self.row = row 99 | self.col = col 100 | self.nrow = len(row) 101 | self.ncol = len(col) 102 | self.alldat = np.empty(self.nrow*self.ncol, dtype=EfieldResult) 103 | self.lock = threading.Lock() 104 | self.R = farR 105 | self.freq = freq 106 | 107 | def __len__(self): 108 | return self.nrow * self.ncol 109 | 110 | def set_R(self, r): 111 | self.R = r 112 | 113 | def set_results(self, tsk): 114 | with self.lock: 115 | b, e = tsk.get_old_idx() 116 | for i in range(b, e): 117 | self.alldat.put(i, tsk.get_results()[i-b]) 118 | 119 | def assign_task(self, mp=200): 120 | if len(self) <= mp: 121 | pos = [(self.R, t, p) for t in self.col for p in self.row] 122 | return [Task((0, len(self)), pos)] 123 | else: 124 | tsk = [] 125 | b, e = 0, 0 126 | pos = [] 127 | for p in self.row: 128 | for t in self.col: 129 | pos.append((self.R, t, p)) 130 | e += 1 131 | if e - b == mp: 132 | tsk.append(Task((b, e), pos)) 133 | pos = [] 134 | b = e 135 | tsk.append(Task((b, e), pos)) 136 | return tsk 137 | 138 | 139 | class Gain2D(FarZone): 140 | def __init__(self, phi, ntheta, freq=10e9): 141 | ts = np.linspace(-np.pi/2, np.pi/2, ntheta) 142 | super().__init__([phi], ts, freq) 143 | 144 | def post_process(self, integ, fig=False, exfn=None): 145 | fields = np.reshape(self.alldat, (self.nrow, self.ncol)) 146 | gs = [x.get_gain(integ) for x in fields[0]] 147 | gs = dB(gs) 148 | 149 | if fig: 150 | plt.figure() 151 | plt.plot(self.col, gs) 152 | plt.ylim(-30, 40) 153 | plt.show() 154 | 155 | if exfn != None: 156 | afile = open(exfn, 'w') 157 | afile.write('Theta[deg],dB(GainTotal)[] - Freq=\'{}GHz\' Phi=\'{}deg\'\n' 158 | .format(self.freq/1e9, np.rad2deg(self.row[0]))) 159 | ts = np.rad2deg(self.col) 160 | for i in range(len(ts)): 161 | afile.write('{},{}\n'.format(ts[i], gs[i])) 162 | afile.close() 163 | 164 | 165 | class Gain3D(FarZone): 166 | def __init__(self, nphi, ntheta, freq=1e9): 167 | self.ps = np.linspace(0, np.pi*2, nphi) 168 | self.ts = np.linspace(-np.pi/2, np.pi/2, ntheta) 169 | super().__init__(self.ps, self.ts, freq) 170 | 171 | def post_process(self, integ, fig=False, exfn=None): 172 | fields = np.reshape(self.alldat, (self.nrow, self.ncol)) 173 | gs = np.ndarray(shape=fields.shape) 174 | for (id, field) in list(enumerate(fields)): 175 | g = dB([x.get_gain(integ) for x in field]) 176 | gs[id,:] = np.array(g) 177 | 178 | if exfn != None: 179 | afile = open(exfn, 'w') 180 | afile.write('Phi[deg],Theta[deg],dB(GainTotal)\n') 181 | ps = np.rad2deg(self.row) 182 | ts = np.rad2deg(self.col) 183 | for i in range(self.ncol): 184 | for j in range(self.nrow): #j phi 185 | afile.write('{},{},{}\n'.format(ps[j], ts[i], gs[j, i])) 186 | afile.close() 187 | 188 | if fig: 189 | T, P = np.meshgrid(self.ts, self.ps) 190 | for i in range(len(self.ps)): 191 | for j in range(len(self.ts)): 192 | if gs[i,j] < -10: 193 | gs[i, j] = -10 194 | 195 | gs = gs - np.min(gs) 196 | 197 | X = gs * np.sin(T) * np.cos(P) 198 | Y = gs * np.sin(T) * np.sin(P) 199 | Z = gs * np.cos(T) 200 | 201 | fg = plt.figure() 202 | #ax = fg.gca(projection='3d') 203 | ax = fg.gca() 204 | 205 | surf = ax.plot_surface(X, Y, Z, cmap=cm.jet, 206 | rstride=1, cstride=1, 207 | linewidth=0, antialiased=False, shade=True) 208 | 209 | fg.colorbar(surf, shrink=0.5, aspect=5) 210 | plt.show() 211 | 212 | 213 | class rE3D(FarZone): 214 | def __init__(self, nphi, ntheta, freq=1e9): 215 | self.ps = np.linspace(0, np.pi*2, nphi) 216 | self.ts = np.linspace(-np.pi/2, np.pi/2, ntheta) 217 | super().__init__(self.ps, self.ts, freq) 218 | 219 | def post_process(self, type='total', fig=False, mfn=None, pfn=None): 220 | fields = np.reshape(self.alldat, (self.nrow, self.ncol)) 221 | gs = np.ndarray(shape=fields.shape, dtype=complex) 222 | 223 | for (id, field) in list(enumerate(fields)): 224 | g = [x.get_rE(type) for x in field] 225 | gs[id,:] = np.array(g) 226 | 227 | 228 | if mfn != None: 229 | afile = open(mfn, 'w') 230 | afile.write('Phi[deg],Theta[deg],mag(rETotal)[V]\n') 231 | ps = np.rad2deg(self.row) 232 | ts = np.rad2deg(self.col) 233 | for i in range(self.ncol): 234 | for j in range(self.nrow): #j phi 235 | afile.write('{},{},{}\n'.format(ps[j], ts[i], np.abs(gs[j, i]))) 236 | afile.close() 237 | 238 | if pfn != None: 239 | afile = open(pfn, 'w') 240 | afile.write('Phi[deg],Theta[deg],phase(rETotal)[deg]\n') 241 | ps = np.rad2deg(self.row) 242 | ts = np.rad2deg(self.col) 243 | for i in range(self.ncol): 244 | for j in range(self.nrow): #j phi 245 | afile.write('{},{},{}\n'.format(ps[j], ts[i], np.angle(gs[j, i], deg=True))) 246 | afile.close() 247 | 248 | if fig: 249 | ps = self.row 250 | ts = self.col 251 | T, P = np.meshgrid(ts, ps) 252 | 253 | plt.figure() 254 | plt.pcolor(np.sin(T)*np.cos(P), np.sin(T)*np.sin(P), np.abs(gs)) 255 | plt.colorbar() 256 | 257 | plt.figure() 258 | plt.pcolor(np.sin(T)*np.cos(P), np.sin(T)*np.sin(P), np.angle(gs, deg=True)) 259 | plt.colorbar() 260 | 261 | plt.show() 262 | 263 | 264 | class Directivity2D(FarZone): 265 | def __init__(self, phi, ntheta, freq=10e9): 266 | ts = np.linspace(-np.pi/2, np.pi/2, ntheta) 267 | super().__init__([phi], ts, freq) 268 | 269 | def post_process(self, integ, fig=False, exfn=None): 270 | fields = np.reshape(self.alldat, (self.nrow, self.ncol)) 271 | gs = [x.get_directivity() for x in fields[0]] 272 | gs = dB(gs) 273 | 274 | if fig: 275 | plt.figure() 276 | plt.plot(self.col, gs) 277 | plt.ylim(-30, 40) 278 | plt.show() 279 | 280 | if exfn != None: 281 | afile = open(exfn, 'w') 282 | afile.write('Theta[deg],dB(GainTotal)[] - Freq=\'{}GHz\' Phi=\'{}deg\'\n' 283 | .format(self.freq/1e9, np.rad2deg(self.row[0]))) 284 | ts = np.rad2deg(self.col) 285 | for i in range(len(ts)): 286 | afile.write('{},{}\n'.format(ts[i], gs[i])) 287 | afile.close() 288 | 289 | class Directivity3D(FarZone): 290 | pass 291 | 292 | class FresnelPlane: 293 | def __init__(self, t, axis, r0, wxy, Nxy): 294 | if axis == 'X': 295 | rt = np.matrix([ 296 | [1, 0, 0], 297 | [0, np.cos(t), -np.sin(t)], 298 | [0, np.sin(t), np.cos(t)] 299 | ]) 300 | elif axis == 'Y': 301 | rt = np.matrix([ 302 | [np.cos(t), 0, np.sin(t)], 303 | [0, 1, 0], 304 | [-np.sin(t), 0, np.cos(t)] 305 | ]) 306 | elif axis == 'Z': 307 | rt = np.matrix([ 308 | [np.cos(t), -np.sin(t), 0], 309 | [np.sin(t), np.cos(t), 0], 310 | [0, 0, 1] 311 | ]) 312 | else: 313 | rt = np.matrix([ 314 | [1, 0, 0], 315 | [0, 1, 0], 316 | [0, 0, 1] 317 | ]) 318 | wx, wy = wxy 319 | Nx, Ny = Nxy 320 | ox = np.linspace(-wx/2, wx/2, Nx) 321 | oy = np.linspace(-wy/2, wy/2, Ny) 322 | self.allpos = [] 323 | self.alldat = np.empty(Nx*Ny, dtype=NearFieldResult) 324 | self.lock = threading.Lock() 325 | self.size = Nx*Ny 326 | self.Nx = Nx 327 | self.Ny = Ny 328 | self.ox = ox 329 | self.oy = oy 330 | self.r0 = r0 331 | 332 | for y in oy: 333 | for x in ox: 334 | oxyz = np.matrix([x, y, r0]) 335 | oxyz = np.transpose(oxyz) 336 | xyz = rt * oxyz 337 | self.allpos.append((xyz.item(0), xyz.item(1), xyz.item(2))) 338 | 339 | def __len__(self): 340 | return self.size 341 | 342 | def set_results(self, tsk): 343 | with self.lock: 344 | b, e = tsk.get_old_idx() 345 | for i in range(b, e): 346 | self.alldat.put(i, tsk.get_results()[i-b]) 347 | 348 | def assign_task(self, mp=200): 349 | if len(self) <= mp: 350 | return [Task((0, len(self)), self.allpos)] 351 | else: 352 | tsk = [] 353 | b, e = 0, 0 354 | pos = [] 355 | 356 | for i in range(len(self)): 357 | pos.append(self.allpos[i]) 358 | e += 1 359 | if e - b == mp: 360 | tsk.append(Task((b, e), pos)) 361 | pos = [] 362 | b = e 363 | tsk.append(Task((b, e), pos)) 364 | return tsk 365 | 366 | def post_process(self, fig=False, mfn=None): 367 | mag, phase = [], [] 368 | for dat in self.alldat: 369 | total = dat.get_etotal() 370 | mag.append(np.abs(total)) 371 | 372 | mag = np.reshape(mag, (self.Nx, self.Ny)) 373 | 374 | if fig: 375 | plt.figure() 376 | plt.pcolor(self.ox, self.oy, mag, cmap='jet') 377 | plt.colorbar() 378 | plt.show() 379 | 380 | 381 | if mfn != None: 382 | afile = open(mfn, 'w') 383 | afile.write('X[m],Y[m],mag(ETotal)[V/m]\n') 384 | for i in range(len(mag)): 385 | for j in range(len(mag[0])): #j phi 386 | afile.write('{},{},{}\n'.format(self.ox[i], self.oy[j], mag[i,j])) 387 | afile.close() 388 | 389 | 390 | class OnAxisLine: 391 | def __init__(self, zlist, zrio): 392 | self.allpos = [(0.0, 0.0, z) for z in zlist] 393 | self.alldat = np.empty(len(zlist), dtype=NearFieldResult) 394 | self.size = len(zlist) 395 | self.zlist = zlist 396 | self.zrio = zrio 397 | 398 | def __len__(self): 399 | return self.size 400 | 401 | def set_results(self, tsk): 402 | b, e = tsk.get_old_idx() 403 | for i in range(b, e): 404 | self.alldat.put(i, tsk.get_results()[i-b]) 405 | 406 | def assign_task(self, mp=200): 407 | if len(self) <= mp: 408 | return [Task((0, len(self)), self.allpos)] 409 | else: 410 | tsk = [] 411 | b, e = 0, 0 412 | pos = [] 413 | 414 | for i in range(len(self)): 415 | pos.append(self.allpos[i]) 416 | e += 1 417 | if e - b == mp: 418 | tsk.append(Task((b, e), pos)) 419 | pos = [] 420 | b = e 421 | tsk.append(Task((b, e), pos)) 422 | return tsk 423 | 424 | def post_process(self, fig=False, mfn=None): 425 | mag, phase = [], [] 426 | for dat in self.alldat: 427 | total = dat.get_etotal() 428 | mag.append(np.abs(total)) 429 | 430 | if fig: 431 | plt.figure() 432 | plt.plot(self.zrio, mag) 433 | plt.show() 434 | 435 | if mfn != None: 436 | afile = open(mfn, 'w') 437 | afile.write('Z[m],mag(ETotal)[V/m]\n') 438 | for idx in range(len(self)): 439 | afile.write('{},{}\n'.format(self.zlist[idx], mag[idx])) 440 | afile.close() 441 | 442 | 443 | # FixMe coordinate bug 444 | class PhiCutPlane: 445 | def __init__(self, wxz, Nxz, phi=0.0): 446 | wx, wz = wxz 447 | Nx, Nz = Nxz 448 | ox = np.linspace(-wx/2.0, wx/2.0, Nx) 449 | oz = np.linspace(1e-4, wz, Nz) 450 | self.ox = ox 451 | self.oz = oz 452 | self.Nx = Nx 453 | self.Nz = Nz 454 | self.allpos = [] 455 | self.alldat = np.empty(Nx*Nz, dtype=NearFieldResult) 456 | self.size = Nx * Nz 457 | self.phi = phi - np.pi/2.0 458 | 459 | for z in oz: 460 | for x in ox: 461 | nx, ny = x*np.cos(phi), x*np.sin(phi) 462 | self.allpos.append((nx, ny, z)) 463 | print(ox) 464 | print(oz) 465 | 466 | def __len__(self): 467 | return self.size 468 | 469 | def set_results(self, tsk): 470 | b, e = tsk.get_old_idx() 471 | for i in range(b, e): 472 | self.alldat.put(i, tsk.get_results()[i-b]) 473 | 474 | def assign_task(self, mp=200): 475 | if len(self) <= mp: 476 | return [Task((0, len(self)), self.allpos)] 477 | else: 478 | tsk = [] 479 | b, e = 0, 0 480 | pos = [] 481 | 482 | for i in range(len(self)): 483 | pos.append(self.allpos[i]) 484 | e += 1 485 | if e - b == mp: 486 | tsk.append(Task((b, e), pos)) 487 | pos = [] 488 | b = e 489 | tsk.append(Task((b, e), pos)) 490 | return tsk 491 | 492 | def post_process(self, fig=False, mfn=None): 493 | mag, phase = [], [] 494 | for dat in self.alldat: 495 | total = dat.get_etotal() 496 | mag.append(np.abs(total)) 497 | 498 | mag = np.reshape(mag, (self.Nz, self.Nx)) 499 | if fig: 500 | plt.figure() 501 | plt.pcolor(mag, cmap='jet') 502 | plt.colorbar() 503 | plt.show() 504 | 505 | if mfn != None: 506 | afile = open(mfn, 'w') 507 | afile.write('X[m], Z[m],mag(ETotal)[V/m]\n') 508 | for i in range(len(mag)): 509 | for j in range(len(mag[0])): #j phi 510 | afile.write('{},{},{}\n'.format(self.ox[i], self.oz[j], mag[i,j])) 511 | afile.close() 512 | 513 | 514 | 515 | if __name__ == '__main__': 516 | #g2d = Gain2D(np.deg2rad(0), 100.) 517 | f2d = FresnelPlane(0.0, '0', 1.0, (0.5, 0.5), (50, 50)) 518 | tsks = f2d.assign_task() 519 | 520 | for (i, tsk) in list(enumerate(tsks)): 521 | print('in task {}'.format(i)) 522 | for (r, t, p) in tsk: 523 | print('r={},t={},p={}'.format(r, t, p)) 524 | print('\n') 525 | 526 | 527 | -------------------------------------------------------------------------------- /rautils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | sol = 299792458 # speed of light unit:m/s 5 | farR = 10 6 | waveimpd = 119.9169832 * np.pi 7 | 8 | def distance(pt1, pt2): 9 | return np.sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2 + (pt1[2]-pt2[2])**2) 10 | 11 | def create_array_pos(cell_sz, scalex, scaley, ex): 12 | nx = scalex+1 if ex else scalex 13 | ny = scaley+1 if ex else scaley 14 | xlist = np.linspace(-cell_sz*scalex/2.+cell_sz/2., cell_sz*scalex/2+cell_sz/2., nx, endpoint=ex) 15 | ylist = np.linspace(-cell_sz*scaley/2.+cell_sz/2., cell_sz*scaley/2+cell_sz/2., ny, endpoint=ex) 16 | return xlist, ylist 17 | 18 | def gsinc(x, k=1.0): 19 | return 1.0 if x == 0.0 else np.sin(k*x) / (k*x) 20 | 21 | def dB(dat, type=''): 22 | ret = dat.copy() 23 | for (i, d) in list(enumerate(ret)): 24 | factor = 20. if type == 'power' else 10.0 25 | ret[i] = factor * np.log10(d) 26 | return ret 27 | 28 | def gain2mag(gain): 29 | ret = gain.copy() 30 | for (i, g) in list(enumerate(ret)): 31 | ret[i] = 10. ** (g / 10.) 32 | return ret 33 | 34 | def norm2zero(dat): 35 | md = np.max(dat) 36 | ret = dat.copy() 37 | for (i, d) in list(enumerate(ret)): 38 | ret[i] = d - md 39 | return ret 40 | 41 | def sph2car_mtx(theta, phi): 42 | return np.matrix( 43 | [ 44 | [np.sin(theta)*np.cos(phi), np.cos(theta)*np.cos(phi), -np.sin(phi)], 45 | [np.sin(theta)*np.sin(phi), np.cos(theta)*np.sin(phi), np.cos(phi)], 46 | [np.cos(theta), -np.sin(theta), 0] 47 | ] 48 | ) 49 | 50 | def car2sph_mtx(theta, phi): 51 | return sph2car_mtx(theta, phi).transpose() 52 | 53 | def sph2car(r, theta, phi): 54 | x = r*np.sin(theta)*np.cos(phi) 55 | y = r*np.sin(theta)*np.sin(phi) 56 | z = r*np.cos(theta) 57 | return x, y, z 58 | 59 | def car2sph(x, y, z): 60 | r = np.sqrt(x*x+y*y+z*z) 61 | theta = np.arccos(z/r) 62 | phi = np.arctan2(y, x) 63 | return r, theta, phi 64 | 65 | def make_v_mtx(a, b, c): 66 | return np.matrix( 67 | [ 68 | [a], 69 | [b], 70 | [c] 71 | ] 72 | ) 73 | 74 | def R2F(alpha, beta, gamma): 75 | mtx1 = np.matrix([[np.cos(gamma), np.sin(gamma), 0], 76 | [-np.sin(gamma), np.cos(gamma), 0], 77 | [0, 0, 1]]) 78 | mtx2 = np.matrix([[1, 0, 0], 79 | [0, np.cos(beta), np.sin(beta)], 80 | [0, -np.sin(beta), np.cos(beta)]]) 81 | mtx3 = np.matrix([[np.cos(alpha), np.sin(alpha), 0], 82 | [-np.sin(alpha), np.cos(alpha), 0], 83 | [0, 0, 1]]) 84 | 85 | A_cc = mtx1 * mtx2 * mtx3 86 | return A_cc 87 | 88 | def F2R(alpha, beta, gamma): 89 | return R2F(alpha, beta, gamma).transpose() 90 | 91 | def ideal_ref_unit(pha, amp=1.0, bits=None, pol='Y'): 92 | ret = [] 93 | for i in range(len(pha)): 94 | sp = pha[i] 95 | if bits != None: 96 | step = np.pi*2/(2**bits) 97 | sp = int(pha[i]/step) * step 98 | 99 | if pol == 'X': 100 | sparam = (amp*np.exp(1j*sp), 0j, 0j, 1+0j) 101 | elif pol == 'Y': 102 | sparam = (1+0j, 0j, 0j, amp*np.exp(1j*sp)) 103 | elif pol == 'XY': 104 | sparam = (amp*np.exp(1j*sp), 0j, 0j, amp*np.exp(1j*sp)) 105 | else: 106 | sparam = (amp*np.exp(1j*sp), 0j, 0j, amp*np.exp(1j*(sp-np.pi/2.0))) 107 | 108 | ret.append(sparam) 109 | 110 | return ret 111 | 112 | def far_field_distance(freq, maxlen): 113 | """ 114 | Calculate far-field distance 115 | :param freq: unit : GHz 116 | :param maxlen: max length of the aperture antenna, unit : m 117 | :return: far-field distance, unit : m 118 | """ 119 | return 2 * maxlen * maxlen / (sol / freq) 120 | 121 | 122 | def Fresnel(x): 123 | A = [ 124 | 1.595769140, 125 | -0.000001702, 126 | -6.808508854, 127 | -0.000576361, 128 | 6.920691902, 129 | -0.016898657, 130 | -3.050485660, 131 | -0.075752419, 132 | 0.850663781, 133 | -0.025639041, 134 | -0.150230960, 135 | 0.034404779 136 | ] 137 | 138 | B = [ 139 | -0.000000033, 140 | 4.255387524, 141 | -0.000092810, 142 | -7.780020400, 143 | -0.009520895, 144 | 5.075161298, 145 | -0.138341947, 146 | -1.363729124, 147 | -0.403349276, 148 | 0.702222016, 149 | -0.216195929, 150 | 0.019547031 151 | ] 152 | 153 | C = [ 154 | 0, 155 | -0.024933975, 156 | 0.000003936, 157 | 0.005770956, 158 | 0.000689892, 159 | -0.009497136, 160 | 0.011948809, 161 | -0.006748873, 162 | 0.000246420, 163 | 0.002102967, 164 | -0.001217930, 165 | 0.000233939 166 | ] 167 | 168 | D = [ 169 | 0.199471140, 170 | 0.000000023, 171 | -0.009351341, 172 | 0.000023006, 173 | 0.004851466, 174 | 0.001903218, 175 | -0.017122914, 176 | 0.029064067, 177 | -0.027928955, 178 | 0.016497308, 179 | -0.005598515, 180 | 0.000838386 181 | ] 182 | 183 | if x == 0: 184 | return 0 185 | elif x < 0: 186 | x = np.abs(x) 187 | x = (np.pi/2) * (x**2) 188 | F = 0 189 | if x < 4: 190 | for k in range(12): 191 | F += (A[k] + 1j*B[k]) * ((x/4) ** k) 192 | return -(F*np.sqrt(x/4) * np.exp(-1j*x)) 193 | else: 194 | for k in range(12): 195 | F += (C[k] + 1j*D[k]) * ((4/x) ** k) 196 | return -(F*np.sqrt(4/x) * np.exp(-1j*x) + (1-1j)/2) 197 | else: 198 | x = (np.pi/2) * (x**2) 199 | F = 0 200 | if x < 4: 201 | for k in range(12): 202 | F += (A[k] + 1j*B[k]) * ((x/4) ** k) 203 | return F*np.sqrt(x/4) * np.exp(-1j*x) 204 | else: 205 | for k in range(12): 206 | F += (C[k] + 1j*D[k]) * ((4/x) ** k) 207 | return F*np.sqrt(4/x) * np.exp(-1j*x) + (1-1j)/2 208 | 209 | 210 | if __name__ == '__main__': 211 | print(distance((1,2,3), (4,5,6)), np.sqrt(27)) 212 | cell_sz = 10. 213 | scale = 10. 214 | print(create_array_pos(cell_sz, scale, scale, False)) 215 | print(create_array_pos(cell_sz, scale, scale, True)) 216 | print(gsinc(10), np.sin(10)/10.) 217 | print(gsinc(0)) 218 | print(dB([1,2,3,4]), gain2mag(dB([1,2,3,4]))) 219 | print(dB([1,2,3,4], 'power')) 220 | print(norm2zero([-2, -3, 1, 2, 4, -7])) 221 | 222 | xyz = [1, 2, 3] 223 | r, t, p = car2sph(*xyz) 224 | xyz_mtx = make_v_mtx(*xyz) 225 | print(car2sph_mtx(t, p)*xyz_mtx) 226 | print(sph2car_mtx(t, p)*car2sph_mtx(t, p)*xyz_mtx) 227 | print(waveimpd) 228 | -------------------------------------------------------------------------------- /sources.py: -------------------------------------------------------------------------------- 1 | from hornpattern import PyramidalHorn, get_default_pyramidal_horn 2 | from rautils import sol, make_v_mtx, car2sph, sph2car, car2sph_mtx, sph2car_mtx, create_array_pos 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | 7 | class PlaneWave: 8 | def __init__(self, freq): 9 | k0 = 2 * np.pi / (sol / freq) 10 | self.e0 = 200.0 11 | self.k0 = k0 12 | self.freq = freq 13 | 14 | def frequency(self): 15 | return self.freq 16 | 17 | def get_k0(self): 18 | return self.k0 19 | 20 | def have_input_power(self): 21 | return False 22 | 23 | def efield_at_xyz(self, x, y, z): 24 | ex = 0j 25 | ey = self.e0 * np.exp(1j*self.k0*z) 26 | ez = 0j 27 | Exyz = make_v_mtx(ex, ey, ez) 28 | r, t, p = car2sph(x, y, z) 29 | Ertp = car2sph_mtx(t, p) * Exyz 30 | return Exyz, Ertp.item(1), Ertp.item(2) 31 | 32 | def efield_at_rtp(self, r, t, p): 33 | x, y, z = sph2car(r, t, p) 34 | return self.efield_at_xyz(x, y, z) 35 | 36 | 37 | class Source: 38 | def __init__(self): 39 | self.src = [] 40 | self.abg = [] 41 | self.pos = [] 42 | self.direction = [] 43 | self.idx = 0 44 | self.type = '' 45 | 46 | def __len__(self): 47 | return len(self.src) 48 | 49 | def __iter__(self): 50 | self.idx = 0 51 | return self 52 | 53 | def __next__(self): 54 | if self.idx == len(self): 55 | raise StopIteration 56 | ret = self.src[self.idx], self.abg[self.idx], self.pos[self.idx], self.direction[self.idx] 57 | self.idx += 1 58 | return ret 59 | 60 | def is_horn(self): 61 | return isinstance(self.src[0], PyramidalHorn) 62 | 63 | def frequency(self): 64 | if len(self) < 1: 65 | raise ValueError 66 | return self.src[0].frequency() 67 | 68 | def k0(self): 69 | if len(self) < 1: 70 | raise ValueError 71 | return self.src[0].get_k0() 72 | 73 | def append(self, src, abg, pos, dir='origin'): 74 | if self.type and self.type != type(src): 75 | print('source should be in same type') 76 | raise TypeError 77 | self.src.append(src) 78 | self.abg.append(abg) 79 | self.pos.append(pos) 80 | self.direction.append(dir) 81 | self.type = type(src) 82 | 83 | def test_plane_wave(): 84 | f = 5.0e9 85 | cell_sz = 15. / 1000. 86 | scale = 50 87 | z = 10. 88 | 89 | pw = PlaneWave(f) 90 | xl, yl = create_array_pos(cell_sz, scale, scale, ex=True) 91 | magE = np.ndarray((len(yl), len(xl))) 92 | pE = np.ndarray((len(yl), len(xl))) 93 | for (yi, y) in list(enumerate(yl)): 94 | for (xi, x) in list(enumerate(xl)): 95 | Exyz, _, _ = pw.efield_at_xyz(x, y, z) 96 | mag = np.sqrt(Exyz.item(0)**2 + Exyz.item(1)**2 + Exyz.item(2)**2) 97 | pha = np.angle(Exyz.item(1)) 98 | print(mag, np.rad2deg(pha)) 99 | #magE[yi, xi] = np.abs(mag) 100 | magE[yi, xi] = mag.real 101 | pE[yi, xi] = pha 102 | 103 | plt.figure() 104 | plt.pcolor(xl, yl, magE) 105 | 106 | plt.figure() 107 | plt.pcolor(xl, yl, pE) 108 | plt.show() 109 | 110 | 111 | if __name__ == '__main__': 112 | srcs = Source() 113 | f = 10e9 114 | srcs.append(get_default_pyramidal_horn(f), (np.deg2rad(0), np.deg2rad(0), np.deg2rad(0)), (0, 0, 1.0)) 115 | srcs.append(get_default_pyramidal_horn(f), (np.deg2rad(0), np.deg2rad(0), np.deg2rad(0)), (1.0, 1.0, 1.0)) 116 | #srcs.append(PlaneWave(f), (np.deg2rad(0), np.deg2rad(0), np.deg2rad(0)), (1.0, 1.0, 1.0)) 117 | 118 | for s, abg, pos in srcs: 119 | print(abg, pos) 120 | --------------------------------------------------------------------------------