Пример #1
0
    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
Пример #2
0
    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
Пример #3
0
    def ss_map_function(self, func, ss, refnode):
        """Apply a function over a list of frequencies or a single frequency"""
        irefnode = self.cir.nodes.index(refnode)

        def myfunc(s):
            x = func(s)
            # Insert reference node voltage
            return self.toolkit.concatenate((x[:irefnode], self.toolkit.array([0.0]), x[irefnode:]))
            
        if isiterable(ss):
            return self.toolkit.array([myfunc(s) for s in ss]).swapaxes(0,1)
        else:
            return myfunc(ss)
Пример #4
0
    def noise_map_function(self, func, ss, refnode):
        """Apply a function over a list of frequencies or a single frequency"""
        irefnode = self.cir.nodes.index(refnode)

        def myfunc(s):
            x, g = func(s)
            return x,g 
            
        if isiterable(ss):
            xlist = []
            glist = []
            for s in ss:
                x,g = myfunc(s)
                xlist = xlist + [x]
                glist = glist + [g]
            return self.toolkit.array(xlist),self.toolkit.array(glist) 
        else:
            return myfunc(ss)
Пример #5
0
def identify_sweep(x, maxerr=1e-6):
    """Identifies sweep from sweep values and return sweep instance"""
    if isinstance(x, (LinSweep, LogSweep)):
        return x

    if not isiterable(x):
        return LinSweep(x, x, 1)

    values = np.array(list(x))

    if len(values) == 1:
        return LinSweep(values[0], values[0], 1)

    linstep = np.diff(values)

    if np.linalg.norm(linstep - linstep[0]) <= maxerr:
        return LinSweep(values[0], values[-1], len(values))
    else:
        return Sweep(values)
Пример #6
0
def identify_sweep(x, maxerr=1e-6):
    """Identifies sweep from sweep values and return sweep instance"""
    if isinstance(x, (LinSweep, LogSweep)):
        return x

    if not isiterable(x):
        return LinSweep(x, x, 1)

    values = np.array(list(x))

    if len(values) == 1:
        return LinSweep(values[0], values[0], 1)

    linstep = np.diff(values)

    if np.linalg.norm(linstep - linstep[0]) <= maxerr:
        return LinSweep(values[0], values[-1], len(values))
    else:
        return Sweep(values)
Пример #7
0
    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))
Пример #8
0
    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))