Esempio n. 1
0
    def run(self, circuit):
        """
        Calculates a DC sweep by solving nodal equations

        The parameter to be swept is specified in the analysis options
        """
        # for now just print some fixed stuff
        print('******************************************************')
        print('                 DC sweep analysis')
        print('******************************************************')
        if hasattr(circuit, 'title'):
            print('\n', circuit.title, '\n')

        if glVar.sparse:
            nd = nodalSP
        else:
            nd = nodal
            print('Using dense matrices\n')

        # Only works with flattened circuits
        if not circuit._flattened:
            circuit.flatten()
            circuit.init()

        # get device (if any)
        paramunit = None
        # tempFlag indicates if we are doing a global temperature sweep
        tempFlag = False
        if self.device:
            # Device specified, try to find it
            try:
                dev = circuit.elemDict[self.device]
            except KeyError:
                raise analysis.AnalysisError('Could not find: {0}'.format(
                    self.device))
            if self.param:
                try:
                    pinfo = dev.paramDict[self.param]
                except KeyError:
                    raise analysis.AnalysisError('Unrecognized parameter: ' +
                                                 self.param)
                else:
                    if not pinfo[2] == float:
                        raise analysis.AnalysisError(
                            'Parameter must be float: ' + self.param)
            else:
                raise analysis.AnalysisError(
                    "Don't know what parameter to sweep!")
            paramunit = pinfo[1]
        else:
            # No device, check if temperature sweep
            if self.param != 'temp':
                raise analysis.AnalysisError(
                    'Only temperature sweep supported if no device specified')
            paramunit = 'C'
            tempFlag = True

        # Create nodal object: for now assume devices do not change
        # topology during sweep
        nd.make_nodal_circuit(circuit)
        dc = nd.DCNodal(circuit)
        x = dc.get_guess()

        sweepvar = np.linspace(start=self.start, stop=self.stop, num=self.num)
        circuit.dC_sweep = sweepvar
        if tempFlag:
            circuit.dC_var = 'Global temperature sweep: temp'
        else:
            circuit.dC_var = 'Device: ' + dev.instanceName \
                + '  Parameter: ' + self.param
        circuit.dC_unit = paramunit
        print('System dimension: {0}'.format(circuit.nD_dimension))
        print('Sweep: ', circuit.dC_var)

        xVec = np.zeros((circuit.nD_dimension, self.num))
        tIter = 0
        tRes = 0.
        for i, value in enumerate(sweepvar):
            if tempFlag:
                for elem in circuit.nD_elemList:
                    # Only sweep temperature if not explicitly given
                    # for a device
                    if not elem.is_set('temp'):
                        try:
                            elem.set_temp_vars(value)
                        except AttributeError:
                            # It is OK if element independent of temperature
                            pass
            else:
                setattr(dev, self.param, value)
                # re-process parameters (topology must not change, for
                # now at least)
                dev.process_params()
                # Re-generate nodal attributes.
                nd.restore_RCnumbers(dev)
                nd.process_nodal_element(dev, circuit)

            # re-process linear matrix
            dc.refresh()
            sV = dc.get_source()

            # solve equations
            try:
                (x, res, iterations) = solve(x, sV, dc.convergence_helpers)
            except NoConvergenceError as ce:
                print(ce)
                return
            # Save result
            xVec[:, i] = x
            # Keep some info about iterations
            tIter += iterations
            tRes += res
            if self.verbose:
                print('{0} = {1}'.format(self.param, value))
                print('Number of iterations = ', iterations)
                print('Residual = ', res)

        # Calculate average residual and iterations
        avei = tIter / len(sweepvar)
        aver = tRes / len(sweepvar)
        print('Average iterations: {0}'.format(avei))
        print('Average residual: {0}\n'.format(aver))

        # Save results in nodes
        circuit.nD_ref.dC_v = np.zeros(self.num)
        for i, term in enumerate(circuit.nD_termList):
            term.dC_v = xVec[i, :]

        # Restore original attribute values ------------------------
        if tempFlag:
            for elem in circuit.nD_elemList:
                if not elem.is_set('temp'):
                    elem.set_attributes()
                    try:
                        elem.set_temp_vars(value)
                    except AttributeError:
                        # It is OK if element independent of temperature
                        pass
        else:
            dev.set_attributes()
            # re-process parameters (topology must not change, for
            # now at least)
            dev.process_params()
            # Re-generate nodal attributes.
            nd.restore_RCnumbers(dev)
            nd.process_nodal_element(dev, circuit)
        # -----------------------------------------------------------

        # Process output requests.
        analysis.process_requests(
            circuit, 'dc', sweepvar,
            '{0} [{1}]'.format(circuit.dC_var, circuit.dC_unit), 'dC_v')

        def getvec(termname):
            return circuit.find_term(termname).dC_v

        if self.shell:
            analysis.ipython_drop(
                """
Available commands:
    sweepvar: vector with swept parameter
    getvec(<terminal>) to retrieve results
""", globals(), locals())
Esempio n. 2
0
    def run(self, circuit):
        """
        The selected device must be nonlinear. Retrieves the device
        instance from circuit and applies the voltages given by
        port_bias and the combination of sweep_port and
        sweep_val. Then plots currents/charges as a function of swept
        voltage.
        """
        # get device 
        try:
            dev = circuit.elemDict[self.device]
        except KeyError: 
            raise AnalysisError('Could not find: {0}'.format(self.device))
            return

        # Initialize device
        dev.init()

        nports = len(self.ports_bias)
        # Check that parameters make some sense
        if not dev.isNonlinear:
            raise AnalysisError(self.device + ' is linear')
        if nports != len(dev.controlPorts) + dev.nDelays:
            raise AnalysisError('ports_bias for ' + self.device 
                                + ': wrong number of control ports given')
        if self.sweep_num < 1:
            raise AnalysisError('sweep_num = ' + str(self.num)
                                + ': wrong number')
        if self.sweep_port >= nports:
            raise AnalysisError('sweep_port = ' + str(self.port)
                                + ': wrong number (starts from zero)')
        param = False
        paramunit = None
        if self.param:
            try:
                pinfo = dev.paramDict[self.param]
            except KeyError:
                raise AnalysisError('Unrecognized parameter: ' 
                                    + self.param)
            else:
                if not ((pinfo[2] == float) or (pinfo[2] == int)):
                    raise AnalysisError('Parameter must be numeric: ' 
                                        + self.param)
                paramunit = ' ' + pinfo[1]
                param = True
            
        # Print some info about what is being tested
        vports  = np.array(self.ports_bias)
        # Generate operating point info
        if self.useAD:
            dev.get_OP(vports)
        print('******************************************************')
        print('Nonlinear device internal source test analysis')
        print('******************************************************')
        print(dev)
        print('\nPort bias voltages:',  self.ports_bias, 'V')
        print('Inner sweep port:', self.sweep_port, ', start:', 
              self.start, ', stop:', self.stop)

        if param:
            npsweep = len(self.param_val)
            print('Parameter sweep: {0} = {1}'.format(self.param, 
                                                      self.param_val))
        else:
            npsweep = 1
        # Print element variables
        dev.print_vars()

        vsweep = np.linspace(self.start, self.stop, self.sweep_num)
        nsamples = np.shape(vsweep)[0]
        ncurrents = len(dev.csOutPorts)
        iout = None
        if ncurrents: 
            iout = np.zeros((npsweep, nsamples, ncurrents))
        ncharges = len(dev.qsOutPorts)
        qout = None
        if ncharges:
            qout = np.zeros((npsweep, nsamples, ncharges))
        for j in xrange(npsweep):
            if param:
                setattr(dev, self.param, self.param_val[j])
                # re-process parameters
                dev.process_params()
            for i in xrange(np.shape(vsweep)[0]):
                vports[self.sweep_port] = vsweep[i]
                if self.useAD:
                    # Use AD tape to evaluate function
                    outvars = dev.eval(vports)
                else:
                    # The one below is slower as it does not use tapes:
                    outvars = np.concatenate(dev.eval_cqs(vports), axis=0)
                # The function below in addition calculates derivatives
                #(outvars, Jac) = dev.eval_and_deriv(vports)
                # Convert current, charge to vectors
                if ncurrents: 
                    iout[j,i,:] = outvars[0:ncurrents]
                if ncharges:
                    qout[j,i,:] = outvars[ncurrents:]

        # Reset device attributes
        dev.clean_attributes()
        dev.set_attributes()
        # Plot currents and voltages if requested
        if self.plot:
            self.plot_all(vsweep, iout, qout, param, npsweep, paramunit)

        if self.shell:
            ipython_drop('', globals(), locals())
