Schematic

Schematic#

A schematic is a graph representation of your circuit.

For complex circuits, a schematic allows you to create symbols and hierarchy levels to represent your circuit.

Having a schematic allows you to also ensure that your layout matches you schematic (design intent).

There are many schematic capturing tools out there:

  • Qucs-s: for RF.

  • Xschem: for analog circuits.

  • Lumerical interconnect: for photonic circuits.

These tools allow you to create schematics with either your mouse or by code.

gdsfactory also allows you to create complex Schematics directly from python with a very simple interface.

import gdsfactory as gf
import yaml
from functools import partial
@gf.schematic_cell
def my_schematic(x: float = 108.5, y: float = 53.1) -> gf.Schematic:
    """Returns a schematic with two rings connected by a waveguide."""
    s = gf.Schematic()
    r1 = s.create_inst(name="r1", component="ring_single")
    r1.place(x=0, y=0)

    r2 = s.create_inst(name="r2", component="ring_single", settings={"radius": 32.2})
    r2.place(x=x, y=y)

    s.add_route(
        name="r1-r2",
        start_ports=[r1.ports["o2"]],
        end_ports=[r2.ports["o1"]],
        routing_strategy="route_bundle",
    )
    return s

c = my_schematic()
c
../_images/d8a1166cf9fbb447ef546cb86e517c362e3955d927148bca8b85d70d3fdb632c.png
@gf.schematic_cell(
    factories=gf.get_factories.get_cells("gdsfactory"),
    routing_strategies=gf.get_active_pdk().routing_strategies
    or {
        "route_bundle": partial(
            gf.routing.route_bundle, layer=gf.get_layer((1, 0)), route_width=1
        )
    },
)
def my_schematic(x: float = 108.5, y: float = 53.1) -> gf.Schematic:
    """Returns a schematic with two rings connected by a waveguide."""
    s = gf.Schematic()
    r1 = s.create_inst(name="r1", component="ring_single")
    r1.place(x=0, y=0)

    r2 = s.create_inst(name="r2", component="ring_single", settings={"radius": 32.2})
    r2.place(x=x, y=y)

    s.add_route(
        name="r1-r2",
        start_ports=[r1.ports["o2"]],
        end_ports=[r2.ports["o1"]],
        routing_strategy="route_bundle",
    )

    return s

c = my_schematic()
c
../_images/d8a1166cf9fbb447ef546cb86e517c362e3955d927148bca8b85d70d3fdb632c.png
@gf.schematic_cell
def ring_array(n: int = 3, pitch_x: float = 100, pitch_y=50, radius: float = 10, radius_delta: float = 5) -> gf.Schematic:
    """Returns a schematic with n rings connected by a waveguide."""
    s = gf.Schematic()

    last_ring  = None

    for i in range(n):
        r = s.create_inst(name=f"r{i}", component="ring_single", settings={"radius": radius+i*radius_delta})
        r.place(x=i*pitch_x, y=i*pitch_y)
        if last_ring is not None:
            s.add_route(
                name=f"r{i-1}-r{i}",
                start_ports=[last_ring.ports["o2"]],
                end_ports=[r.ports["o1"]],
                routing_strategy="route_bundle",
            )
        last_ring = r
    return s

c = ring_array()
c
../_images/cfe1fedf99dd762532be948d20519475190df1346c390a1a4f71035aaba7f997.png
c = gf.c.mzi()

# .plot_netlist_graphviz(): This method reads the component's netlist and uses Graphviz (a graph visualization tool) to create a block diagram.
# interactive=False: This parameter specifies that the output should be a static image rather than an interactive plot.
c.plot_netlist_graphviz(interactive=False)
../_images/3d3bc2a77504067ca9efba3d037169afb27dbc8d2d8ddd8069b083ce6ecb4361.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7fda16e29790>
../_images/f38073b6d61b6f6348459513ead90a701e595f4b10be4edb321febe6db9f3378.png

Lets create a MZI lattice of 3 elements.

from kfactory.schematic import RegularArray
import gdsfactory as gf

@gf.cell
def splitter_tree_with_new_ports(**kwargs) -> gf.Component:
    """Returns a splitter tree with new ports."""
    c = gf.c.splitter_tree(**kwargs).copy()
    c.auto_rename_ports()
    return c


pdk = gf.get_active_pdk()
pdk.register_cells(splitter_tree_new_ports=splitter_tree_with_new_ports)


@gf.schematic_cell(overwrite_existing=True) # for development 
def lidar(n: int = 2**3, dbr_pitch: float = 3) -> gf.Schematic:
    """Returns a schematic with lidar array by a waveguide."""
    s = gf.Schematic()
    spt = s.create_inst(name="splitter", component='splitter_tree_new_ports', settings={'noutputs': n, 'spacing': (50, 50)})
    dbr = s.create_inst(name="dbr", component='dbr', array=RegularArray(rows=n, column_pitch=0, row_pitch=dbr_pitch))
    spt.place(x=0, y=0)
    dbr.place(x=250+n*dbr_pitch, y=-n*dbr_pitch/2+dbr_pitch/2)

    start_ports = [spt.ports[f"o{i+2}"] for i in range(n)]
    end_ports = [dbr.ports["o1", 0, i] for i in range(n)]

    s.add_route(
            name="splitter_to_dbr",
            start_ports=start_ports,
            end_ports=end_ports,
            routing_strategy="route_bundle",
            radius=5,
            separation=3,
            sort_ports=True,
        )
    return s

c = lidar(n=2**4)
c
../_images/3a348ccf872f66b95f48fccbada2875f666668deca50b833a39c0b56f91b17d9.png