Пример #1
0
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
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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
Пример #6
0
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()
Пример #7
0
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
Пример #8
0
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
Пример #9
0
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
Пример #10
0
# Behold, we can run a simulation on a single ring resonator.
cir1 = ring_factory(10000)
sim1 = SweepSimulation(cir1, 1500e-9, 1600e-9)
res1 = sim1.simulate()

f1, s = res1.data(res1.pinlist["in"], res1.pinlist["pass"])
plt.plot(f1, s)
plt.title("10-micron Ring Resonator")
plt.tight_layout()
plt.show()


# Now, we'll create the circuit (using several ring resonator subcircuits)
# and add all individual instances.
circuit = Subcircuit("Add-Drop Filter")
e = circuit.add(
    [
        (wg_data, "input"),
        (ring_factory(10000), "ring10"),
        (wg_data, "out1"),
        (wg_data, "connect1"),
        (ring_factory(11000), "ring11"),
        (wg_data, "out2"),
        (wg_data, "connect2"),
        (ring_factory(12000), "ring12"),
        (wg_data, "out3"),
        (term, "terminator"),
    ]
)
Пример #11
0
def build_circuit(data, libraries):
    """
    Parameters
    ----------
    data : dict
        The dictionary defining all the circuits and analyzers, as exported
        by SiEPIC and parsed by the parser.
    libraries : list or str
        A string or list of strings of python module names containing the 
        model libraries for the components in the circuit.

    Returns
    -------
    built : dict
        A dictionary of constructed Python objects, with the following keys:
            - `circuits`: dictionary of circuit names to their corresponding
              instantiated Subcircuit objects.
            - `subcircuits`: instantiated Subcircuit objects for all 
              subcircuits found in the spice data.
            - `analyses`: instantiated Simulation objects for all network
              analyzers found in the spice data.
    """
    # Make sure `libraries` is a list
    libraries = libraries if type(libraries) is list else [libraries]

    # Create a dictionary from component names to their models
    available_comps = get_components(libraries)

    # Create all the defined subcircuits
    # [`name`, `ports`, `components`, `params`]
    subcircuits = {}
    for sub in data['subcircuits']:
        circuit = Subcircuit(sub['name'])
        connections = {}

        # Create all the components in the subcircuit and compile all the connections
        # [`name`, `model`, `ports`, `params`]
        for component in sub['components']:
            # Add each component
            kwargs = rearg(component['model'], component['params'])
            circuit.add([(available_comps[component['model']](**kwargs),
                          component['name'])])
            circuit.elements[component['name']].pins = tuple(
                pin for pin in component['ports'])

            # Track all it's nets
            for port in component['ports']:
                if port in connections:
                    connections[port].append(component['name'])
                else:
                    connections[port] = [component['name']]

        # Create all the connections between components
        for port, comps in connections.items():
            circuit.connect(comps[0], port, comps[1],
                            port) if len(comps) == 2 else None

        subcircuits[sub['name']] = circuit

    # Create circuits, since they're composed of subcircuits
    # [`name`, `ports`, `subcircuits`, `params`]
    circuits = {}
    # TODO: What if one day a circuit contains more than one subcircuit?
    for circ in data['circuits']:
        subs = subcircuits[circ['subcircuits']]
        if len(circ['ports']) != len(subs.pins):
            raise ValueError(
                'Ports on circuit do not match ports on subcircuit.')
        circuits[circ['name']] = subs

    # Create all the simulation objects
    # [`definition`, `params`].
    analyses = []
    for analysis in data['analyses']:
        # [`input_unit`, `input_parameter`]
        if analysis['definition']['input_parameter'] == 'start_and_stop':
            # [`minimum_loss`, `analysis_type`, `multithreading`,
            #  `number_of_threads`, `orthogonal_identifier`, `start`, `stop`,
            #  `number_of_points`, `input`, `output`]
            circ, inp = analysis['params']['output'].split(',')
            start = analysis['params']['start']
            stop = analysis['params']['stop']
            points = int(analysis['params']['number_of_points'])
            mode = 'wl' if analysis['definition'][
                'input_unit'] == 'wavelength' else 'freq'
            sim = SweepSimulation(circuits[circ], start, stop, points, mode)
            analyses.append(sim)

    return {
        'circuits': circuits,
        'subcircuits': subcircuits,
        'analyses': analyses
    }
