Ejemplo n.º 1
0
def smp_connector(em,
                  x,
                  y,
                  z,
                  zmax,
                  coax_port_length=0.2e-3,
                  pin_diameter=0.85e-3):
    copper_shield = openems.Metal(em, 'smp_shield')
    copper = openems.Metal(em, 'smp_pin')
    lcp = openems.Dielectric(em, 'lcp', eps_r=3.2)

    # shield
    outside = np.array([[-2.5, 1.0], [-2.5, 2.5], [2.5, 2.5], [2.5, -2.5],
                        [-2.5, -2.5], [-2.5, -1.0]]) * 1e-3
    angle = np.arcsin(1.0 / 2.25)
    inside = openems.arc(0, 0, 4.5e-3 / 2.0, -np.pi + angle, np.pi - angle)
    openems.Polygon(copper_shield,
                    priority=9,
                    pcb_layer=None,
                    points=[x, y] + np.concatenate((inside, outside)),
                    elevation=[z, z + 0.9e-3],
                    normal_direction='z')

    outside = np.array([[0, 2.5], [2.5, 2.5], [2.5, -2.5], [0, -2.5]]) * 1e-3
    inside = openems.arc(0, 0, 1.95e-3 / 2.0, -np.pi * 0.5, np.pi * 0.5)
    openems.Polygon(copper_shield,
                    priority=9,
                    pcb_layer=None,
                    points=[x, y] + np.concatenate((inside, outside)),
                    elevation=[z + 0.9e-3, zmax],
                    normal_direction='z').duplicate().mirror('x')

    # pin
    start = np.array([x, y, zmax - coax_port_length])
    stop = np.array([x, y, z + 0.9e-3])
    copper.AddCylinder(start, stop, 0.5 * pin_diameter, priority=9)

    # smaller part of pin
    stop[2] = z
    copper.AddCylinder(start, stop, 0.5 * 0.8e-3, priority=9)

    # insulator
    start = np.array([x, y, z])
    stop = np.array([x, y, z + 0.9e-3])
    lcp.AddCylinder(start, stop, 4.5e-3 * 0.5, priority=1)

    if coax_port_length != 0:
        # port (coax)
        start = [
            x + 0.5 * coax_port_length, y + 0.5 * coax_port_length,
            zmax - coax_port_length
        ]
        stop = [x - 0.5 * coax_port_length, y - 0.5 * coax_port_length, zmax]
        openems.Port(em, start, stop, direction='z', z=50)
        em.mesh.AddLine('z', start[2])
Ejemplo n.º 2
0
def generate(
        em,
        sub,
        z, # [bottom of substrate, top of substrate, top of metal]
        port_length,
        ms_width,
        section, # pairs of x and y size of a segment
        box_width):
    box_length = 2.0*(port_length) + np.sum(section[:,0])
    pec = openems.Metal(em, 'pec')
    # substrate
    start = np.array([ 0.5*box_length, 0.5*box_width, z[0]])
    stop  = np.array([-0.5*box_length, -0.5*box_width, z[1]])
    openems.Box(sub, 1, start, stop)
    # pads
    x0 = -0.5*box_length
    x1 = x0 + port_length
    x2 = x1 + ms_width
    start = np.array([x1,  0.5*ms_width, z[1]])
    stop  = np.array([x2, -0.5*ms_width, z[2]])
    l1 = openems.Box(pec, 9, start, stop, padname = '1')
    l2 = l1.duplicate("line_p2").mirror('x')
    l2.padname = '2'
    x = x1
    points = np.zeros((2*len(section),2))
    i = 0
    for s in section:
        points[i,0] = x
        x += s[0]
        points[i+1,0] = x
        points[i,1] = 0.5*s[1]
        points[i+1,1] = 0.5*s[1]
        i += 2
    print(points)
    points = np.concatenate((points, points[::-1]*[1,-1.0]))
    print(points)
    pec.AddPolygon(
        points = points,
        priority = 9,
        elevation = z[1:],
        normal_direction = 'z',
        pcb_layer = 'F.Cu',
        pcb_width = 1e-5)

    # main line ports
    start = [x0, -0.5*ms_width, z[1]]
    stop  = [x1,  0.5*ms_width, z[2]]
    em.AddPort(start, stop, direction='x', z=50).duplicate().mirror('x')
