Exemple #1
0
    class Passivated(cls):

        passivation_margin = LayoutParamInterface()
        passivation_scale = LayoutParamInterface()
        passivation_layer = LayoutParamInterface()

        def __init__(self, *a, **kw):

            cls.__init__(self, *a, **kw)
            self.passivation_margin = margin
            self.passivation_scale = scale
            self.passivation_layer = layer

        def draw(self):

            supercell = cls.draw(self)

            cell = pt.Device(self.name)

            master_ref = cell.add_ref(supercell, alias='Device')

            add_passivation(cell, self.passivation_margin,
                            self.passivation_scale, self.passivation_layer)

            if issubclass(cls, pc.SMD):

                bottom_port = Port(name='S_1',
                                   width=self.size.x,
                                   orientation=270,
                                   midpoint=s.coord)

                top_port = Port(name='N_2',
                                width=self.size.x,
                                orientation=90,
                                midpoint=n.coord)

                cell.add_port(top_port)
                cell.add_port(bottom_port)

                cell.add(
                    pt._make_poly_connection(bottom_port,
                                             master_ref.ports['S_1'],
                                             layer=self.layer))

                cell.add(
                    pt._make_poly_connection(top_port,
                                             master_ref.ports['N_2'],
                                             layer=self.layer))

            else:

                pt._copy_ports(supercell, cell)

            return cell
Exemple #2
0
    class connectedPorts(cls):

        connector_distance = LayoutParamInterface()

        def __init__(self, *a, **kw):

            super().__init__(*a, **kw)

            self.connector_distance = pt.Point(0, 100)

        def draw(self):

            cell = Device(self.name)

            supercell = super().draw()

            cell << supercell

            for t in tags:

                connector = connect_ports(supercell,
                                          t,
                                          layers=layers,
                                          distance=self.connector_distance.y)

                cell << connector

                pt._copy_ports(connector, cell)

            return cell