Пример #12
0
Файл: mzi.py Проект: tvt173/ubc
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
Пример #13
0
import matplotlib.pyplot as plt
import numpy as np

from simphony.library import siepic
from simphony.netlist import Subcircuit
from simphony.simulation import SweepSimulation, MonteCarloSweepSimulation

# 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')
Пример #14
0
import matplotlib.pyplot as plt
import numpy as np

from simphony.library import siepic
from simphony.netlist import Subcircuit
from simphony.simulation import SweepSimulation, MonteCarloSweepSimulation

# 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"
Пример #15
0
# We can rename the pins attribute on the class before we instantiate them;
# then we don't have to rename the pins on each element individually later.
ebeam.ebeam_wg_integral_1550.pins = ("in", "out")
sipann.sipann_dc_fifty.pins = ("in1", "in2", "out1", "out2")
sipann.sipann_dc_crossover1550.pins = ("in1", "in2", "out1", "out2")

# Get all the models we're going to need for the green machine circuit:
gc = ebeam.ebeam_gc_te1550()
wg100 = ebeam.ebeam_wg_integral_1550(length=100e-6)
dc = sipann.sipann_dc_fifty()
crossover = sipann.sipann_dc_crossover1550()
wgin2 = ebeam.ebeam_wg_integral_1550(length=102.125e-6)
wg300 = ebeam.ebeam_wg_integral_1550(length=300e-6)

# Add all the elements used in the circuit
circuit = Subcircuit("Green Machine")
e = circuit.add(
    [
        # Define the four input grating couplers
        (gc, "in1"),
        (gc, "in2"),
        (gc, "in3"),
        (gc, "in4"),
        # The grating couplers each feed into their own waveguide
        (wg100, "wg1"),
        (wg100, "wg2"),
        (wg100, "wg3"),
        (wg100, "wg4"),
        # Each pair of waveguides feeds into a 50/50 directional coupler
        (dc, "dc1"),
        (dc, "dc2"),
Пример #16
0
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
Пример #17
0
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
Пример #18
0

# Behold, we can run a simulation on a single ring resonator.
cir1 = ring_factory(10000)
sim1 = SweepSimulation(cir1, 1500e-9, 1600e-9)
res1 = sim1.simulate()

f1, s = res1.data(res1.pinlist['in'], res1.pinlist['pass'])
plt.plot(f1, s)
plt.title("10-micron Ring Resonator")
plt.tight_layout()
plt.show()

# Now, we'll create the circuit (using several ring resonator subcircuits)
# and add all individual instances.
circuit = Subcircuit('Add-Drop Filter')
e = circuit.add([(wg_data, 'input'), (ring_factory(10000), 'ring10'),
                 (wg_data, 'out1'), (wg_data, 'connect1'),
                 (ring_factory(11000), 'ring11'), (wg_data, 'out2'),
                 (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'),
Пример #19
0
# We can rename the pins attribute on the class before we instantiate them;
# then we don't have to rename the pins on each element individually later.
ebeam.ebeam_wg_integral_1550.pins = ('in', 'out')
sipann.sipann_dc_fifty.pins = ('in1', 'in2', 'out1', 'out2')
sipann.sipann_dc_crossover1550.pins = ('in1', 'in2', 'out1', 'out2')

# Get all the models we're going to need for the green machine circuit:
gc = ebeam.ebeam_gc_te1550()
wg100 = ebeam.ebeam_wg_integral_1550(length=100e-6)
dc = sipann.sipann_dc_fifty()
crossover = sipann.sipann_dc_crossover1550()
wgin2 = ebeam.ebeam_wg_integral_1550(length=102.125e-6)
wg300 = ebeam.ebeam_wg_integral_1550(length=300e-6)

# Add all the elements used in the circuit
circuit = Subcircuit('Green Machine')
e = circuit.add([
    # Define the four input grating couplers
    (gc, 'in1'),
    (gc, 'in2'),
    (gc, 'in3'),
    (gc, 'in4'),

    # The grating couplers each feed into their own waveguide
    (wg100, 'wg1'),
    (wg100, 'wg2'),
    (wg100, 'wg3'),
    (wg100, 'wg4'),

    # Each pair of waveguides feeds into a 50/50 directional coupler
    (dc, 'dc1'),
Пример #20
0
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
Пример #21
0
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