Ejemplo n.º 3
0
#!/usr/bin/env python3
import sys
import openems
import numpy as np

mm = 1e-3 # default unit is the meter
em = openems.OpenEMS(sys.argv[1], EndCriteria = 1e-6, fmin = 0e6, fmax = 60e9)
em.fsteps = 801
copper = openems.Metal(em, 'copper')
sub = openems.Dielectric(em, 'substrate', eps_r=3.2)
mask = openems.Dielectric(em, 'mask', eps_r=3.3)
air = openems.Dielectric(em, 'air', eps_r=1.0006)

foil_thickness = 0.035*mm
port_length = 0.05*mm
box_length = 5*mm
box_width = 1.5*mm
ms_width = 0.190*mm
box_top = 1.5*mm

# dimensions Z
substrate_top = 0.102*mm
foil_top = substrate_top + foil_thickness
em.resolution = 50e-6

em.mesh.AddLine('z', foil_top + box_top)
em.mesh.AddLine('z', -0.5*mm)

# substrate
start = np.array([-0.5*box_length, 0.5*box_width, 0])
stop  = np.array([0.5*box_length, -0.5*box_width, substrate_top])
Ejemplo n.º 4
0
def generate(
        em,
        substrate,
        z,  # [bottom of substrate, top of substrate, top of metal]
        y1=5.5 * mm,
        y2=0.9 * mm,
        r=0.5 * mm,
        rv=[200, 200, 200, 200],
        w=[0.127 * mm, 0.152 * mm, 0.19 * mm, 0.23 * mm],
        port_length=0.2 * mm,
        ms_width=0.36 * mm,
        endspace=0.5 * mm,
        resistor_size='0402'):
    alumina = openems.Dielectric(em, 'alumina', eps_r=9.8)
    metal = openems.Metal(em, 'pec_wilkinson')
    n = len(rv)

    # substrate
    start = np.array([(n * 4 - 1) * r + endspace, y1 + r + endspace, z[0]])
    stop = np.array([-1.0 * endspace, -1.0 * start[1], z[1]])
    substrate.AddBox(start, stop, 1)

    # common port line (pad 1)
    start = np.array([-1.0 * endspace + port_length, 0.5 * ms_width, z[1]])
    stop = np.array([0, -0.5 * ms_width, z[2]])
    metal.AddBox(start, stop, priority=9, padname='1')

    lo = arc(r, -y1, r + 0.5 * w[0], pi, 2 * pi, 16)
    li = arc(r, -y1, r - 0.5 * w[0], pi, 2 * pi, 16)
    lo = cat((lo, arc(3 * r, -y2, r - 0.5 * w[0], pi, 0.55 * pi, 16)))
    li = cat((li, arc(3 * r, -y2, r + 0.5 * w[0], pi, 0.55 * pi, 16)))
    for i in range(n - 1):
        x = (4 * i + 3) * r
        w2 = w[1 + i]
        em.mesh.AddLine('x', x + r - 0.5 * w2)
        em.mesh.AddLine('x', x + r + 0.5 * w2)
        em.mesh.AddLine('x', x + 3 * r - 0.5 * w2)
        em.mesh.AddLine('x', x + 3 * r + 0.5 * w2)
        lo = cat((lo, arc(x, -y2, r - 0.5 * w2, 0.45 * pi, 0, 16)))
        li = cat((li, arc(x, -y2, r + 0.5 * w2, 0.45 * pi, 0, 16)))
        lo = cat((lo, arc(2 * r + x, -y1, r + 0.5 * w2, pi, 2 * pi, 16)))
        li = cat((li, arc(2 * r + x, -y1, r - 0.5 * w2, pi, 2 * pi, 16)))
        lo = cat((lo, arc(4 * r + x, -y2, r - 0.5 * w2, pi, 0.55 * pi, 16)))
        li = cat((li, arc(4 * r + x, -y2, r + 0.5 * w2, pi, 0.55 * pi, 16)))
    l = cat((lo, li[::-1]))
    l = cat((l[::-1] * [1, -1], l))
    openems.Polygon(metal,
                    priority=9,
                    points=l,
                    elevation=z[1:],
                    normal_direction='z',
                    pcb_layer='F.Cu',
                    pcb_width=0.001)

    # x at 2 port side
    x0 = (n * 4 - 1) * r + endspace
    x1 = x0 - port_length

    # output lines
    for (ym, padname) in [(1, 2), (-1, 3)]:
        start = np.array([x1, ym * 0.2 * mm, z[1]])
        stop = np.array([(n * 4 - 1) * r - 0.1 * mm,
                         ym * (0.2 * mm + ms_width), z[2]])
        lp2 = metal.AddBox(start, stop, priority=9, padname=padname)

    # main line port
    start = [-1.0 * endspace, -0.5 * ms_width, z[1]]
    stop = [-1.0 * endspace + port_length, 0.5 * ms_width, z[2]]
    openems.Port(em, start, stop, direction='x', z=50)

    # coupled line ports
    for ym in [-1, 1]:
        start = [x0 - port_length, ym * 0.2 * mm, z[1]]
        stop = [x0, ym * (0.2 * mm + ms_width), z[2]]
        openems.Port(em, start, stop, direction='x', z=50)

    for i in range(n):
        if not rv[i]:
            continue
        em.add_resistor('r{}'.format(i),
                        origin=np.array([4 * r * i + 3 * r, 0, z[2]]),
                        direction='y',
                        value=rv[i],
                        invert=False,
                        priority=9,
                        dielectric=alumina,
                        metal=metal,
                        element_down=False,
                        size=resistor_size)
