def ring_factory(radius): """ Creates a full ring (with terminator) from a half ring. Ports of a half ring are ordered like so: 2 4 | | \ / \ / ---=====--- 1 3 Resulting pins are ('in', 'out', 'pass'). Parameters ---------- radius : float The radius of the ring resonator, in nanometers. """ # Have rings for selecting out frequencies from the data line. # See SiPANN's model API for argument order and units. half_ring = SimphonyWrapper(scee.HalfRing(500, 220, radius, 100)) circuit = Subcircuit() circuit.add([(half_ring, 'input'), (half_ring, 'output'), (term, 'terminator')]) circuit.elements['input'].pins = ('pass', 'midb', 'in', 'midt') circuit.elements['output'].pins = ('out', 'midt', 'term', 'midb') circuit.connect_many([('input', 'midb', 'output', 'midb'), ('input', 'midt', 'output', 'midt'), ('terminator', 'n1', 'output', 'term')]) return circuit
def add_gc(circuit, gc=gc1550te, cpi="input", cpo="output", gpi="port 1", gpo="port 2"): """ add input and output gratings Args: circuit: needs to have `input` and `output` pins gc: grating coupler cpi: circuit pin input name cpo: circuit pin output name gpi: grating pin input name gpo: grating pin output name .. code:: _______ | | gpi-> gpo--|cpi cpo|--gpo <-gpi |_______| """ gc = pp.call_if_func(gc) c = Subcircuit(f"{circuit.name}_{gc.name}") c.add([(gc, "gci"), (gc, "gco"), (circuit, "circuit")]) c.connect_many([("gci", gpo, "circuit", cpi), ("gco", gpo, "circuit", cpo)]) c.elements["gci"].pins[gpi] = "input" c.elements["gco"].pins[gpi] = "output" return c
def add_gc(circuit, gc=siepic.ebeam_gc_te1550): """ add input and output gratings Args: circuit: needs to have `input` and `output` pins gc: grating coupler """ c = Subcircuit(f"{circuit}_gc") gc = pp.call_if_func(gc) c.add([ (gc, "gci"), (gc, "gco"), (circuit, "circuit"), ]) c.connect_many([ ("gci", "n1", "circuit", "input"), ("gco", "n1", "circuit", "output"), ]) # c.elements["circuit"].pins["input"] = "input_circuit" # c.elements["circuit"].pins["output"] = "output_circuit" c.elements["gci"].pins["n2"] = "input" c.elements["gco"].pins["n2"] = "output" return c
def ring_double_siepic( wg_width=0.5, gap=0.2, length_x=4, bend_radius=5, length_y=2, coupler=siepic.ebeam_dc_halfring_straight, waveguide=siepic.ebeam_wg_integral_1550, ): """ double bus ring made of two couplers (ct: top, cb: bottom) connected with two vertical waveguides (wyl: left, wyr: right) .. code:: --==ct==-- | | wl wr length_y | | --==cb==-- gap length_x .. plot:: :include-source: import pp c = pp.c.ring(wg_width=0.5, gap=0.2, length_x=4, bend_radius=5, length_y=2) pp.plotgds(c) .. plot:: :include-source: import simphony.library.gdsfactory as cl c = cl.ring() cl.sweep_simulation(c) """ waveguide = pp.call_if_func(waveguide) coupler = pp.call_if_func(coupler) # Create the circuit, add all individual instances circuit = Subcircuit("mzi") circuit.add([(coupler, "ct"), (coupler, "cb"), (waveguide, "wl"), (waveguide, "wr")]) # Circuits can be connected using the elements' string names: circuit.connect_many([ ("cb", "2", "wl", "n1"), ("wl", "n2", "ct", "n4"), ("ct", "2", "wr", "n2"), ("wr", "n1", "cb", "n4"), ]) circuit.elements["cb"].pins["n4"] = "input" circuit.elements["cb"].pins["n3"] = "output" circuit.elements["ct"].pins["n3"] = "drop" circuit.elements["ct"].pins["n4"] = "cdrop" return circuit
def ring_double_siepic( wg_width=0.5, gap=0.2, length_x=4, bend_radius=5, length_y=2, coupler=siepic.ebeam_dc_halfring_straight, waveguide=siepic.ebeam_wg_integral_1550, terminator=siepic.ebeam_terminator_te1550, ): """ double bus ring made of two couplers (ct: top, cb: bottom) connected with two vertical waveguides (wyl: left, wyr: right) .. code:: --==ct==-- | | wl wr length_y | | --==cb==-- gap length_x drop n1 _ _ n3 cdrop \______/ ______ in n2 _/ \_n4 | | n1 | | n3 \______/ ______ in n2 _/ \_n4 output """ waveguide = pp.call_if_func(waveguide) coupler = pp.call_if_func(coupler) # Create the circuit, add all individual instances circuit = Subcircuit("mzi") circuit.add([(coupler, "ct"), (coupler, "cb"), (waveguide, "wl"), (waveguide, "wr")]) # Circuits can be connected using the elements' string names: circuit.connect_many([ ("cb", "n1", "wl", "n1"), ("wl", "n2", "ct", "n2"), ("ct", "n4", "wr", "n1"), ("wr", "n2", "cb", "n3"), ]) circuit.elements["cb"].pins["n2"] = "input" circuit.elements["cb"].pins["n4"] = "output" circuit.elements["ct"].pins["n1"] = "drop" circuit.elements["ct"].pins["n3"] = "cdrop" return circuit
def ring_double_sipann( wg_width=0.5, gap=0.2, length_x=4, bend_radius=5, length_y=2, coupler=siepic.ebeam_dc_halfring_straight, waveguide=siepic.ebeam_wg_integral_1550, terminator=ebeam.ebeam_terminator_te1550, ): """ double bus ring made of two couplers (ct: top, cb: bottom) connected with two vertical waveguides (wyl: left, wyr: right) .. code:: --==ct==-- | | wl wr length_y | | --==cb==-- gap length_x .. plot:: :include-source: import pp c = pp.c.ring(wg_width=0.5, gap=0.2, length_x=4, bend_radius=5, length_y=2) pp.plotgds(c) .. plot:: :include-source: import simphony.library.gdsfactory as cl c = cl.ring() cl.sweep_simulation(c) """ waveguide = pp.call_if_func(waveguide) half_ring = pp.call_if_func(coupler) term = pp.call_if_func(coupler) circuit = Subcircuit() circuit.add([(half_ring, "input"), (half_ring, "output"), (term, "terminator")]) circuit.elements["input"].pins = ("pass", "midb", "in", "midt") circuit.elements["output"].pins = ("out", "midt", "term", "midb") circuit.connect_many([ ("input", "midb", "output", "midb"), ("input", "midt", "output", "midt"), ("terminator", "n1", "output", "term"), ]) return circuit
def mzi_gc(L0=1, L1=100, L2=10, y_model_factory=mmi1x2): """ MZI with grating couplers Deprecated! use add_gc instead """ y = pp.call_if_func(y_model_factory) gc = siepic.ebeam_gc_te1550() wg_long = siepic.ebeam_wg_integral_1550(length=(2 * L0 + 2 * L1 + L2) * 1e-6) wg_short = siepic.ebeam_wg_integral_1550(length=(2 * L0 + L2) * 1e-6) # Create the circuit, add all individual instances circuit = Subcircuit("MZI") circuit.add([ (gc, "input"), (gc, "output"), (y, "splitter"), (y, "recombiner"), (wg_long, "wg_long"), (wg_short, "wg_short"), ]) # You can set pin names individually: circuit.elements["input"].pins["n2"] = "input" circuit.elements["output"].pins["n2"] = "output" # Or you can rename all the pins simultaneously: # circuit.elements["splitter"].pins = ("in1", "out1", "out2") # circuit.elements["recombiner"].pins = ("out1", "in2", "in1") # Circuits can be connected using the elements' string names: circuit.connect_many([ ("input", "n1", "splitter", "W0"), ("splitter", "E0", "wg_long", "n1"), ("splitter", "E1", "wg_short", "n1"), ("recombiner", "E0", "wg_long", "n2"), ("recombiner", "E1", "wg_short", "n2"), ("output", "n1", "recombiner", "W0"), ]) return circuit
def ring_factory(radius): """ Creates a full ring (with terminator) from a half ring. Ports of a half ring are ordered like so: 2 4 | | \ / \ / ---=====--- 1 3 Resulting pins are ('in', 'out', 'pass'). Parameters ---------- radius : float The radius of the ring resonator, in microns. """ # Have rings for selecting out frequencies from the data line. half_ring = sipann.sipann_dc_halfring(radius=radius) circuit = Subcircuit() circuit.add([ (half_ring, 'input'), (half_ring, 'output'), (term, 'terminator') ]) circuit.elements['input'].pins = ('pass', 'midb', 'in', 'midt') circuit.elements['output'].pins = ('out', 'midt', 'term', 'midb') circuit.connect_many([ ('input', 'midb', 'output', 'midb'), ('input', 'midt', 'output', 'midt'), ('terminator', 'n1', 'output', 'term') ]) return circuit
def result_monte(): # Declare the models used in the circuit gc = siepic.ebeam_gc_te1550() y = siepic.ebeam_y_1550() wg150 = siepic.ebeam_wg_integral_1550(length=150e-6) wg50 = siepic.ebeam_wg_integral_1550(length=50e-6) # Create the circuit, add all individual instances circuit = Subcircuit("MZI") e = circuit.add([ (gc, "input"), (gc, "output"), (y, "splitter"), (y, "recombiner"), (wg150, "wg_long"), (wg50, "wg_short"), ]) # You can set pin names individually: circuit.elements["input"].pins["n2"] = "input" circuit.elements["output"].pins["n2"] = "output" # Or you can rename all the pins simultaneously: circuit.elements["splitter"].pins = ("in1", "out1", "out2") circuit.elements["recombiner"].pins = ("out1", "in2", "in1") # Circuits can be connected using the elements' string names: circuit.connect_many([ ("input", "n1", "splitter", "in1"), ("splitter", "out1", "wg_long", "n1"), ("splitter", "out2", "wg_short", "n1"), ("recombiner", "in1", "wg_long", "n2"), ("recombiner", "in2", "wg_short", "n2"), ("output", "n1", "recombiner", "out1"), ]) sim = MonteCarloSweepSimulation(circuit) return sim.simulate()
) # You can set pin names individually (here I'm naming all the outputs that # I'll want to access after the simulation has been run): circuit.elements["input"].pins["n1"] = "input" circuit.elements["out1"].pins["n2"] = "out1" circuit.elements["out2"].pins["n2"] = "out2" circuit.elements["out3"].pins["n2"] = "out3" circuit.connect_many( [ ("input", "n2", "ring10", "in"), ("out1", "n1", "ring10", "out"), ("connect1", "n1", "ring10", "pass"), ("connect1", "n2", "ring11", "in"), ("out2", "n1", "ring11", "out"), ("connect2", "n1", "ring11", "pass"), ("connect2", "n2", "ring12", "in"), ("out3", "n1", "ring12", "out"), ("terminator", "n1", "ring12", "pass"), ] ) # Run a simulation on the netlist. simulation = SweepSimulation(circuit, 1524.5e-9, 1551.15e-9) result = simulation.simulate() fig = plt.figure(tight_layout=True) gs = gridspec.GridSpec(1, 3) ax = fig.add_subplot(gs[0, :2])
def mzi( L0=1, L1=100, L2=10, y_model_factory=siepic.ebeam_y_1550, wg=siepic.ebeam_wg_integral_1550, ): """ Mzi circuit model Args: L0 (um): vertical length for both and top arms L1 (um): bottom arm extra length, delta_length = 2*L1 L2 (um): L_top horizontal length .. code:: __L2__ | | L0 L0r | | splitter==| |==recombiner | | L0 L0r | | L1 L1 | | |__L2__| .. plot:: :include-source: import pp c = pp.c.mzi(L0=0.1, L1=0, L2=10) pp.plotgds(c) .. plot:: :include-source: import ubc c = ubc.cm.mzi() gl.sweep_simulation(c) """ y = pp.call_if_func(y_model_factory) wg_long = wg(length=(2 * L0 + 2 * L1 + L2) * 1e-6) wg_short = wg(length=(2 * L0 + L2) * 1e-6) # Create the circuit, add all individual instances circuit = Subcircuit("mzi") circuit.add([ (y, "splitter"), (y, "recombiner"), (wg_long, "wg_long"), (wg_short, "wg_short"), ]) circuit.elements["splitter"].pins = ("in1", "out1", "out2") circuit.elements["recombiner"].pins = ("out1", "in2", "in1") # Circuits can be connected using the elements' string names: circuit.connect_many([ ("splitter", "out1", "wg_long", "n1"), ("splitter", "out2", "wg_short", "n1"), ("recombiner", "in1", "wg_long", "n2"), ("recombiner", "in2", "wg_short", "n2"), ]) circuit.elements["splitter"].pins["in1"] = "input" circuit.elements["recombiner"].pins["out1"] = "output" return circuit
# work on the circuit connnections. circuit.connect_many([ ('in1', 'n2', 'wg1', 'in'), ('in2', 'n2', 'wg2', 'in'), ('in3', 'n2', 'wg3', 'in'), ('in4', 'n2', 'wg4', 'in'), ('wg1', 'out', 'dc1', 'in1'), ('wg2', 'out', 'dc1', 'in2'), ('wg3', 'out', 'dc2', 'in1'), ('wg4', 'out', 'dc2', 'in2'), ('dc1', 'out1', 'wg_pass1', 'in'), ('dc1', 'out2', 'wg_in1', 'in'), ('wg_in1', 'out', 'crossing', 'in1'), ('crossing', 'out1', 'wg_out1', 'in'), ('dc2', 'out1', 'wg_in2', 'in'), ('wg_in2', 'out', 'crossing', 'in2'), ('crossing', 'out2', 'wg_out2', 'in'), ('dc2', 'out2', 'wg_pass2', 'in'), ('wg_pass1', 'out', 'dc3', 'in1'), ('wg_out1', 'out', 'dc3', 'in2'), ('wg_out2', 'out', 'dc4', 'in1'), ('wg_pass2', 'out', 'dc4', 'in2'), ('dc3', 'out1', 'wg5', 'in'), ('dc3', 'out2', 'wg6', 'in'), ('dc4', 'out1', 'wg7', 'in'), ('dc4', 'out2', 'wg8', 'in'), ('wg5', 'out', 'out1', 'n1'), ('wg6', 'out', 'out2', 'n1'), ('wg7', 'out', 'out3', 'n1'), ('wg8', 'out', 'out4', 'n1'), ])
def mzi(L0=1, L1=100, L2=10, y_model_factory=mmi1x2): """ Mzi Args: L0: vertical length for both and top arms L1: bottom arm extra length, delta_length = 2*L1 L2: L_top horizontal length .. code:: __L2__ | | L0 L0r | | splitter==| |==recombiner | | L0 L0r | | L1 L1 | | |__L2__| .. plot:: :include-source: import pp c = pp.c.mzi(L0=0.1, L1=0, L2=10) pp.plotgds(c) .. plot:: :include-source: import simphony.library.gdsfactory as cl c = cl.mzi() simulation = SweepSimulation(circuit, 1500e-9, 1600e-9) result = simulation.simulate() f, s = result.data("input", "output") plt.plot(f, s) plt.title("MZI") plt.tight_layout() plt.show() """ y = pp.call_if_func(y_model_factory) wg_long = siepic.ebeam_wg_integral_1550(length=(2 * L0 + 2 * L1 + L2) * 1e-6) wg_short = siepic.ebeam_wg_integral_1550(length=(2 * L0 + L2) * 1e-6) # Create the circuit, add all individual instances circuit = Subcircuit("mzi") circuit.add([ (y, "splitter"), (y, "recombiner"), (wg_long, "wg_long"), (wg_short, "wg_short"), ]) # Circuits can be connected using the elements' string names: circuit.connect_many([ ("splitter", "E0", "wg_long", "n1"), ("splitter", "E1", "wg_short", "n1"), ("recombiner", "E0", "wg_long", "n2"), ("recombiner", "E1", "wg_short", "n2"), ]) circuit.elements["splitter"].pins["W0"] = "input" circuit.elements["recombiner"].pins["W0"] = "output" return circuit
def mzi_circuit(L0=1, L1=100, L2=10): """ Mzi Args: L0: vertical length for both and top arms L1: bottom arm extra length L2: L_top horizontal length .. code:: __L2__ | | L0 L0r | | splitter==| |==recombiner | | L0 L0r | | L1 L1 | | |__L2__| .. plot:: :include-source: import pp c = pp.c.mzi(L0=0.1, L1=0, L2=10) pp.plotgds(c) """ gc = siepic.ebeam_gc_te1550() y = siepic.ebeam_y_1550() wg_long = siepic.ebeam_wg_integral_1550(length=(2 * L0 + +L1 + L2) * 1e-6) wg_short = siepic.ebeam_wg_integral_1550(length=(2 * L0 + L2) * 1e-6) # Create the circuit, add all individual instances circuit = Subcircuit("MZI") circuit.add([ (gc, "input"), (gc, "output"), (y, "splitter"), (y, "recombiner"), (wg_long, "wg_long"), (wg_short, "wg_short"), ]) # You can set pin names individually: circuit.elements["input"].pins["n2"] = "input" circuit.elements["output"].pins["n2"] = "output" # Or you can rename all the pins simultaneously: circuit.elements["splitter"].pins = ("in1", "out1", "out2") circuit.elements["recombiner"].pins = ("out1", "in2", "in1") # Circuits can be connected using the elements' string names: circuit.connect_many([ ("input", "n1", "splitter", "in1"), ("splitter", "out1", "wg_long", "n1"), ("splitter", "out2", "wg_short", "n1"), ("recombiner", "in1", "wg_long", "n2"), ("recombiner", "in2", "wg_short", "n2"), ("output", "n1", "recombiner", "out1"), ]) return circuit
circuit.connect_many( [ ("in1", "n2", "wg1", "in"), ("in2", "n2", "wg2", "in"), ("in3", "n2", "wg3", "in"), ("in4", "n2", "wg4", "in"), ("wg1", "out", "dc1", "in1"), ("wg2", "out", "dc1", "in2"), ("wg3", "out", "dc2", "in1"), ("wg4", "out", "dc2", "in2"), ("dc1", "out1", "wg_pass1", "in"), ("dc1", "out2", "wg_in1", "in"), ("wg_in1", "out", "crossing", "in1"), ("crossing", "out1", "wg_out1", "in"), ("dc2", "out1", "wg_in2", "in"), ("wg_in2", "out", "crossing", "in2"), ("crossing", "out2", "wg_out2", "in"), ("dc2", "out2", "wg_pass2", "in"), ("wg_pass1", "out", "dc3", "in1"), ("wg_out1", "out", "dc3", "in2"), ("wg_out2", "out", "dc4", "in1"), ("wg_pass2", "out", "dc4", "in2"), ("dc3", "out1", "wg5", "in"), ("dc3", "out2", "wg6", "in"), ("dc4", "out1", "wg7", "in"), ("dc4", "out2", "wg8", "in"), ("wg5", "out", "out1", "n1"), ("wg6", "out", "out2", "n1"), ("wg7", "out", "out3", "n1"), ("wg8", "out", "out4", "n1"), ] )
(wg50, 'wg_short'), ]) # You can set pin names individually: circuit.elements['input'].pins['n2'] = 'input' circuit.elements['output'].pins['n2'] = 'output' # Or you can rename all the pins simultaneously: circuit.elements['splitter'].pins = ('in1', 'out1', 'out2') circuit.elements['recombiner'].pins = ('out1', 'in2', 'in1') # Circuits can be connected using the elements' string names: circuit.connect_many([ ('input', 'n1', 'splitter', 'in1'), ('splitter', 'out1', 'wg_long', 'n1'), ('splitter', 'out2', 'wg_short', 'n1'), ('recombiner', 'in1', 'wg_long', 'n2'), ('recombiner', 'in2', 'wg_short', 'n2'), ('output', 'n1', 'recombiner', 'out1'), ]) # or by using the actual object reference. # circuit.connect(e[0], e[0].pin[0], e[2], e[2].pin[0]) # At this point, your circuit is defined. This file can serve as a description # for a subcircuit that is used in a larger circuit, and can simply be imported # using the Python import system (``from mzi import circuit``). # Run a simulation on the netlist. simulation = SweepSimulation(circuit, 1500e-9, 1600e-9) result = simulation.simulate()
) # You can set pin names individually: circuit.elements["input"].pins["n2"] = "input" circuit.elements["output"].pins["n2"] = "output" # Or you can rename all the pins simultaneously: circuit.elements["splitter"].pins = ("in1", "out1", "out2") circuit.elements["recombiner"].pins = ("out1", "in2", "in1") # Circuits can be connected using the elements' string names: circuit.connect_many( [ ("input", "n1", "splitter", "in1"), ("splitter", "out1", "wg_long", "n1"), ("splitter", "out2", "wg_short", "n1"), ("recombiner", "in1", "wg_long", "n2"), ("recombiner", "in2", "wg_short", "n2"), ("output", "n1", "recombiner", "out1"), ] ) # or by using the actual object reference. # circuit.connect(e[0], e[0].pin[0], e[2], e[2].pin[0]) # At this point, your circuit is defined. This file can serve as a description # for a subcircuit that is used in a larger circuit, and can simply be imported # using the Python import system (``from mzi import circuit``). # Run a simulation on the netlist. simulation = SweepSimulation(circuit, 1500e-9, 1600e-9) result = simulation.simulate()
(wg_data, 'connect2'), (ring_factory(12000), 'ring12'), (wg_data, 'out3'), (term, 'terminator')]) # You can set pin names individually (here I'm naming all the outputs that # I'll want to access after the simulation has been run): circuit.elements['input'].pins['n1'] = 'input' circuit.elements['out1'].pins['n2'] = 'out1' circuit.elements['out2'].pins['n2'] = 'out2' circuit.elements['out3'].pins['n2'] = 'out3' circuit.connect_many([ ('input', 'n2', 'ring10', 'in'), ('out1', 'n1', 'ring10', 'out'), ('connect1', 'n1', 'ring10', 'pass'), ('connect1', 'n2', 'ring11', 'in'), ('out2', 'n1', 'ring11', 'out'), ('connect2', 'n1', 'ring11', 'pass'), ('connect2', 'n2', 'ring12', 'in'), ('out3', 'n1', 'ring12', 'out'), ('terminator', 'n1', 'ring12', 'pass'), ]) # Run a simulation on the netlist. simulation = SweepSimulation(circuit, 1524.5e-9, 1551.15e-9) result = simulation.simulate() fig = plt.figure(tight_layout=True) gs = gridspec.GridSpec(1, 3) ax = fig.add_subplot(gs[0, :2]) f, s = result.data('input', 'out1')
def mzi( length_y: float = 1.0, delta_length: float = 100.0, length_x: float = 10.0, y_model_factory: ModelFactory = siepic.ebeam_y_1550, waveguide: ModelFactory = siepic.ebeam_wg_integral_1550, ) -> Subcircuit: """Mzi circuit model Args: length_y: vertical length for both and top arms (um) delta_length: bottom arm extra length length_x: horizontal length for both and top arms (um) waveguide: waveguide_model .. code:: __Lx__ | | Ly Lyr (not a parameter) | | splitter==| |==combiner | | Ly Lyr (not a parameter) | | | delta_length/2 | | |__Lx__| .. plot:: :include-source: import pp c = pp.c.mzi(length_y=0.1, delta_length=0, length_x=10) pp.plotgds(c) .. plot:: :include-source: import ubc import gdslib as gl c = ubc.circuits.mzi() gl.plot_circuit(c) """ y = pp.call_if_func(y_model_factory) wg_long = waveguide(length=(2 * length_y + delta_length + length_x) * 1e-6) wg_short = waveguide(length=(2 * length_y + length_x) * 1e-6) # Create the circuit, add all individual instances circuit = Subcircuit("mzi") circuit.add([ (y, "splitter"), (y, "recombiner"), (wg_long, "wg_long"), (wg_short, "wg_short"), ]) circuit.elements["splitter"].pins = ("in1", "out1", "out2") circuit.elements["recombiner"].pins = ("out1", "in2", "in1") # Circuits can be connected using the elements' string names: circuit.connect_many([ ("splitter", "out1", "wg_long", "n1"), ("splitter", "out2", "wg_short", "n1"), ("recombiner", "in1", "wg_long", "n2"), ("recombiner", "in2", "wg_short", "n2"), ]) circuit.elements["splitter"].pins["in1"] = "input" circuit.elements["recombiner"].pins["out1"] = "output" return circuit
def ring_double( wg_width=0.5, gap=0.2, length_x=4, bend_radius=5, length_y=2, coupler=coupler_ring, waveguide=siepic.ebeam_wg_integral_1550, ): """ double bus ring made of two couplers (ct: top, cb: bottom) connected with two vertical waveguides (wyl: left, wyr: right) .. code:: --==ct==-- | | wl wr length_y | | --==cb==-- gap length_x ---=========--- E0 length_x W0 / \ / \ | | N1 N0 N0 N1 | | \ / \ / ---=========--- W0 length_x E0 .. plot:: :include-source: import pp c = pp.c.ring_double(wg_width=0.5, gap=0.2, length_x=4, bend_radius=5, length_y=2) pp.plotgds(c) .. plot:: :include-source: import gdslib as gl c = gl.ring_double() gl.sweep_simulation(c) """ waveguide = pp.call_if_func(waveguide) coupler = pp.call_if_func(coupler, length_x=length_x, bend_radius=bend_radius, gap=gap, wg_width=wg_width) # Create the circuit, add all individual instances circuit = Subcircuit("ring_double") circuit.add([(coupler, "ct"), (coupler, "cb"), (waveguide, "wl"), (waveguide, "wr")]) # Circuits can be connected using the elements' string names: circuit.connect_many([ ("cb", "N0", "wl", "n1"), ("wl", "n2", "ct", "N1"), ("ct", "N0", "wr", "n1"), ("wr", "n2", "cb", "N1"), ]) circuit.elements["cb"].pins["W0"] = "input" circuit.elements["cb"].pins["E0"] = "output" circuit.elements["ct"].pins["E0"] = "drop" circuit.elements["ct"].pins["W0"] = "cdrop" return circuit