def connect_circuit(netlist): """ Connects the s-matrices of a photonic circuit given its Netlist and returns a single 'SimulatedComponent' object containing the frequency array, the assembled s-matrix, and a list of the external nets (negative integers). Parameters ---------- component_list : List[SimulatedComponent] A list of the components to be connected. net_count : int The total number of internal nets in the component list. Returns ------- combined : ScatteringMatrix After the circuit has been fully connected, the result is a single ComponentSimulation with fields f (frequency), s (s-matrix), and nets (external ports: negative numbers, as strings). Notes ----- This function doesn't actually store ``combined`` on each iteration through the netlist. That's because the Pin objects can only reference one PinList at a time, which in turn can only reference one Element. Since we transferring the actual Pin objects between lists, keeping a reference to the Pin also keeps a reference to the ``combined`` Element alive. Hence, we track pins but not the ``SimulationResult``. """ _logger = _module_logger.getChild('SweepSimulation.connect_circuit') # FIXME: What if there are no items in the netlist (only one element # in the circuit)? for net in netlist: p1, p2 = net if p1.element == p2.element: _logger.debug('Internal connection') combined = ScatteringMatrix() combined.s = innerconnect_s(p1.element.s, p1.index, p2.index) pinlist = p1.pinlist pinlist.remove(p1, p2) combined.pinlist = pinlist else: _logger.debug('External connection') combined = ScatteringMatrix() combined.s = connect_s(p1.element.s, p1.index, p2.element.s, p2.index) pinlist = p1.pinlist + p2.pinlist pinlist.remove(p1, p2) combined.pinlist = pinlist return combined
import matplotlib.pyplot as plt import numpy as np from simphony.library import ebeam, sipann from simphony.connect import innerconnect_s, connect_s from simphony.simulation import freq2wl, wl2freq # First, we'll set up the frequency range we wish to perform the simulation on. freq = np.linspace(wl2freq(1600e-9), wl2freq(1500e-9), 2000) # Get the scattering parameters for each of the elements in our network. half_ring_left = sipann.sipann_dc_halfring(radius=10).s_parameters(freq) half_ring_right = sipann.sipann_dc_halfring(radius=10).s_parameters(freq) term = ebeam.ebeam_terminator_te1550().s_parameters(freq) ### CONFIGURATION 1 ### n1 = connect_s(half_ring_left, 1, half_ring_right, 3) n2 = innerconnect_s(n1, 2, 4) n3 = connect_s(n2, 1, term, 0) ### CONFIGURATION 2 ### m1 = connect_s(half_ring_right, 1, half_ring_left, 3) m2 = innerconnect_s(m1, 2, 4) m3 = connect_s(term, 0, m2, 3) plt.plot(freq, np.abs(n3[:, 1, 2])**2, 'b.') plt.plot(freq, np.abs(m3[:, 0, 1])**2, 'r--') plt.tight_layout() plt.show()
def _s_parameters( self, freqs: "np.array", s_parameters_method: str = "s_parameters", ) -> "np.ndarray": """Returns the scattering parameters for the subcircuit. This method will combine the s-matrices of the underlying components using the subnetwork growth algorithm. Parameters ---------- freqs : The list of frequencies to get scattering parameters for. s_parameters_method : The method name to call to get the scattering parameters. Either 's_parameters' or 'monte_carlo_s_parameters' """ from simphony.simulators import Simulator all_pins = [] available_pins = [] s_block = None # merge all of the s_params into one giant block diagonal matrix for component in self._wrapped_circuit: # simulators don't have scattering parameters if isinstance(component, Simulator): continue # get the s_params from the cache if possible if s_parameters_method == "s_parameters": try: s_params = self.__class__.scache[component] except KeyError: s_params = getattr(component, s_parameters_method)(freqs) self.__class__.scache[component] = s_params elif s_parameters_method == "monte_carlo_s_parameters": # don't cache Monte Carlo scattering parameters s_params = getattr(component, s_parameters_method)(freqs) # merge the s_params into the block diagonal matrix if s_block is None: s_block = s_params else: s_block = create_block_diagonal(s_block, s_params) # keep track of all of the pins (in order) in the circuit all_pins += component.pins available_pins += component.pins # use the subnetwork growth algorithm for each connection for pin in all_pins: # make sure pins only get connected once # and pins connected to simulators get skipped if (pin._isconnected(include_simulators=False) and pin in available_pins and pin._connection in available_pins): # the pin indices in available_pins lines up with the row/column # indices in the matrix. as the matrix shrinks, we remove pins # from available_pins so the indices always line up k = available_pins.index(pin) l = available_pins.index(pin._connection) s_block = innerconnect_s(s_block, k, l) available_pins.remove(pin) available_pins.remove(pin._connection) return s_block