Ejemplo n.º 5
0
#!/usr/bin/env python3
# Common SMA edge launch to OSHPark 4 layer
import sys
from scipy.constants import mil
import openems
import numpy as np

em = openems.OpenEMS('sma_el',
                     EndCriteria=1e-6,
                     fmin=0,
                     fmax=20e9,
                     fsteps=1001)
em.resolution = 8e-5
copper = openems.Metal(em, 'copper')
copper_shield = openems.Metal(em, 'copper_shield')
sub = openems.Dielectric(em, 'ro4350b', eps_r=3.66, tand=0.0035, fc=em.fmax)
teflon = openems.Dielectric(em, 'teflon', eps_r=2.1, tand=0.0002, fc=em.fmax)

foil_thickness = 35e-6
substrate_thickness = 62 * mil - 7 * mil
port_length = 300e-6
box_length = 10e-3
box_width = 6e-3
box_height = 6e-3
ms_width = 1.0e-3
board_gap = 0.0

# coax
coax_scale = 2.0
pin_diameter = 0.5e-3 * coax_scale
dielectric_diameter = 1.67e-3 * coax_scale
Ejemplo n.º 6
0
#!/usr/bin/env python3
import sys
from scipy.constants import pi, c, epsilon_0, mu_0, mil, inch
mm = 0.001
import openems
import openems.miter
import numpy as np

em = openems.OpenEMS('miter_6.6')
em.end_criteria = 1e-6
em.fmin = 0
em.fmax = 40e9
em.fsteps = 1601
fc = 40e9
pec = openems.Metal(em, 'pec')
sub = openems.Dielectric(em, 'ro4350b', eps_r=3.66, tand=0.0035, fc=fc)

foil_thickness = 0.033*mm
substrate_thickness = 6.6*mil
ms_air_above = 1.0*mm
z = [0.0, substrate_thickness, substrate_thickness + foil_thickness]
em.mesh.AddLine('z', z[2] + ms_air_above)

em.resolution = 50e-6