Exemple #3
0
    class OnePortProbed(cls):
        ''' LayoutPart decorated with a one port probe.

        Parameters:
        -----------
            ground_conn_style : ('straight','side')

            gnd_routing_width: float.

        '''

        gnd_routing_width = LayoutParamInterface()

        def __init__(self, *args, **kwargs):

            cls.__init__(self, *args, **kwargs)

            self.gnd_routing_width = 100.0

        def draw(self):

            self._set_relations()

            device_cell = cls.draw(self)

            probe_cell = self.probe.draw()

            cell = Device(name=self.name)

            cell.add_ref(device_cell, alias="Device")

            self._add_signal_connection(cell, 'bottom')

            probe_ref = cell.add_ref(probe_cell, alias="Probe")

            self._move_probe_ref(cell)

            self._setup_signal_routing(cell)

            cell.absorb(cell << self._draw_signal_routing())

            try:

                self._setup_ground_routing(cell, 'straight')

                routing_cell = self._draw_ground_routing()

            except:

                self._setup_ground_routing(cell, 'side')

                routing_cell = self._draw_ground_routing()

            _add_default_ground_vias(self, routing_cell)

            cell.add_ref(routing_cell, alias=self.name + "GroundTrace")

            return cell

        def _add_signal_connection(self, cell, tag):

            device_cell = cell["Device"]

            ports = pt._find_ports(device_cell, tag, depth=0)

            if len(ports) > 1:

                distance = self.probe_dut_distance.y - self.probe_conn_distance.y

                port_mid = pt._get_centroid_ports(ports)

                if distance - port_mid.width > 0:

                    sigtrace = connect_ports(device_cell,
                                             tag=tag,
                                             layers=self.probe.sig_layer,
                                             distance=distance -
                                             port_mid.width,
                                             metal_width=port_mid.width)

                else:

                    sigtrace = connect_ports(device_cell,
                                             tag=tag,
                                             layers=self.probe.sig_layer,
                                             distance=0,
                                             metal_width=distance)

                _add_default_ground_vias(self, sigtrace)

                cell.absorb(cell << sigtrace)

                sigtrace.ports[tag].width = self.probe.size.x

                pt._copy_ports(sigtrace, cell)

            else:

                cell.add_port(port=device_cell.ports[tag])

        def export_all(self):

            df = super().export_all()
            df["DUTResistance"] = super().resistance_squares
            df["ProbeResistance"] = self.probe_resistance_squares

            return df

        @property
        def resistance_squares(self):

            return super().resistance_squares

        @staticmethod
        def get_components():

            supercomp = copy(cls.get_components())

            if issubclass(probe, pc.GSGProbe):

                supercomp.update({
                    "Probe": probe,
                    "SigTrace": pc.Routing,
                    "GndLeftTrace": pc.MultiRouting,
                    "GndRightTrace": pc.MultiRouting,
                    "GndVia": pc.Via
                })

            else:

                raise ValueError("To be implemented")

            return supercomp

        @property
        def probe_resistance_squares(self):

            return 0

        @property
        def probe_dut_distance(self):

            base_dist = self.idt.probe_distance

            if hasattr(self, 'pad'):

                base_dist = pt.Point(
                    base_dist.x,
                    self.pad.size + self.pad.distance + base_dist.y)

            if hasattr(self.probe, 'pad'):

                base_dist = pt.Point(
                    base_dist.x, self.probe.pad.size +
                    self.probe.pad.distance + base_dist.y)

            return base_dist

        @property
        def probe_conn_distance(self):

            tot_distance = self.probe_dut_distance

            return pt.Point(tot_distance.x, tot_distance.y * 3 / 4)

        def _move_probe_ref(self, cell):

            device_ref = cell["Device"]

            probe_ref = cell["Probe"]

            bottom_ports = pt._find_ports(cell, 'bottom', depth=0, exact=True)

            try:

                probe_port = probe_ref.ports['SigN']

            except:

                probe_port = probe_ref.ports['SigN_1']

            top_ports = pt._find_ports(device_ref, 'top')

            if len(top_ports) > 1:

                probe_ref.connect(port=probe_port,
                                  destination=bottom_ports[0],
                                  overlap=-self.probe_conn_distance.y)

            else:

                probe_ref.connect(port=probe_port,
                                  destination=bottom_ports[0],
                                  overlap=-self.probe_dut_distance.y)

        def _setup_ground_routing(self, cell, label):

            device_ref = cell["Device"]

            probe_ref = cell["Probe"]

            bbox = super()._bbox_mod(device_ref.bbox)

            if isinstance(self.probe, pc.GSGProbe):

                for index, groundroute in enumerate(
                    [self.gndlefttrace, self.gndrighttrace]):

                    groundroute.layer = self.probe.ground_layer

                    groundroute.clearance = bbox

                    groundroute.set_auto_overhang(True)

                    groundroute.trace_width = self.gnd_routing_width

                    if index == 0:

                        groundroute.side = 'left'

                        if label == 'straight':

                            groundroute.source = (
                                probe_ref.ports['GroundLXN'], )

                        elif label == 'side':

                            groundroute.source = (
                                probe_ref.ports['GroundLXW'], )

                    elif index == 1:

                        groundroute.side = 'right'

                        if label == 'straight':

                            groundroute.source = (
                                probe_ref.ports['GroundRXN'], )

                        elif label == 'side':

                            groundroute.source = (
                                probe_ref.ports['GroundRXE'], )

                    dest_ports = pt._find_ports(device_ref, 'top')

                    groundroute.destination = tuple(dest_ports)

            elif isinstance(self.probe, pc.GSProbe):

                raise ValueError(
                    "OnePortProbed with GSprobe to be implemented ")

            else:

                raise ValueError(
                    "OnePortProbed without GSG/GSprobe to be implemented ")

        def _draw_ground_routing(self):

            if isinstance(self.probe, pc.GSGProbe):

                routing_cell = Device()

                routing_cell.absorb(routing_cell << self.gndlefttrace.draw())

                routing_cell.absorb(routing_cell << self.gndrighttrace.draw())

                return pt.join(routing_cell)

            else:

                raise ValueError("To be implemented")

        def _setup_signal_routing(self, cell):

            sig_trace = self.sigtrace

            sig_trace.layer = self.probe.sig_layer

            sig_trace.source = cell["Probe"].ports["SigN"]

            sig_trace.destination = cell.ports["bottom"]

            sig_trace.trace_width = self._calc_sig_routing_width(
                sig_trace.source, sig_trace.destination)

            sig_trace.set_auto_overhang(True)

        def _calc_sig_routing_width(self, pad_port, device_port):

            if device_port.width > pad_port.width:

                return device_port.width

            else:

                return None

        def _draw_signal_routing(self):

            return self.sigtrace.draw()

        def get_params(self):

            df = super().get_params()

            modkeys = [*df.keys()]

            pt.pop_all_match(modkeys, "SigTrace")

            pt.pop_all_match(modkeys, "GndLeftTrace")

            pt.pop_all_match(modkeys, "GndRightTrace")

            return {k: df[k] for k in modkeys}
