File: gradientmodel.py

package info (click to toggle)
python-gradientmodel 0.0.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,336 kB
  • sloc: python: 134; makefile: 5
file content (198 lines) | stat: -rw-r--r-- 5,754 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
"""Calculate the properties of a rough metal surface using the Gradient Model.

References:

   G. Gold and K. Helmreich, “A Physical Surface Roughness Model and Its
   Applications,” IEEE Trans. Microw. Theory Tech., vol. 65, no. 10, pp.
   3720–3732, Oct. 2017, doi: 10.1109/TMTT.2017.2695192.

   K. Lomakin, G. Gold, and K. Helmreich, “Analytical Waveguide Model
   Precisely Predicting Loss and Delay Including Surface Roughness,” IEEE
   Trans. Microw. Theory Tech., vol. 66, no. 6, pp. 2649–2662, Jun. 2018,
   doi: 10.1109/TMTT.2018.2827383.

This package uses the closed-form solution from:

   D. N. Grujic, “Closed-Form Solution of Rough Conductor Surface Impedance,”
   IEEE Trans. Microw. Theory Tech., vol. 66, no. 11, pp. 4677–4683, 2018,
   doi: 10.1109/TMTT.2018.2864586.

"""

import numpy as np
from mpmath import hyp2f1, hyp3f2
from numpy import ndarray, pi, sqrt, exp
from scipy.constants import mu_0, epsilon_0


def mag_field(x, f, rq, sigma0=5.8e7):
    """Calculate the magnetic field tangential to the metal surface.

    Args:
        x: position relative to surface, in units [m]
        f: frequency, in units [Hz]
        rq: rms surface roughness, in units [m]
        sigma0: dc conductivity, optional, default is 5.8e7, in units [S]

    Returns:
        magnetic field

    """

    x_is_array = isinstance(x, ndarray) and len(x) > 1
    f_is_array = isinstance(f, ndarray) and len(f) > 1
    if x_is_array and f_is_array:
        print("x and f can't both be arrays")
        raise ValueError

    # Constants
    xi = 0.5
    chi = sqrt(2) * rq

    # Angular frequency
    w = 2 * pi * f

    # Eqns 15 and 21 from Grujic 2018
    alpha = (1 + 1j) / 2 * rq * sqrt(mu_0 * w * sigma0)
    beta = 0.5 * (sqrt(1 + 4 * alpha ** 2) - 1)

    # Eqn 32 from Grujic 2018
    zeta = 1 / (1 + exp(2 * (x / chi + xi)))

    # Coefficients
    a1 = alpha + beta
    a2 = alpha - beta - 1
    b1 = 1 + 2 * alpha

    # Eqn 31 from Grujic 2018
    if isinstance(x, ndarray) and len(x) > 1:
        mag = np.empty_like(x, dtype=complex)
        for i, _z in np.ndenumerate(zeta):
            mag[i] = _z ** alpha
            mag[i] *= hyp2f1(a1, a2, b1, _z)
    elif isinstance(f, ndarray) and len(f) > 1:
        mag = np.empty_like(f, dtype=complex)
        for i in range(len(f)):
            mag[i] = zeta ** alpha[i] * hyp2f1(a1[i], a2[i], b1[i], zeta)
    else:
        mag = zeta ** alpha * hyp2f1(a1, a2, b1, zeta)

    return mag


def surface_impedance(f, rq, x0=None, sigma0=5.8e7):
    """Calculate the surface impedance of a rough metal.

    Args:
        f: frequency, in units [Hz]
        rq: rms surface roughness, in units [m]
        x0: starting point for integral, optional, default is -5*rq,
            in units [m]
        sigma0: dc conductivity, optional, default is 5.8e7, in units [S]

    Returns:
        surface impedance

    """

    f_is_array = isinstance(f, ndarray) and len(f) > 1

    # Constants
    xi = 0.5
    chi = sqrt(2) * rq
    if x0 is None:
        x0 = -5 * rq

    # Angular frequency
    w = 2 * pi * f

    # Eqns 15 and 21
    alpha = (1 + 1j) / 2 * rq * sqrt(mu_0 * w * sigma0)
    beta = 0.5 * (sqrt(1 + 4 * alpha ** 2) - 1)

    # Eqn 32
    zeta = 1 / (1 + exp(2 * (x0 / chi + xi)))

    # Magnetic field, mag
    mag = mag_field(x0, f, rq, sigma0=sigma0)

    # Anti-derivative, bb
    # Eqn 40 and 41 in Grujic 2018
    a1 = 1 + alpha - beta
    a2 = 2 + alpha + beta
    a3 = alpha
    b1 = 1 + 2 * alpha
    b2 = 1 + alpha
    if f_is_array:
        f0 = np.empty_like(f, dtype=complex)
        f1 = np.empty_like(f, dtype=complex)
        for i in range(len(f)):
            f1[i] = hyp3f2(a1[i], a2[i], a3[i] + 1, b1[i], b2[i] + 1, zeta)
            f0[i] = hyp3f2(a1[i], a2[i], a3[i], b1[i], b2[i], zeta)
        bb = chi / 2 * (zeta ** alpha) * (zeta / (1 + alpha) * f1 - f0 / alpha)
    else:
        f1 = hyp3f2(a1, a2, a3 + 1, b1, b2 + 1, zeta)
        f0 = hyp3f2(a1, a2, a3, b1, b2, zeta)
        bb = chi / 2 * (zeta ** alpha) * (zeta / (1 + alpha) * f1 - f0 / alpha)

    return -1j * mu_0 * w * bb / mag


def rough_properties(f, rq, x0=None, sigma0=5.8e7):
    """Calculate the surface properties of a rough metal.

    Args:
        f: frequency, in units [Hz]
        rq: rms surface roughness, in units [m]
        x0: starting point for integral, optional, default is -5*rq,
            in units [m]
        sigma0: dc conductivity, optional, default is 5.8e7, in units [S]

    Returns:
        surface impedance, effective conductivity, effective permeability

    """

    # Angular frequency
    w = 2 * pi * f

    # Surface roughness
    zs_rough = surface_impedance(f, rq, x0=x0, sigma0=sigma0)

    # Effective conductivity
    cond_eff = mu_0 * w / (2 * zs_rough.real ** 2)

    # Effective permeability
    ur_eff = 2 * sigma0 * zs_rough.imag ** 2 / w / mu_0

    return zs_rough, cond_eff, ur_eff


# Waveguide loss -------------------------------------------------------------

def waveguide_propagation(f, a, b, cond_eff, ur_eff, cond=5.8e7, er=1, ur=1, tand=0):

    # angular frequency
    w = 2 * pi * f

    # skin depths
    skin_c = 1 / sqrt(pi * mu_0 * ur * cond_eff * f)
    skin_m = 1 / sqrt(pi * mu_0 * ur_eff * cond * f)

    # equivalent circuit values
    r1 = 2 / (cond_eff * skin_c * b)
    r2 = 2 * a * (a + 2 * b) / (b * pi**2 * cond_eff * skin_c)
    l1 = 2 / (cond * skin_m * b * a)
    l2 = 2 * a * (a + 2 * b) / (b * pi**2 * cond * skin_m * a)
    c1 = er * epsilon_0
    g1 = w * c1 * tand

    # propagation constant
    t1 = r1 + 1j * w * l1
    t2 = 1 / (r2 + 1j * w * l2) + g1 + 1j * w * c1
    gamma = sqrt(t1 * t2)

    # characteristic impedance
    zte = sqrt(t1 / t2)

    return gamma, zte