openems.miter.generate(
    em,
    pec,
    sub,
    miter = 0.35 * mm,
    z = z,
Ejemplo n.º 7
0
#!/usr/bin/env python
import sys
from scipy.constants import pi, c, epsilon_0, mu_0, mil, inch

mm = 0.001
import openems
import openems.idbpf
import numpy as np

em = openems.OpenEMS('idbpf_b3', fmin=1e6, fmax=16e9)
em.end_criteria = 1e-10
em.fsteps = 1601
fc = 7.12e9
eps_r = 3.66
#em.add_lossy_metal('copper', frequency=fc, conductivity=56e6/3, ur=1.0)
openems.Metal(em, 'copper')
openems.Metal(em, 'pec')
#em.via_offset_x = 5*mil
#em.via_offset_y = 5*mil
openems.Dielectric(em, 'sub', eps_r=eps_r).set_tanD(0.0035, freq=fc)

foil_thickness = 0.035 * mm
substrate_thickness = 22 * mil
ms_air_above = 2.0 * mm
via = 0.3 * mm
via_pad = 0.6 * mm

# dimensions Z
substrate_bottom = 0.0
substrate_top = substrate_bottom + substrate_thickness
foil_top = substrate_top + foil_thickness
Ejemplo n.º 8
0
    def generate(self):
        pec = openems.Metal(self.em, 'pec_filter')
        ring_ix = 0.5 * (np.max(self.rl) + self.end_gap)
        ring_ox = ring_ix + 2.0 * self.via_padradius
        via_z = [[self.z[0], self.z[1] + self.lidz], [self.z[1], self.z[2]]]
        # fingers
        y = -0.5 * self.space[-1:][0]
        mirror = False
        mirrorstring = ['', 'x']
        for i in range(len(self.space))[::-1]:  # reverse order
            x1 = 0.5 * (ring_ox + ring_ix)
            x2 = ring_ix - self.rl[i]
            y += self.space[i]
            start = [x1, y, self.z[1]]
            y += self.rw[i]
            stop = [x2, y, self.z[2]]
            box = openems.Box(pec,
                              9,
                              start,
                              stop,
                              padname='poly',
                              pcb_layer=self.pcb_layer)
            box.mirror(mirrorstring[mirror])
            mirror = not mirror
            box2 = box.duplicate()
            box2.mirror('xy')
            v = openems.Via(pec,
                            priority=2,
                            x=ring_ix + self.via_padradius,
                            y=y - 0.5 * self.rw[i],
                            z=via_z,
                            drillradius=self.via_radius,
                            padradius=self.via_padradius,
                            padname='2')
            if not mirror:
                v.mirror('x')
            v.duplicate().mirror('xy')
            if self.endmetal:
                v.duplicate().mirror('y')
                v.duplicate().mirror('x')

        mirror = not mirror
        # ports
        y1 = y
        y -= 0.5 * self.rw[0]  # center of line
        y2 = y + 0.5 * self.feedwidth + self.ring_y_width  # y outside
        px = ring_ix - self.tapoffset
        py = y2 - self.portlength
        start = [px + 0.5 * self.feedwidth, y2, self.z[1]]
        stop = [px - 0.5 * self.feedwidth, py, self.z[2]]
        p = openems.Port(self.em, start, stop, direction='y', z=50)
        p.mirror(mirrorstring[mirror])
        p2 = p.duplicate().mirror('xy')
        # feed lines
        start = [px + 0.5 * self.feedwidth, py, self.z[1]]
        stop = [px - 0.5 * self.feedwidth, y - 0.5 * self.rw[0], self.z[2]]
        box = openems.Box(pec,
                          9,
                          start,
                          stop,
                          padname='1',
                          pcb_layer=self.pcb_layer)
        box.mirror(mirrorstring[mirror])
        box2 = box.duplicate()
        box2.mirror('xy')
        box2.padname = '3'
        # substrate
        start = np.array([ring_ox, y2, self.z[0]])
        stop = openems.mirror(start, 'xy')
        stop[2] = self.z[1] + self.lidz
        sub = openems.Box(self.sub, 1, start, stop)
        # mask
        if self.mask_thickness > 0.0:
            start = np.array([ring_ox, y2, self.z[1]])
            stop = openems.mirror(start, 'xy')
            stop[2] += self.mask_thickness
            openems.Box(mask, 1, start, stop)
        # grounded end metal
        if self.endmetal:
            em1 = openems.Box(
                pec,
                9,
                start=[ring_ix, y2, self.z[1]],
                stop=[ring_ix + 2.0 * self.via_padradius, -y2, self.z[2]],
                padname='2',
                pcb_layer=self.pcb_layer)
            em1.duplicate().mirror('x')
Ejemplo n.º 9
0
def idbpf(
        em,  # openems instance
        sub,  # substrate, define with openems.Dielectric()
        z=[],  # z position, z[0] = sub bottom, z[1] = sub top, z[2] = foil top
        lidz=0,  # upper substrate thickness
        rl=[],  # length of resonator fingers
        rw=[],  # width of resonator fingers
        space=[],  # space between resonator fingers
        endmetal=True,  # add metal to filter ends
        portlength=0.2 * mm,  # length of the openems port
        feedwidth=0.85 * mm,  # width of the trace leaving the filter and port
        end_gap=0.3 * mm,  # space between the end of a resonator and ground
        via_radius=0.15 * mm,  # radius of the via drills
        via_padradius=0.3 * mm,  # radius of the via pads
        pcb_layer='F.Cu',  # Kicad layer
        mask=None,  # mask, define with openems.Dielectric()
        mask_thickness=0,  # set to non-zero to enable solder mask over filter
):
    edge_space = 0.5 * mm
    pec = openems.Metal(em, 'pec_filter')
    ring_ix = 0.5 * (np.max(rl) + end_gap)
    ring_ox = ring_ix + 2.0 * via_padradius
    via_z = [[z[0], z[1] + lidz], [z[1], z[2]]]
    # fingers
    y = -0.5 * space[-1:][0]
    mirror = False
    mirrorstring = ['', 'x']
    for i in range(len(space))[::-1]:  # reverse order
        x1 = 0.5 * (ring_ox + ring_ix)
        x2 = ring_ix - rl[i]
        y += space[i]
        start = [x1, y, z[1]]
        y += rw[i]
        stop = [x2, y, z[2]]
        box = openems.Box(pec,
                          9,
                          start,
                          stop,
                          padname='poly',
                          pcb_layer=pcb_layer)
        box.mirror(mirrorstring[mirror])
        mirror = not mirror
        box2 = box.duplicate()
        box2.mirror('xy')
        if i == 0:
            continue
        v = openems.Via(pec,
                        priority=2,
                        x=ring_ix + via_padradius,
                        y=y - 0.5 * rw[i],
                        z=via_z,
                        drillradius=via_radius,
                        padradius=via_padradius,
                        padname='2')
        if not mirror:
            v.mirror('x')
        v.duplicate().mirror('xy')
    mirror = not mirror
    # ports
    y1 = y + feedwidth - rw[0]  # outer edge of feed
    y2 = y - rw[0]  # inner edge
    px = ring_ox
    start = [px, y2, z[1]]
    stop = [px - portlength, y1, z[2]]
    p = openems.Port(em, start, stop, direction='x', z=50)
    p.mirror(mirrorstring[mirror])
    p2 = p.duplicate().mirror('xy')
    # feed lines
    start = [-ring_ix + rl[0], y1, z[1]]
    stop = [px - portlength, y2, z[2]]
    box = openems.Box(pec, 9, start, stop, padname='1', pcb_layer=pcb_layer)
    box.mirror(mirrorstring[mirror])
    box2 = box.duplicate()
    box2.mirror('xy')
    box2.padname = '3'
    # substrate
    start = np.array([ring_ox, y1 + edge_space, z[0]])
    stop = openems.mirror(start, 'xy')
    stop[2] = z[1] + lidz
    sub = openems.Box(sub, 1, start, stop)
    # mask
    if mask_thickness > 0.0:
        start = np.array([ring_ox, y2, z[1]])
        stop = openems.mirror(start, 'xy')
        stop[2] += mask_thickness
        openems.Box(mask, 1, start, stop)
    # grounded end metal
    if endmetal:
        em1 = openems.Box(
            pec,
            9,
            start=[ring_ix, -y2 + space[0], z[1]],
            stop=[ring_ix + 2.0 * via_padradius, y1 + edge_space, z[2]],
            padname='2',
            pcb_layer=pcb_layer)
        em1.duplicate().mirror('xy')
Ejemplo n.º 10
0
def idbpf(em, # openems instance
          sub, # substrate, define with openems.Dielectric()
          lidz = 0.0,
          z = [], # z position, z[0] = sub bottom, z[1] = sub top, z[2] = foil top
          space = [], # space between resonator fingers
          rl = [], # length of resonator fingers
          rw = [], # width of resonator fingers
          portlength = 0.2*mm, # length of the openems port
          feedwidth = 0.85*mm, # width of the trace leaving the filter and port
          tapoffset = 1.0*mm, # offset of tap from end of resonator
          end_gap = 0.3*mm, # space between the end of a resonator and ground
          via_radius = 0.15*mm, # radius of the via drills
          via_padradius = 0.3*mm, # radius of the via pads
          pcb_layer = 'F.Cu', # Kicad layer
          mask_thickness = 0, # set to non-zero to enable solder mask over filter
          mask = None, # mask, define with openems.Dielectric()
          endmetal = True, # add metal to filter ends
):
    pec = openems.Metal(em, 'pec_filter')
    ring_y_width = via_padradius * 2.0
    ring_ix = 0.5 * (np.max(rl) + end_gap)
    ring_ox = ring_ix + 2.0 * via_padradius
    via_z = [[z[0], z[1]+lidz], [z[1], z[2]]]
    # fingers
    y = -0.5*space[-1:][0]
    mirror = np.array([1,1,1])
    if len(space) % 2 == 0:
        mirror[0] *= -1
    for i in range(len(space))[::-1]: # reverse order
        x1 = 0.5 * (ring_ox + ring_ix)
        x2 = ring_ix - rl[i]
        y += space[i]
        start = [x1, y, z[1]];
        y += rw[i]
        stop  = [x2, y, z[2]];
        for m in [np.array([1,1,1]),np.array([-1,-1,1])]:
            m *= mirror
            openems.Box(pec, 9, start*m, stop*m, padname = 'poly', pcb_layer=pcb_layer)
            openems.Via(pec, priority=2,
                        x=m[0]*(ring_ix+via_padradius),
                        y=m[1]*(y-0.5*rw[i]),
                        z=via_z,
                        drillradius=via_radius,
                        padradius=via_padradius, padname='2')
        mirror[0] *= -1

        if endmetal:
            v.duplicate().mirror('y')
            v.duplicate().mirror('x')

    mirror *= [-1,1,1]
    # ports
    y1 = y
    y -= 0.5*rw[0] # center of line
    y2 = y + 0.5*feedwidth + ring_y_width # y outside
    px = ring_ix - tapoffset
    py = y2 - portlength
    for m in [-1,1]:
        start = [m*(px + 0.5*feedwidth), m*y2, z[1]]
        stop  = [m*(px - 0.5*feedwidth), m*py, z[2]]
        openems.Port(em, start, stop, direction='y', z=50)
        # feed lines
        start = [m*(px + 0.5*feedwidth), m*py, z[1]]
        stop  = [m*(px - 0.5*feedwidth), m*(y-0.5*rw[0]), z[2]]
        openems.Box(pec, 9, start, stop, padname = '1' if m==1 else '3',
                    pcb_layer=pcb_layer)
    # substrate
    start = np.array([ring_ox, y2, z[0]])
    stop  = openems.mirror(start, 'xy')
    stop[2] = z[1]+lidz
    sub = openems.Box(sub, 1, start, stop)
    # mask
    if mask_thickness > 0.0:
        start = np.array([ring_ox, y2, z[1]])
        stop  = openems.mirror(start, 'xy')
        stop[2] += mask_thickness
        openems.Box(mask, 1, start, stop)
    # grounded end metal
    if endmetal:
        for xm in [-1,1]:
            em1 = openems.Box(pec, 9, start = [xm*ring_ix, y2, z[1]],
                              stop = [xm*(ring_ix + 2.0*via_padradius), -y2, z[2]],
                              padname = '2', pcb_layer=pcb_layer)
Ejemplo n.º 11
0
def generate(
        em,
        sub,
        mask,
        min_width, # minimum copper width, typically design rule minimum
        cutout_width, # width of ground plane cutouts
        inductors,
        capacitors,
        z, # bottom of [air below, bottom metal, substrate, top metal, air above, lid]
        port_length,
        ms_width,
        box_width,
        half_fan_angle=0.25*np.pi):

    em.mesh.AddLine('z', z[0]) # air above, below
    em.mesh.AddLine('z', z[5])
    em.mesh.AddLine('z', 0.5*(z[2]+z[3]))
    em.mesh.AddLine('z', 0.25*(3*z[2]+z[3]))
    em.mesh.AddLine('z', 0.25*(z[2]+3*z[3]))
    em.mesh.AddLine('y', -0.5*min_width)
    em.mesh.AddLine('y', 0.5*min_width)

    box_length = 2.0*(np.sum(inductors) + capacitors[0] + 0.5e-3)

    x0 = -0.5*box_length
    x1 = x0 + port_length
    x2 = x1 + ms_width

    yb = 0.5*cutout_width
    yo = -0.1e-3 # overlap

    pec = openems.Metal(em, 'pec')

    # substrate
    start = np.array([ 0.5*box_length, 0.5*box_width, z[2]])
    stop  = np.array([-0.5*box_length, -0.5*box_width, z[3]])
    openems.Box(sub, 1, start, stop)
    # solder mask
    if mask != None:
        start[2] = z[3] + 25e-6
        openems.Box(mask, 1, start, stop)

    # top copper polygon
    points = np.zeros((6+10*len(inductors),2))
    points[0] = [x1, 0.5*ms_width]
    x = -np.sum(inductors)
    points[1] = [x - 0.5*ms_width, 0.5*ms_width]
    points[2:10] = arc(x, 0, capacitors[0],
                       0.5*np.pi+half_fan_angle,
                       0.5*np.pi-half_fan_angle,
                       npoints = 8)
    points[10] = [x + 0.5*min_width, 0.5*min_width]
    i = 11
    x += inductors[0]
    for j in range(1, len(inductors)):
        points[i+0] = [x-0.5*min_width, 0.5*min_width]
        points[i+1:i+9] = arc(x, 0, capacitors[j],
                              0.5*np.pi+half_fan_angle,
                              0.5*np.pi-half_fan_angle,
                              npoints = 8)
        points[i+9] = [x+0.5*min_width, 0.5*min_width]
        i += 10
        x += inductors[j]
    # center cap
    points[i+0] = [-0.5*min_width, 0.5*min_width]
    points[i+1:i+5] = arc(0, 0, capacitors[-1],
                          0.5*np.pi+half_fan_angle,
                          0.5*np.pi + 0.001, npoints = 4)
    print(points)
    points = np.concatenate((points, points[::-1]*[-1,1]))
    points = np.concatenate((points, points[::-1]*[1,-1]))
    pec.AddPolygon(
        points = points,
        priority = 9,
        elevation = z[3:5],
        pcb_layer = 'F.Cu')

    # ground plane
    gpec = openems.Metal(em, 'ground_plane')
    points = np.zeros((2+6*len(inductors),2))
    points[0] = [x0, 0.5*box_width]
    points[1] = [x0, yo]
    i = 2
    x = -np.sum(inductors)
    for l in inductors:
        hmw = 0.5*min_width
        xl = x + hmw
        points[i+0] = [xl,yo]
        points[i+1] = [xl,hmw]
        xl = x + yb
        points[i+2] = [xl,yb]
        xl = x + l - yb
        points[i+3] = [xl,yb]
        xl = x + l - hmw
        points[i+4] = [xl,hmw]
        points[i+5] = [xl,yo]
        i += 6
        x += l
    print("ground plane",points)
    for ym in [1,-1]:
        gpec.AddPolygon(
            points = [1,ym] * np.concatenate((points, points[::-1]*[-1,1])),
            priority = 9,
            elevation = z[1:3],
            pcb_layer = 'B.Cu',
            is_custom_pad = True,
            x=0,
            y=ym*(yb+0.1e-3),
            pad_name='3',
        )

    for (xm,padname) in [(-1,2),(1,1)]:
        # main line ports
        start = [x0*xm, -0.5*ms_width, z[3]]
        stop  = [x1*xm,  0.5*ms_width, z[4]]
        em.AddPort(start, stop, direction='x', z=50)
        # pads
        start[0] = x2*xm
        l1 = openems.Box(pec, 9, start, stop, padname=padname)