Exemple #4
0
    class TwoPort(cls):

        offset = LayoutParamInterface()

        def __init__(self, *a, **kw):

            if not issubclass(cls, (pc.GSGProbe, pc.GSProbe)):

                raise TypeError(
                    f"passed probe class is invalid ({cls.__name__})")

            cls.__init__(self, *a, *kw)

            self.offset = LayoutDefault.TwoPortProbeoffset

        def draw(self):
            def mirror_label(str):

                if 'N_' in str:

                    return str.replace('N_', 'S_')

                if 'E_' in str:

                    return str.replace('E_', 'W_')

                if 'S_' in str:

                    return str.replace('S_', 'N_')

                if 'W_' in str:

                    return str.replace('W_', 'E_')

                return str

            cell = Device(name=self.name)

            probe_cell = super().draw()

            p1 = cell.add_ref(probe_cell, alias='Port1')

            p2 = cell.add_ref(probe_cell, alias='Port2')

            p2.rotate(center=(p1.x, p1.ymax), angle=180)

            p2.move(destination=self.offset.coord)

            for n, p in p1.ports.items():

                cell.add_port(port=p, name=n + '_1')

            for n, p in p2.ports.items():

                if 'LX' in n:

                    cell.add_port(port=p,
                                  name=mirror_label(n + '_2').replace(
                                      'LX', 'RX'))

                else:

                    if 'RX' in n:

                        cell.add_port(port=p,
                                      name=mirror_label(n + '_2').replace(
                                          'RX', 'LX'))

                    else:

                        cell.add_port(port=p, name=mirror_label(n + '_2'))

            return cell
Exemple #5
0
    class Fixture(cls):

        style = LayoutParamInterface('short', 'open')

        def __init__(self, *a, **k):

            super().__init__(*a, **k)

            self.style = style

        def draw(self):

            supercell = cls.draw(self)

            cell = pg.deepcopy(supercell)

            style = self.style

            if style == 'open':

                pt._remove_alias(cell, 'IDT')

            if style == 'short':

                for subcell in cell.get_dependencies(recursive=True):

                    if "IDT" in subcell.name:

                        subcell.remove_polygons(
                            lambda x, y, z: y == self.idt.layer)

                        trace_cell = pc.PolyRouting()

                        trace_cell.source = subcell.ports['top']

                        trace_cell.destination = subcell.ports['bottom']

                        trace_cell.layer = (self.idt.layer, )

                        subcell.add(trace_cell.draw())

            return cell

        @property
        def resistance_squares(self):

            style = self.style

            if style == 'open':

                from numpy import Inf
                return 1e9

            elif style == 'short':

                cell = cls.draw(self)

                ports = cell.get_ports()

                top_port = cell.ports['top']
                bottom_port = cell.ports['bottom']

                l = top_port.y - bottom_port.y
                w = (top_port.width + bottom_port.width) / 2

                return l / w
