def solve_abcd(self, freqs, refnode = gnd, complexfreq = False): (inp, inn), (outp, outn) = self.ports toolkit = self.toolkit ## Add voltage source at input port and create ## copies with output open and shorted respectively circuit_vs_open = copy(self.cir) circuit_vs_open['VS_TwoPort'] = VS(inp, inn, vac=1) circuit_vs_shorted = copy(circuit_vs_open) circuit_vs_shorted['VL_TwoPort'] = VS(outp, outn, vac=0) ## Run AC-analysis on the two circuits ac_open = AC(circuit_vs_open, toolkit=toolkit) ac_shorted = AC(circuit_vs_shorted, toolkit=toolkit) res_open = ac_open.solve(freqs, refnode = refnode, complexfreq=complexfreq) res_shorted = ac_shorted.solve(freqs, refnode = refnode, complexfreq=complexfreq) A = res_open.v(inp, inn) / res_open.v(outp, outn) B = res_shorted.v(inp, inn) / res_shorted.i('VL_TwoPort.plus') C = res_open.i('VS_TwoPort.minus') / res_open.v(outp, outn) D = res_shorted.i('VS_TwoPort.minus') / res_shorted.i('VL_TwoPort.plus') return np.array([[A,B],[C,D]], dtype=object)
def solve(self, freqs, refnode=gnd, complexfreq=False): toolkit = self.toolkit x = self.toolkit.zeros( self.cir.n) ## FIXME, this should be replaced by DC-analysis self.loopprobe['vinj'].ipar.vac = 1 self.loopprobe['iinj'].ipar.iac = 0 ac_vinj = AC(self.cir, toolkit=toolkit) res_vinj = ac_vinj.solve(freqs, refnode=refnode, complexfreq=complexfreq, u=self.cir.u(x, analysis='feedback')) self.loopprobe['vinj'].ipar.vac = 0 self.loopprobe['iinj'].ipar.iac = 1 ac_iinj = AC(self.cir, toolkit=toolkit) res_iinj = ac_iinj.solve(freqs, refnode=refnode, complexfreq=complexfreq, u=self.cir.u(x, analysis='feedback')) B = res_vinj.i(self.loopprobe_name + '.vinj.plus') D = res_vinj.v(self.loopprobe_name + '.inp', self.loopprobe_name + '.inn') A = res_iinj.i(self.loopprobe_name + '.vinj.plus') C = res_iinj.v(self.loopprobe_name + '.inp', self.loopprobe_name + '.inn') T = (2 * (A * D - B * C) - A + D) / (2 * (B * C - A * D) + A - D + 1) result = InternalResultDict() result['F'] = 1 + T 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))