def sweep_simulation(circuit, iport="input", oport="output", start=1500e-9, stop=1600e-9, num=2000, logscale=True, **kwargs): """ Plot Sparameter circuit transmission over wavelength Args: num: number of sampled points """ circuit = pp.call_if_func(circuit) simulation = SweepSimulation(circuit, start, stop, num) result = simulation.simulate() f, s = result.data(iport, oport) w = freq2wl(f) * 1e9 if logscale: s = 20 * np.log10(abs(s)) ylabel = "|S| (dB)" else: ylabel = "|S|" f, ax = plt.subplots() ax.plot(w, s) plt.xlabel("wavelength (nm)") plt.ylabel(ylabel) plt.title(circuit.name) return ax
def mzi_simulation(**kwargs): """ Run a simulation on the netlist """ circuit = mzi_circuit(**kwargs) simulation = SweepSimulation(circuit, 1500e-9, 1600e-9) result = simulation.simulate() f, s = result.data("input", "output") w = speed_of_light / f plt.plot(w * 1e9, s) plt.title("MZI") plt.xlabel("wavelength (nm)") plt.tight_layout() plt.show()
def get_transmission(circuit, iport="input", oport="output", start=1500e-9, stop=1600e-9, num=2000): circuit = pp.call_if_func(circuit) simulation = SweepSimulation(circuit, start, stop, num) result = simulation.simulate() f, s = result.data(iport, oport) w = freq2wl(f) * 1e9 return dict(wavelength_nm=w, s=s)
def sweep_simulation(circuit, iport="input", oport="output", start=1500e-9, stop=1600e-9, logscale=True, **kwargs): """ Run a simulation on the circuit """ circuit = pp.call_if_func(circuit) simulation = SweepSimulation(circuit, start, stop) result = simulation.simulate() f, s = result.data(iport, oport) w = freq2wl(f) * 1e9 if logscale: s = 20 * np.log10(abs(s)) plt.plot(w, s) plt.title(circuit.name) plt.tight_layout() plt.show()
def result_norm(): # 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 = SweepSimulation(circuit) return sim.simulate()
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 # 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'),
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 }
('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'), ]) # Run a simulation on our circuit. simulation = SweepSimulation(circuit, 1549.9e-9, 1550.1e-9) # simulation = SweepSimulation(circuit, 1510e-9, 1590e-9) result = simulation.simulate() # Get the simulation results # f, s = result.data(result.pinlist['in1'], result.pinlist['out1']) # The Green Machine is optimized for 1550 nanometers. We'd like to investigate # its behavior at that specific frequency: set_freq = wl2freq(1550e-9) in_port = 'in1' plt.figure() plt.plot(*result.data(result.pinlist[in_port], result.pinlist['out1']), label='1 to 5') plt.plot(*result.data(result.pinlist[in_port], result.pinlist['out2']),
('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() f, s = result.data('input', 'output') plt.plot(f, s) plt.title("MZI") plt.tight_layout() plt.show() # We can run a monte carlo simulation on the circuit, too simulation = MonteCarloSweepSimulation(circuit, 1500e-9, 1600e-9) runs = 10 result = simulation.simulate(runs=runs) for i in range(1, runs + 1): f, s = result.data('input', 'output', i) plt.plot(f, s)