Esempio n. 3
0
    def run(self, circuit):
        """
        Calculates a AC sweep by solving nodal equations around

        The parameter to be swept is specified in the analysis options
        """
        # for now just print some fixed stuff
        print('******************************************************')
        print('                 AC sweep analysis')
        print('******************************************************')
        if hasattr(circuit, 'title'):
            print('\n', circuit.title, '\n')

        # Only works with flattened circuits
        if not circuit._flattened:
            circuit.flatten()
            circuit.init()

        nd.make_nodal_circuit(circuit)
        dc = nd.DCNodal(circuit)
        x0 = dc.get_guess()
        sV = dc.get_source()
        print('System dimension: {0}'.format(circuit.nD_dimension))
        # solve equations
        try: 
            print('Calculating DC operating point ... ', end='')
            sys.stdout.flush()
            (x, res, iterations) = solve(x0, sV, dc.convergence_helpers)
            print('Succeded.\n')
        except NoConvergenceError as ce:
            print('Failed.\n')
            print(ce)
            return
        dc.save_OP(x)

        # Create frequency vector
        if self.log:
            fvec = np.logspace(start = np.log10(self.start), 
                               stop = np.log10(self.stop), 
                               num = self.num)
        else:
            fvec = np.linspace(start = self.start, 
                               stop = self.stop, 
                               num = self.num)

        # Perform analysis
        nd.run_AC(circuit, fvec)

        # Process output requests.  
        analysis.process_requests(circuit, 'ac', 
                                  fvec, 'Frequency [Hz]',
                                  'aC_V', log = self.log)
        analysis.process_requests(circuit, 'ac_mag', 
                                  fvec, 'Frequency [Hz]',
                                  'aC_V', lambda x: abs(x), log = self.log)
        analysis.process_requests(circuit, 'ac_phase', 
                                  fvec, 'Frequency [Hz]',
                                  'aC_V', 
                                  lambda v: 180./np.pi * np.angle(v),
                                  'degrees', self.log)
        analysis.process_requests(circuit, 'ac_dB', 
                                  fvec, 'Frequency [Hz]',
                                  'aC_V', 
                                  lambda v: 20. * np.log10(v),
                                  'dB', self.log)

        def getvec(termname):
            return circuit.termDict[termname].aC_V

        if self.shell:
            analysis.ipython_drop("""
Available commands:
    fvec: frequency vector
    getvec(<terminal>) to retrieve AC result vector
""", globals(), locals())
Esempio n. 4
0
    def run(self, circuit):
        """
        The selected device must be nonlinear. Retrieves the device
        instance from circuit and applies the voltages given by
        port_bias and the combination of sweep_port and
        sweep_val. Then plots currents/charges as a function of swept
        voltage.
        """
        # get device
        try:
            dev = circuit.elemDict[self.device]
        except KeyError:
            raise AnalysisError('Could not find: {0}'.format(self.device))
            return

        # Initialize device
        dev.init()

        nports = len(self.ports_bias)
        # Check that parameters make some sense
        try:
            vports = np.array(self.ports_bias, dtype=float)
        except ValueError:
            raise AnalysisError('ports_bias for ' + self.device +
                                ': some fields are not numeric?')
        if not dev.isNonlinear:
            raise AnalysisError(self.device + ' is linear')
        if nports != len(dev.controlPorts) + dev.nDelays:
            raise AnalysisError('ports_bias for ' + self.device +
                                ': wrong number of control ports given')
        if self.sweep_num < 1:
            raise AnalysisError('sweep_num = ' + str(self.num) +
                                ': wrong number')
        if self.sweep_port >= nports:
            raise AnalysisError('sweep_port = ' + str(self.port) +
                                ': wrong number (starts from zero)')
        param = False
        paramunit = None
        if self.param:
            try:
                pinfo = dev.paramDict[self.param]
            except KeyError:
                raise AnalysisError('Unrecognized parameter: ' + self.param)
            else:
                if not ((pinfo[2] == float) or (pinfo[2] == int)):
                    raise AnalysisError('Parameter must be numeric: ' +
                                        self.param)
                paramunit = ' ' + pinfo[1]
                param = True

        # Print some info about what is being tested
        print('******************************************************')
        print('Nonlinear device internal source test analysis')
        print('******************************************************')
        print(dev)
        print('\nPort bias voltages:', self.ports_bias, 'V')
        print('Inner sweep port:', self.sweep_port, ', start:', self.start,
              ', stop:', self.stop)

        if param:
            npsweep = len(self.param_val)
            print('Parameter sweep: {0} = {1}'.format(self.param,
                                                      self.param_val))
        else:
            npsweep = 1
        # Print element variables
        dev.print_vars()
        # Generate operating point info
        print('\n    Operating point info:\n')
        try:
            # Calculate operating point
            opDict = dev.get_OP(vports)
            # Format operating point information
            for key in sorted(opDict.iterkeys()):
                print('    {0:10} : {1}'.format(key, opDict[key]))
        except AttributeError:
            print('(none)')

        vsweep = np.linspace(self.start, self.stop, self.sweep_num)
        nsamples = np.shape(vsweep)[0]
        ncurrents = len(dev.csOutPorts)
        iout = None
        if ncurrents:
            iout = np.zeros((npsweep, nsamples, ncurrents))
        ncharges = len(dev.qsOutPorts)
        qout = None
        if ncharges:
            qout = np.zeros((npsweep, nsamples, ncharges))
        for j in xrange(npsweep):
            if param:
                setattr(dev, self.param, self.param_val[j])
                # re-process parameters
                dev.process_params()
            for i in xrange(np.shape(vsweep)[0]):
                vports[self.sweep_port] = vsweep[i]
                if self.useAD:
                    # Use AD tape to evaluate function
                    outvars = dev.eval(vports)
                else:
                    # The one below is slower as it does not use tapes:
                    outvars = np.concatenate(dev.eval_cqs(vports), axis=0)
                # The function below in addition calculates derivatives
                #(outvars, Jac) = dev.eval_and_deriv(vports)
                # Convert current, charge to vectors
                if ncurrents:
                    iout[j, i, :] = outvars[0:ncurrents]
                if ncharges:
                    qout[j, i, :] = outvars[ncurrents:]

        # Reset device attributes
        dev.clean_attributes()
        dev.set_attributes()
        # Plot currents and voltages if requested
        if self.plot:
            self.plot_all(vsweep, iout, qout, param, npsweep, paramunit)

        if self.shell:
            ipython_drop('', globals(), locals())
