def solve(self, freqs, complexfreq=False, refnode=gnd): toolkit = self.toolkit circuit_noloop = copy(self.cir) circuit_noloop[self.device] = LoopBreaker(circuit_noloop[self.device], self.inp, self.inn, self.outp, self.outn, parent=circuit_noloop, instance_name=self.device) x = self.toolkit.zeros( self.cir.n) ## FIXME, this should come from the DC analysis epar = self.epar G = self.cir.G(x, epar) G_noloop = circuit_noloop.G(x, epar) C = self.cir.C(x, epar) C_noloop = circuit_noloop.C(x, epar) ## Refer the voltages to the reference node by removing ## the rows and columns that corresponds to this node irefnode = self.cir.get_node_index(refnode) G, G_noloop, C, C_noloop = remove_row_col((G, G_noloop, C, C_noloop), irefnode, self.toolkit) if complexfreq: slist = freqs else: slist = 2j * self.toolkit.pi * freqs ## Calculate return difference def Ffunc(s): Y = toolkit.toMatrix(G + s * C) Y_noloop = toolkit.toMatrix(G_noloop + s * C_noloop) return toolkit.det(Y) / toolkit.det(Y_noloop) if isiterable(slist): F = Waveform(self.toolkit.array(slist), self.toolkit.array([Ffunc(s) for s in slist]), xlabels=('frequency', ), xunits=('Hz', ), ylabel='F') else: F = Ffunc(slist) ## Calculate loop-gain T = F - 1 result = InternalResultDict() result['F'] = F result['T'] = T result['loopgain'] = -T return result
def solve(self, freqs, complexfreq = False, refnode = gnd): toolkit = self.toolkit circuit_noloop = copy(self.cir) circuit_noloop[self.device] = LoopBreaker(circuit_noloop[self.device], self.inp,self.inn, self.outp,self.outn, parent = circuit_noloop, instance_name = self.device) x = self.toolkit.zeros(self.cir.n) ## FIXME, this should come from the DC analysis epar = self.epar G = self.cir.G(x, epar) G_noloop = circuit_noloop.G(x, epar) C = self.cir.C(x, epar) C_noloop = circuit_noloop.C(x, epar) ## Refer the voltages to the reference node by removing ## the rows and columns that corresponds to this node irefnode = self.cir.get_node_index(refnode) G,G_noloop,C,C_noloop = remove_row_col((G,G_noloop,C,C_noloop), irefnode, self.toolkit) if complexfreq: slist = freqs else: slist = 2j * self.toolkit.pi * freqs ## Calculate return difference def Ffunc(s): Y = toolkit.toMatrix(G + s*C) Y_noloop = toolkit.toMatrix(G_noloop + s*C_noloop) return toolkit.det(Y) / toolkit.det(Y_noloop) if isiterable(slist): F = Waveform(self.toolkit.array(slist), self.toolkit.array([Ffunc(s) for s in slist]), xlabels = ('frequency',), xunits = ('Hz',), ylabel = 'F') else: F = Ffunc(slist) ## Calculate loop-gain T = F - 1 result = InternalResultDict() result['F'] = F result['T'] = T result['loopgain'] = -T return result
def solve_s(self, freqs, complexfreq = False): """Calculate scattering (s) parameters of circuit >>> c = SubCircuit() >>> n1 = c.add_node('net1') >>> n2 = c.add_node('net2') >>> c['R1'] = R(n1, n2, r=9e3) >>> c['R2'] = R(n2, gnd, r=1e3) >>> an = TwoPortAnalysis(c, n1, gnd, n2, gnd) >>> twoport = an.solve_s(freqs = 0) >>> mu = 1/twoport.A[0,0] >>> print mu (0.1+0j) """ ## The s-parameters of an n-port are defined as ## B = S * A ## where A and B are column-vectors of size n of ## the ingoing and outgoing waves respectively ## S is an NxN matrix containing the s-parameters ## The elements of the A and B vectors are defined as: ## ## a_n = (v_n + Z0 * i_n) / 2 * 1 / sqrt(|Re Z0|) ## b_n = (v_n - Z0 * i_n) / 2 * 1 / sqrt(|Re Z0|) ## ## where v is the port-voltage and i the current flowing ## into the device, Z0 is an arbitrary chosen impedance ## ## The straight-forward method to calculate the S matrix ## that is used here is to run n AC-analyses and in each ## analysis connect a voltage source of voltage 2V ## in series with a resistor with resistance R0 ohm ## (The chosen Z0 value is real). The other ports ## are terminated with resistance R0. ## The s-parameters S_k_n can now be calculated as: ## S_k_n = b_k / a_n ## where ## a_n = ((2-R0*i_n) + R0 * i+n) / 2 / sqrt(R0) = 1 / sqrt(R0) ## b_k = (v_k + v_k) / 2 / sqrt(R0) = v_k / sqrt(R0) | k != n ## b_n = ((2-R0*i_n) - R0*i_n) / 2 / sqrt(R0) = {i_n = (v_n - 2)/R0} = ## (2-2*R0*(v_n-2)/R0)/2/sqrt(R0) = (1 - v_n - 2) / sqrt(R0) = ## = (v_n - 1) / sqrt(R0) ## => S_k_n = b_k / a_n = v_k | k != n ## S_n_n = b_n / a_n = v_n - 1 ## ## toolkit = self.toolkit # Reference impedance g0 = 1 N = len(self.ports) portnumbers = range(N) S = np.zeros((N,N), dtype=object) circuit = copy(self.cir) refnode = self.ports[0][1] ## Place power sources at the ports for n, sourceport in enumerate(self.ports): circuit['_is%d'%n] = ISInternal(sourceport[1], sourceport[0], i=0,iac = 0, toolkit=toolkit) circuit['_rl%d'%n] = G(sourceport[1], sourceport[0], g = g0, noisy=False, toolkit=toolkit) if toolkit.symbolic: ## For now just one frequency is allowed assert not isiterable(freqs) Gmat, C, CY, u, x, ss = dc_steady_state(circuit, freqs, refnode, toolkit, complexfreq = complexfreq, epar = self.epar) ## Refer the voltages to the reference node by removing ## the rows and columns that corresponds to this node irefnode = self.cir.get_node_index(refnode) Gmat,C,CY,u = remove_row_col((Gmat,C,CY,u), irefnode, toolkit) Y = C * ss + Gmat detY = toolkit.det(Y) for n, sourceport in enumerate(self.ports): ## Add stimulus to the port circuit['_is%d'%n].ipar.iac = 2 * g0 ## If symbolic the s-parameters are calculated using co-factors if toolkit.symbolic: u_wrefnode = circuit.u(x, analysis='internalac', epar=self.epar) (u,) = circuit.remove_refnode((u_wrefnode,), refnode) ## Calculate s-parameters using cofactors for k, port in enumerate(self.ports): resname = "v(%s,%s)"%(port[0], port[1]) res = linearsolver_partial(Y, u, refnode, [resname], circuit, toolkit, detY=detY) if k == n: S[k,n] = res[resname] - 1 else: S[k,n] = res[resname] else: ## Run AC-analysis acana = AC(circuit, toolkit=toolkit, analysis='internalac') res = acana.solve(freqs, refnode=refnode, complexfreq = complexfreq) ## Obtain s-parameters for k, port in enumerate(self.ports): if k == n: S[k,n] = res.v(port[0], port[1]) - 1 else: S[k,n] = res.v(port[0], port[1]) ## Clear stimulus to the port circuit['_is%d'%n].ipar.iac = 0 ## Find noise wave correlation matrix ## The method works as follows: ## 1. terminate all ports with z0 ## 2. calculate transimpedances from a current source in each node ## to the port voltages by using the adjoint Y-matrix. ## As seen above the outgoing wave b is b=V(port_k) / sqrt(z0) ## for a terminated port. ## 3. Form a transform matrix T where the columns are the transimpedance ## vectors divided by sqrt(z0) ## 4. Calculate the correlation matrix as: ## CS = T * CY * T+ ## Calculate transimpedances branchlist = [Branch(*port) for port in self.ports] transimpana = TransimpedanceAnalysis(circuit, toolkit=toolkit) zmlist = transimpana.solve(freqs, branchlist, refnode=refnode, complexfreq=complexfreq) T = np.matrix(zmlist) * g0**0.5 ## Complex frequency variable if complexfreq: s = freqs else: s = 2j*np.pi*freqs ## Calculate CY of circuit x = np.zeros(circuit.n) CY = circuit.CY(x, np.imag(s), epar = self.epar) irefnode = circuit.get_node_index(refnode) CY, = remove_row_col((CY,), irefnode, self.toolkit) ## Calculate noise wave correlation matrix CS = np.array(T * CY * T.H) return NPortS(S, CS, z0=1/toolkit.integer(g0))
def solve_s(self, freqs, complexfreq=False): """Calculate scattering (s) parameters of circuit >>> c = SubCircuit() >>> n1 = c.add_node('net1') >>> n2 = c.add_node('net2') >>> c['R1'] = R(n1, n2, r=9e3) >>> c['R2'] = R(n2, gnd, r=1e3) >>> an = TwoPortAnalysis(c, n1, gnd, n2, gnd) >>> twoport = an.solve_s(freqs = 0) >>> mu = 1/twoport.A[0,0] >>> print mu (0.1+0j) """ ## The s-parameters of an n-port are defined as ## B = S * A ## where A and B are column-vectors of size n of ## the ingoing and outgoing waves respectively ## S is an NxN matrix containing the s-parameters ## The elements of the A and B vectors are defined as: ## ## a_n = (v_n + Z0 * i_n) / 2 * 1 / sqrt(|Re Z0|) ## b_n = (v_n - Z0 * i_n) / 2 * 1 / sqrt(|Re Z0|) ## ## where v is the port-voltage and i the current flowing ## into the device, Z0 is an arbitrary chosen impedance ## ## The straight-forward method to calculate the S matrix ## that is used here is to run n AC-analyses and in each ## analysis connect a voltage source of voltage 2V ## in series with a resistor with resistance R0 ohm ## (The chosen Z0 value is real). The other ports ## are terminated with resistance R0. ## The s-parameters S_k_n can now be calculated as: ## S_k_n = b_k / a_n ## where ## a_n = ((2-R0*i_n) + R0 * i+n) / 2 / sqrt(R0) = 1 / sqrt(R0) ## b_k = (v_k + v_k) / 2 / sqrt(R0) = v_k / sqrt(R0) | k != n ## b_n = ((2-R0*i_n) - R0*i_n) / 2 / sqrt(R0) = {i_n = (v_n - 2)/R0} = ## (2-2*R0*(v_n-2)/R0)/2/sqrt(R0) = (1 - v_n - 2) / sqrt(R0) = ## = (v_n - 1) / sqrt(R0) ## => S_k_n = b_k / a_n = v_k | k != n ## S_n_n = b_n / a_n = v_n - 1 ## ## toolkit = self.toolkit # Reference impedance g0 = 1 N = len(self.ports) portnumbers = range(N) S = np.zeros((N, N), dtype=object) circuit = copy(self.cir) refnode = self.ports[0][1] ## Place power sources at the ports for n, sourceport in enumerate(self.ports): circuit["_is%d" % n] = ISInternal(sourceport[1], sourceport[0], i=0, iac=0, toolkit=toolkit) circuit["_rl%d" % n] = G(sourceport[1], sourceport[0], g=g0, noisy=False, toolkit=toolkit) if toolkit.symbolic: ## For now just one frequency is allowed assert not isiterable(freqs) Gmat, C, CY, u, x, ss = dc_steady_state( circuit, freqs, refnode, toolkit, complexfreq=complexfreq, epar=self.epar ) ## Refer the voltages to the reference node by removing ## the rows and columns that corresponds to this node irefnode = self.cir.get_node_index(refnode) Gmat, C, CY, u = remove_row_col((Gmat, C, CY, u), irefnode, toolkit) Y = C * ss + Gmat detY = toolkit.det(Y) for n, sourceport in enumerate(self.ports): ## Add stimulus to the port circuit["_is%d" % n].ipar.iac = 2 * g0 ## If symbolic the s-parameters are calculated using co-factors if toolkit.symbolic: u_wrefnode = circuit.u(x, analysis="internalac", epar=self.epar) (u,) = circuit.remove_refnode((u_wrefnode,), refnode) ## Calculate s-parameters using cofactors for k, port in enumerate(self.ports): resname = "v(%s,%s)" % (port[0], port[1]) res = linearsolver_partial(Y, u, refnode, [resname], circuit, toolkit, detY=detY) if k == n: S[k, n] = res[resname] - 1 else: S[k, n] = res[resname] else: ## Run AC-analysis acana = AC(circuit, toolkit=toolkit, analysis="internalac") res = acana.solve(freqs, refnode=refnode, complexfreq=complexfreq) ## Obtain s-parameters for k, port in enumerate(self.ports): if k == n: S[k, n] = res.v(port[0], port[1]) - 1 else: S[k, n] = res.v(port[0], port[1]) ## Clear stimulus to the port circuit["_is%d" % n].ipar.iac = 0 ## Find noise wave correlation matrix ## The method works as follows: ## 1. terminate all ports with z0 ## 2. calculate transimpedances from a current source in each node ## to the port voltages by using the adjoint Y-matrix. ## As seen above the outgoing wave b is b=V(port_k) / sqrt(z0) ## for a terminated port. ## 3. Form a transform matrix T where the columns are the transimpedance ## vectors divided by sqrt(z0) ## 4. Calculate the correlation matrix as: ## CS = T * CY * T+ ## Calculate transimpedances branchlist = [Branch(*port) for port in self.ports] transimpana = TransimpedanceAnalysis(circuit, toolkit=toolkit) zmlist = transimpana.solve(freqs, branchlist, refnode=refnode, complexfreq=complexfreq) T = np.matrix(zmlist) * g0 ** 0.5 ## Complex frequency variable if complexfreq: s = freqs else: s = 2j * np.pi * freqs ## Calculate CY of circuit x = np.zeros(circuit.n) CY = circuit.CY(x, np.imag(s), epar=self.epar) irefnode = circuit.get_node_index(refnode) CY, = remove_row_col((CY,), irefnode, self.toolkit) ## Calculate noise wave correlation matrix CS = np.array(T * CY * T.H) return NPortS(S, CS, z0=1 / toolkit.integer(g0))