Exemple #6
0
    class Arrayed(cls):

        n_blocks = LayoutParamInterface()

        def __init__(self, *args, **kwargs):

            cls.__init__(self, *args, **kwargs)

            self.n_blocks = n

        def draw(self):

            unit_cell = cls.draw(self)

            cell = pt.draw_array(unit_cell, self.n_blocks, 1)

            cell.name = self.name

            self._make_internal_ground_connections(cell)

            return cell

        def _make_internal_ground_connections(self, cell):

            lx_ports = pt._find_ports(cell, 'GroundLX', depth=0)

            rx_ports = pt._find_ports(cell, 'GroundRX', depth=0)

            if len(lx_ports) <= 1 or len(rx_ports) <= 1:

                return

            else:

                lx_ports.remove(lx_ports[0])

                rx_ports.remove(rx_ports[-1])

            polyconn = pc.PolyRouting()

            polyconn.layer = (self.plate_layer, )

            for l, r in zip(lx_ports, rx_ports):

                polyconn.source = l
                polyconn.destination = r

                cell.add(polyconn.draw())
                cell.remove(cell.ports[l.name])
                cell.remove(cell.ports[r.name])

        @property
        def resistance_squares(self):

            r = super().resistance_squares

            cell = cls.draw(self)

            for p in cell.get_ports():

                if 'bottom' in p.name:

                    p_bot = p

                    break

            w = p_bot.width

            l = w

            n_blocks = self.n_blocks

            if n_blocks == 1:

                return r + l / w

            else:

                x_dist = self.idt.active_area.x + self.etchpit.x * 2

                if n_blocks % 2 == 1:

                    return pt.parallel_res(r + l / w, (r + 2 * x_dist / l) /
                                           (n_blocks - 1))

                if n_blocks % 2 == 0:

                    if n_blocks == 2:

                        return (r + x_dist / l) / 2

                    else:

                        return pt.parallel_res(
                            (r + x_dist / l) / 2,
                            (r + 2 * x_dist / l) / (n_blocks - 2))

        @property
        def active_area(self):

            active_area = super().active_area

            return pt.Point(active_area.x * self.n_blocks, active_area.y)

        def export_all(self):

            df = super().export_all()

            df["SingleDeviceResistance"] = super().resistance_squares

            return df
Exemple #7
0
    class LargeGrounded(probe):
        ''' legacy class to make large ground pads.

        Properties:

            ground_size (float).
        '''

        ground_size = LayoutParamInterface()

        def __init__(self, *args, **kwargs):

            probe.__init__(self, *args, **kwargs)

            self.ground_size = LayoutDefault.LargePadground_size

        def draw(self):

            oldprobe = probe.draw(self)

            cell = pg.deepcopy(oldprobe)

            groundpad = pt._draw_multilayer('compass',
                                            layers=self.ground_layer,
                                            size=(self.ground_size,
                                                  self.ground_size))

            [_, _, ul, ur, *_] = pt._get_corners(groundpad)

            for alias in cell.aliases:

                if 'GroundLX' in alias:

                    dest = cell[alias].ports['N'].endpoints[1]

                    for portname in cell.ports:

                        if alias in portname:

                            cell.remove(cell.ports[portname])

                    cell.remove(cell[alias])

                    groundref = cell.add_ref(groundpad, alias=alias)

                    groundref.move(origin=ur.coord, destination=dest)

                    pt._copy_ports(groundref, cell, prefix="GroundLX")

                if 'GroundRX' in alias:

                    dest = cell[alias].ports['N'].endpoints[0]

                    for portname in cell.ports:

                        if alias in portname:

                            cell.remove(cell.ports[portname])

                    cell.remove(cell[alias])

                    groundref = cell.add_ref(groundpad, alias=alias)

                    groundref.move(origin=ul.coord, destination=dest)

                    for portname in cell[alias].ports:

                        cell.remove(cell[alias].ports[portname])

                    pt._copy_ports(groundref, cell, prefix="GroundRX")

            return cell