Esempio n. 5
0
    def run(self, circuit):
        """
        Calculates the operating point by solving nodal equations

        The state of all devices is determined by the values of the
        voltages at the controlling ports.
        """
        # for now just print some fixed stuff
        print('******************************************************')
        print('             Operating point analysis')
        print('******************************************************')
        if hasattr(circuit, 'title'):
            print('\n', circuit.title, '\n')

        if glVar.sparse:
            nd = nodalSP
        else:
            nd = nodal
            print('Using dense matrices\n')

        # Only works with flattened circuits
        if not circuit._flattened:
            circuit.flatten()
            circuit.init()

        # Create nodal object
        nd.make_nodal_circuit(circuit)
        dc = nd.DCNodal(circuit)
        x0 = dc.get_guess()
        sV = dc.get_source()
        # solve equations
        try: 
            (x, res, iterations) = solve(x0, sV, dc.convergence_helpers)
        except NoConvergenceError as ce:
            print(ce)
            return
        dc.save_OP(x)

        print('Number of iterations = ', iterations)
        print('Residual = ', res)

        print('\n Node      |  Value               | Unit ')
        print('----------------------------------------')
        for key in sorted(circuit.termDict.iterkeys()):
            term = circuit.termDict[key]
            print('{0:10} | {1:20} | {2}'.format(key, term.nD_vOP, term.unit))

        if self.intvars or self.elemop:
            for elem in circuit.nD_nlinElem:
                print('\nElement: ', elem.instanceName)
                if self.intvars:
                    print('\n    Internal nodal variables:\n')
                    for term in elem.get_internal_terms():
                        print('    {0:10} : {1:20} {2}'.format(
                                term.instanceName, term.nD_vOP, term.unit))
                if self.elemop:
                    print('\n    Operating point info:\n')
                    try:
                        # Calculate operating point
                        opDict = elem.get_OP(elem.nD_xOP)
                        # Format operating point information
                        for key in sorted(opDict.iterkeys()):
                            print('    {0:10} : {1}'.format(key, opDict[key]))
                    except AttributeError:
                        print('    (none)')
        print('\n')

        def getvar(termname):
            return circuit.find_term(termname).nD_vOP

        def getterm(termname):
            return circuit.find_term(termname)

        def getdev(elemname):
            return circuit.elemDict[elemname]

        if self.shell:
            ipython_drop("""
Available commands:
    getvar(<terminal name>) returns variable at <terminal name>
    getterm(<terminal name>) returns terminal reference
    getdev(<device name>) returns device reference
""", globals(), locals())
Esempio n. 6
0
    def run(self, circuit):
        """
        Calculates transient analysis by solving nodal equations
        """
        # for now just print some fixed stuff
        print('******************************************************')
        print('                 Transient analysis')
        print('******************************************************')
        if hasattr(circuit, 'title'):
            print('\n', circuit.title, '\n')

        if glVar.sparse:
            nd = nodalSP
        else:
            nd = nodal
            print('Using dense matrices\n')

        # Only works with flattened circuits
        if not circuit._flattened:
            circuit.flatten()
            circuit.init()

        # Select integration method
        if self.im == 'BE':
            imo = BEuler()
        elif self.im == 'trap':
            imo = Trapezoidal()
        else:
            raise analysis.AnalysisError(
                'Unknown integration method: {0}'.format(self.im))

        # Create nodal objects and solve for initial state
        nd.make_nodal_circuit(circuit)
        dc = nd.DCNodal(circuit)
        tran = nd.TransientNodal(circuit, imo)
        x = dc.get_guess()
        # Use sources including transient values for t == 0
        sV = tran.get_source(0.)
        # solve DC equations
        try: 
            print('Calculating DC operating point ... ', end='')
            sys.stdout.flush()
            (x, res, iterations) = solve(x, sV, dc.convergence_helpers)
            print('Succeded.\n')
        except NoConvergenceError as ce:
            print('Failed.\n')
            print(ce)
            return
        dc.save_OP(x)
        tran.set_IC(self.tstep)
        # Release memory in dc object?
        del(dc)

        # Create time vector
        timeVec = np.arange(start=0., stop = self.tstop, step = self.tstep, 
                            dtype=float)
        nsamples = len(timeVec)
        circuit.tran_timevec = timeVec

        # Get terminals to plot/save from circuit. 
        termSet = circuit.get_requested_terms('tran')

        # Special treatment for ground terminal
        termSet1 = set(termSet)
        if circuit.nD_ref in termSet1:
            termSet1.remove(circuit.nD_ref)
            circuit.nD_ref.tran_v = np.zeros(nsamples)

        # Allocate vectors for results
        if self.saveall:
            for term in circuit.nD_termList:
                term.tran_v = np.empty(nsamples)
                term.tran_v[0] = x[term.nD_namRC]                
            circuit.nD_ref.tran_v = np.zeros(nsamples)
        else:
            # Only save requested nodes
            for term in termSet1:
                term.tran_v = np.empty(nsamples)
                term.tran_v[0] = x[term.nD_namRC]

        # Save initial values
        xOld = x
        tIter = 0
        tRes = 0.
        dots = 50
        print('System dimension: {0}'.format(circuit.nD_dimension))
        print('Number of samples: {0}'.format(nsamples))
        print('Integration method: {0}'.format(self.im))
        if self.verbose:
            print('-------------------------------------------------')
            print(' Step    | Time (s)     | Iter.    | Residual    ')
            print('-------------------------------------------------')
        else:
            print('Printing one dot every {0} samples:'.format(dots))
            sys.stdout.flush()

        for i in xrange(1, nsamples):
            tran.accept(xOld)
            sV = tran.get_rhs(timeVec[i])
            # solve equations: use previous time-step solution as an
            # initial guess
            if i > 1:
                # Re-use factorized Jacobian: This saves the time to
                # evaluate the function and Jacobian plus the time for
                # factorization. Only sparse implementation stores
                # factorized Jacobian
                xOld -= tran.get_chord_deltax(sV)
            try: 
                (x, res, iterations) = solve(xOld, sV, 
                                             tran.convergence_helpers)
            except NoConvergenceError as ce:
                print(ce)
                return

            # Save results
            xOld[:] = x
            if self.saveall:
                for term in circuit.nD_termList:
                    term.tran_v[i] = x[term.nD_namRC]                
            else:
                # Only save requested nodes
                for term in termSet1:
                    term.tran_v[i] = x[term.nD_namRC]
            # Keep some info about iterations
            tIter += iterations
            tRes += res
            if self.verbose:
                print('{0:8} | {1:12} | {2:8} | {3:12}'.format(
                        i, timeVec[i], iterations, res))
            elif not i%dots:
                print('.', end='')
                sys.stdout.flush()

        # Calculate average residual and iterations
        avei = float(tIter) / nsamples
        aver = tRes / nsamples
        print('\nAverage iterations: {0}'.format(avei))
        print('Average residual: {0}\n'.format(aver))

        # Process output requests.  
        analysis.process_requests(circuit, 'tran', 
                                  timeVec, 'Time [s]', 'tran_v')

        def getvec(termname):
            return circuit.find_term(termname).tran_v

        if self.shell:
            analysis.ipython_drop("""
Available commands:
    timeVec: time vector
    getvec(<terminal>) to retrieve results (if result saved)
""", globals(), locals())
Esempio n. 7
0
    def run(self, circuit):
        """
        Calculates transient analysis by solving nodal equations
        """
        # for now just print some fixed stuff
        print('******************************************************')
        print('                 Transient analysis')
        print('******************************************************')
        if hasattr(circuit, 'title'):
            print('\n', circuit.title, '\n')

        if glVar.sparse:
            nd = nodalSP
        else:
            nd = nodal
            print('Using dense matrices\n')

        # Only works with flattened circuits
        if not circuit._flattened:
            circuit.flatten()
            circuit.init()

        # Select integration method
        if self.im == 'BE':
            imo = BEuler()
        elif self.im == 'trap':
            imo = Trapezoidal()
        else:
            raise analysis.AnalysisError(
                'Unknown integration method: {0}'.format(self.im))

        # Create nodal objects and solve for initial state
        nd.make_nodal_circuit(circuit)
        dc = nd.DCNodal(circuit)
        tran = nd.TransientNodal(circuit, imo)
        x = dc.get_guess()
        # Use sources including transient values for t == 0
        sV = tran.get_source(0.)
        # solve DC equations
        try: 
            print('Calculating DC operating point ... ', end='')
            sys.stdout.flush()
            (x, res, iterations) = solve(x, sV, dc.convergence_helpers)
            print('Succeded.\n')
        except NoConvergenceError as ce:
            print('Failed.\n')
            print(ce)
            return
        dc.save_OP(x)
        tran.set_IC(self.tstep)
        # Release memory in dc object?
        del(dc)

        # Create time vector
        timeVec = np.arange(start=0., stop = self.tstop, step = self.tstep, 
                            dtype=float)
        nsamples = len(timeVec)
        circuit.tran_timevec = timeVec

        # Get terminals to plot/save from circuit. 
        termSet = circuit.get_requested_terms('tran')

        # Special treatment for ground terminal
        termSet1 = set(termSet)
        if circuit.nD_ref in termSet1:
            termSet1.remove(circuit.nD_ref)
            circuit.nD_ref.tran_v = np.zeros(nsamples)

        # Allocate vectors for results
        if self.saveall:
            for term in circuit.nD_termList:
                term.tran_v = np.empty(nsamples)
                term.tran_v[0] = x[term.nD_namRC]                
            circuit.nD_ref.tran_v = np.zeros(nsamples)
        else:
            # Only save requested nodes
            for term in termSet1:
                term.tran_v = np.empty(nsamples)
                term.tran_v[0] = x[term.nD_namRC]

        # Save initial values
        xOld = x
        tIter = 0
        tRes = 0.
        dots = 50
        print('System dimension: {0}'.format(circuit.nD_dimension))
        print('Number of samples: {0}'.format(nsamples))
        print('Integration method: {0}'.format(self.im))
        if self.verbose:
            print('-------------------------------------------------')
            print(' Step    | Time (s)     | Iter.    | Residual    ')
            print('-------------------------------------------------')
        else:
            print('Printing one dot every {0} samples:'.format(dots))
            sys.stdout.flush()

        for i in xrange(1, nsamples):
            tran.accept(xOld)
            sV = tran.get_rhs(timeVec[i])
            # solve equations: use previous time-step solution as an
            # initial guess
            if i > 1:
                # Re-use factorized Jacobian: This saves the time to
                # evaluate the function and Jacobian plus the time for
                # factorization. Only sparse implementation stores
                # factorized Jacobian
                xOld += tran.get_chord_deltax(sV)
            try: 
                (x, res, iterations) = solve(xOld, sV, 
                                             tran.convergence_helpers)
            except NoConvergenceError as ce:
                print(ce)
                return

            # Save results
            xOld[:] = x
            if self.saveall:
                for term in circuit.nD_termList:
                    term.tran_v[i] = x[term.nD_namRC]                
            else:
                # Only save requested nodes
                for term in termSet1:
                    term.tran_v[i] = x[term.nD_namRC]
            # Keep some info about iterations
            tIter += iterations
            tRes += res
            if self.verbose:
                print('{0:8} | {1:12} | {2:8} | {3:12}'.format(
                        i, timeVec[i], iterations, res))
            elif not i%dots:
                print('.', end='')
                sys.stdout.flush()

        # Calculate average residual and iterations
        avei = float(tIter) / nsamples
        aver = tRes / nsamples
        print('\nAverage iterations: {0}'.format(avei))
        print('Average residual: {0}\n'.format(aver))

        # Process output requests.  
        analysis.process_requests(circuit, 'tran', 
                                  timeVec, 'Time [s]', 'tran_v')

        def getvec(termname):
            return circuit.find_term(termname).tran_v

        if self.shell:
            analysis.ipython_drop("""
Available commands:
    timeVec: time vector
    getvec(<terminal>) to retrieve results (if result saved)
""", globals(), locals())
Esempio n. 8
0
    def run(self, circuit):
        """
        Calculates a DC sweep by solving nodal equations

        The parameter to be swept is specified in the analysis options
        """
        # for now just print some fixed stuff
        print('******************************************************')
        print('                 DC sweep analysis')
        print('******************************************************')
        if hasattr(circuit, 'title'):
            print('\n', circuit.title, '\n')

        if glVar.sparse:
            nd = nodalSP
        else:
            nd = nodal
            print('Using dense matrices\n')

        # Only works with flattened circuits
        if not circuit._flattened:
            circuit.flatten()
            circuit.init()

        # get device (if any)
        paramunit = None
        # tempFlag indicates if we are doing a global temperature sweep
        tempFlag = False
        if self.device:
            # Device specified, try to find it
            try:
                dev = circuit.elemDict[self.device]
            except KeyError: 
                raise analysis.AnalysisError(
                    'Could not find: {0}'.format(self.device))
            if self.param:
                try:
                    pinfo = dev.paramDict[self.param]
                except KeyError:
                    raise analysis.AnalysisError('Unrecognized parameter: ' 
                                                 + self.param)
                else:
                    if not pinfo[2] == float:
                        raise analysis.AnalysisError(
                            'Parameter must be float: ' + self.param)
            else:
                raise analysis.AnalysisError(
                    "Don't know what parameter to sweep!")
            paramunit = pinfo[1]
        else:
            # No device, check if temperature sweep
            if self.param != 'temp':
                raise analysis.AnalysisError(
                    'Only temperature sweep supported if no device specified')
            paramunit = 'C'
            tempFlag = True

        # Create nodal object: for now assume devices do not change
        # topology during sweep
        nd.make_nodal_circuit(circuit)
        dc = nd.DCNodal(circuit)
        x = dc.get_guess()

        sweepvar = np.linspace(start = self.start, stop = self.stop, 
                               num = self.num)
        circuit.dC_sweep = sweepvar
        if tempFlag:
            circuit.dC_var = 'Global temperature sweep: temp'
        else:
            circuit.dC_var = 'Device: ' + dev.instanceName \
                + '  Parameter: ' + self.param
        circuit.dC_unit = paramunit
        print('System dimension: {0}'.format(circuit.nD_dimension))
        print('Sweep: ', circuit.dC_var)
        
        xVec = np.zeros((circuit.nD_dimension, self.num))
        tIter = 0
        tRes = 0.
        for i, value in enumerate(sweepvar):
            if tempFlag:
                for elem in circuit.nD_elemList:
                    # Only sweep temperature if not explicitly given
                    # for a device
                    if not elem.is_set('temp'):
                        try:
                            elem.set_temp_vars(value)
                        except AttributeError:
                            # It is OK if element independent of temperature
                            pass
            else:
                setattr(dev, self.param, value)
                # re-process parameters (topology must not change, for
                # now at least)
                dev.process_params()
                # Re-generate nodal attributes. 
                nd.restore_RCnumbers(dev)
                nd.process_nodal_element(dev, circuit)

            # re-process linear matrix
            dc.refresh()
            sV = dc.get_source()

            # solve equations
            try: 
                (x, res, iterations) = solve(x, sV, dc.convergence_helpers)
            except NoConvergenceError as ce:
                print(ce)
                return
            # Save result
            xVec[:,i] = x
            # Keep some info about iterations
            tIter += iterations
            tRes += res
            if self.verbose:
                print('{0} = {1}'.format(self.param , value))
                print('Number of iterations = ', iterations)
                print('Residual = ', res)

        # Calculate average residual and iterations
        avei = tIter / len(sweepvar)
        aver = tRes / len(sweepvar)
        print('Average iterations: {0}'.format(avei))
        print('Average residual: {0}\n'.format(aver))

        # Save results in nodes
        circuit.nD_ref.dC_v = np.zeros(self.num)
        for i,term in enumerate(circuit.nD_termList):
            term.dC_v = xVec[i,:]

        # Restore original attribute values ------------------------
        if tempFlag:
            for elem in circuit.nD_elemList:
                if not elem.is_set('temp'):
                    elem.set_attributes()
                    try:
                        elem.set_temp_vars(value)
                    except AttributeError:
                        # It is OK if element independent of temperature
                        pass
        else:
            dev.set_attributes()
            # re-process parameters (topology must not change, for
            # now at least)
            dev.process_params()
            # Re-generate nodal attributes. 
            nd.restore_RCnumbers(dev)
            nd.process_nodal_element(dev, circuit)
        # -----------------------------------------------------------

        # Process output requests.  
        analysis.process_requests(circuit, 'dc', sweepvar, 
                                  '{0} [{1}]'.format(circuit.dC_var, 
                                                     circuit.dC_unit), 
                                  'dC_v')

        def getvec(termname):
            return circuit.find_term(termname).dC_v

        if self.shell:
            analysis.ipython_drop("""
Available commands:
    sweepvar: vector with swept parameter
    getvec(<terminal>) to retrieve results
""", globals(), locals())
Esempio n. 9
0
    def run(self, circuit):
        """
        Calculates a AC sweep by solving nodal equations around

        The parameter to be swept is specified in the analysis options
        """
        # for now just print some fixed stuff
        print('******************************************************')
        print('                 AC sweep analysis')
        print('******************************************************')
        if hasattr(circuit, 'title'):
            print('\n', circuit.title, '\n')

        # Only works with flattened circuits
        if not circuit._flattened:
            circuit.flatten()
            circuit.init()

        nd.make_nodal_circuit(circuit)
        dc = nd.DCNodal(circuit)
        x0 = dc.get_guess()
        sV = dc.get_source()
        print('System dimension: {0}'.format(circuit.nD_dimension))
        # solve equations
        try:
            print('Calculating DC operating point ... ', end='')
            sys.stdout.flush()
            (x, res, iterations) = solve(x0, sV, dc.convergence_helpers)
            print('Succeded.\n')
        except NoConvergenceError as ce:
            print('Failed.\n')
            print(ce)
            return
        dc.save_OP(x)

        # Create frequency vector
        if self.log:
            fvec = np.logspace(start=np.log10(self.start),
                               stop=np.log10(self.stop),
                               num=self.num)
        else:
            fvec = np.linspace(start=self.start, stop=self.stop, num=self.num)

        # Perform analysis
        nd.run_AC(circuit, fvec)

        # Process output requests.
        analysis.process_requests(circuit,
                                  'ac',
                                  fvec,
                                  'Frequency [Hz]',
                                  'aC_V',
                                  log=self.log)
        analysis.process_requests(circuit,
                                  'ac_mag',
                                  fvec,
                                  'Frequency [Hz]',
                                  'aC_V',
                                  lambda x: abs(x),
                                  log=self.log)
        analysis.process_requests(circuit, 'ac_phase', fvec, 'Frequency [Hz]',
                                  'aC_V', lambda v: 180. / np.pi * np.angle(v),
                                  'degrees', self.log)
        analysis.process_requests(circuit, 'ac_dB', fvec, 'Frequency [Hz]',
                                  'aC_V', lambda v: 20. * np.log10(v), 'dB',
                                  self.log)

        def getvec(termname):
            return circuit.find_term(termname).aC_V

        if self.shell:
            analysis.ipython_drop(
                """
Available commands:
    fvec: frequency vector
    getvec(<terminal>) to retrieve AC result vector
""", globals(), locals())