Exemplo n.º 1
0
    def find_vde_index(self, id_wdescr, verbose=3):
        """Finds a voltage defined element MNA index.

        Parameters:
        id_wdescr (string): the element name, eg. 'V1'. Notice it includes
                            both the id ('V') and the description ('1').
        verbose (int): verbosity level, from 0 (silent) to 6 (debug).

        Returns:
        the index (int)
        """
        vde_index = 0
        found = False
        for elem in self:
            if is_elem_voltage_defined(elem):
                if elem.part_id.upper() == id_wdescr.upper():
                    found = True
                    break
                else:
                    vde_index += 1

        if not found:
            printing.print_warning(
                "find_vde_index(): element %s was not found. This is a bug." %
                (id_wdescr, ))
        else:
            printing.print_info_line(
                ("%s found at index %d" % (id_wdescr, vde_index), 6), verbose)
        return vde_index
Exemplo n.º 2
0
def run(circ, an_list=None):
    """ Processes an analysis vector:
    circ: the circuit instance
    an_queue: the list of analyses to be performed, if unset defaults to those queued
              with queue_analysis()

    Returns: the results (in dict form)
    """
    results = {}

    if not an_list:
        an_list = _queue
    else:
        if type(an_list) == tuple:
            an_list = list(an_list)
        elif type(an_list) == dict:
            an_list = [an_list] # run(mycircuit, op1)
        elif type(an_list) == list:
            pass

    while len(an_list):
        an_item = an_list.pop(0)
        an_type = an_item.pop('type')
        if 'x0' in an_item and isinstance(an_item['x0'], str):
            printing.print_warning("%s has x0 set to %s, unavailable. Using 'None'." %
                                   (an_type.upper(), an_item['x0']))
            an_item['x0'] = None
        r = analysis[an_type](circ, **an_item)
        results.update({an_type: r})
        if an_type == 'op':
            _x0s.update({'op': r})
            _x0s.update({'op+ic': icmodified_x0(circ, r)})
            _handle_netlist_ics(circ, an_list, ic_list=[])
    return results
Exemplo n.º 3
0
    def find_vde_index(self, id_wdescr, verbose=3):
        """Finds a voltage defined element MNA index.

        Parameters:
        id_wdescr (string): the element name, eg. 'V1'. Notice it includes
                            both the id ('V') and the description ('1').
        verbose (int): verbosity level, from 0 (silent) to 6 (debug).

        Returns:
        the index (int)
        """
        vde_index = 0
        found = False
        for elem in self:
            if is_elem_voltage_defined(elem):
                if elem.part_id.upper() == id_wdescr.upper():
                    found = True
                    break
                else:
                    vde_index += 1

        if not found:
            printing.print_warning(
                "find_vde_index(): element %s was not found. This is a bug." % (id_wdescr,))
        else:
            printing.print_info_line(
                ("%s found at index %d" % (id_wdescr, vde_index), 6), verbose)
        return vde_index
Exemplo n.º 4
0
def process_postproc(postproc_list, title, results, outfilename, remote=False):
    """Runs the post-processing operations, such as plotting.
	postproc_list: list of post processing operations as returned by main()
	title: the deck title
	results: the results to be plotted (including the ones that are not needed)
	outfilename: if the plots are saved to disk, this is the filename without extension
	remote: boolean, do not show plots if True (such as ssh without X11 forwarding)

	Returns: None
	"""
    index = 0
    if outfilename == 'stdout':
        printing.print_warning(
            "Plotting and printing the results to stdout are incompatible options. Plotting skipped."
        )
        return
    for postproc in postproc_list:
        #print postproc["analysis"], results.keys(), results.has_key(postproc["analysis"]), results[postproc["analysis"]] is None #DEBUG
        plotting.plot_results(
            title, postproc["x"], postproc["l2l1"],
            results[postproc["analysis"]],
            "%s-%d.%s" % (outfilename, index, options.plotting_outtype))
        index = index + 1
    if len(postproc_list) and not remote:
        plotting.show_plots()
    return None
Exemplo n.º 5
0
def check_step_and_points(step, points, period):
    """Sets consistently the step size and the number of points, according to the given period
    Returns: (points, step)
    """
    if step is None and points is None:
        print "Warning: shooting had no step nor n. of points setted. Using", options.shooting_default_points, "points."
        points = options.shooting_default_points
    elif step is not None and points is not None:
        print "Warning: shooting had both step and n. of points setted. Using", step, "step. (NA)"
        points = None

    if points:
        step = (1.0 * period) / (points - 1)
    else:
        points = (1.0 * period) / step
        if points % 1 != 0:
            step = step + (step * (points % 1)) / int(points)
            points = int((1.0 * period) / step)
            printing.print_warning("adapted step is %g" % (step,))
        else:
            points = int(points)
        points = points + \
            1  # 0 - N where xN is in reality the first point of the second period!!

    return (points, step)
Exemplo n.º 6
0
def main(filename,
         outfile="stdout",
         tran_method=transient.TRAP.lower(),
         no_step_control=False,
         dc_guess='guess',
         print_circuit=False,
         remote=True,
         verbose=3):
    """This method allows calling ahkab from a Python script.
	"""
    printing.print_info_line(
        ("This is ahkab %s running with:" % (__version__), 6), verbose)
    printing.print_info_line(
        ("  Python %s" % (sys.version.split('\n')[0], ), 6), verbose)
    printing.print_info_line(("  Numpy %s" % (numpy.__version__), 6), verbose)
    printing.print_info_line(("  Sympy %s" % (sympy.__version__), 6), verbose)
    printing.print_info_line(("  Matplotlib %s" % (matplotlib.__version__), 6),
                             verbose)

    utilities._set_execution_lock()

    read_netlist_from_stdin = (filename is None or filename == "-")
    (circ, directives,
     postproc_direct) = netlist_parser.parse_circuit(filename,
                                                     read_netlist_from_stdin)

    check, reason = dc_analysis.check_circuit(circ)
    if not check:
        printing.print_general_error(reason)
        printing.print_circuit(circ)
        sys.exit(3)

    if verbose > 3 or print_circuit:
        print "Parsed circuit:"
        printing.print_circuit(circ)
    elif verbose > 1:
        print circ.title.upper()

    an_list = netlist_parser.parse_analysis(circ, directives)
    postproc_list = netlist_parser.parse_postproc(circ, an_list,
                                                  postproc_direct)
    if len(an_list) > 0:
        printing.print_info_line(("Requested an.:", 4), verbose)
        if verbose >= 4:
            map(printing.print_analysis, an_list)
    else:
        if verbose:
            printing.print_warning("No analysis requested.")
    if len(an_list) > 0:
        results = process_analysis(an_list, circ, outfile, verbose, guess=dc_guess.lower()=="guess", \
        cli_tran_method=tran_method, disable_step_control=no_step_control)
    else:
        printing.print_warning("Nothing to do. Quitting.")

    if len(an_list) > 0 and len(postproc_list) > 0 and len(results):
        process_postproc(postproc_list, circ.title, results, outfile, remote)

    utilities._unset_execution_lock()

    return results
Exemplo n.º 7
0
def check_step_and_points(step, points, period):
    """Sets consistently the step size and the number of points, according to the given period
    Returns: (points, step)
    """
    if step is None and points is None:
        print "Warning: shooting had no step nor n. of points setted. Using", options.shooting_default_points, "points."
        points = options.shooting_default_points
    elif step is not None and points is not None:
        print "Warning: shooting had both step and n. of points setted. Using", step, "step. (NA)"
        points = None

    if points:
        step = (1.0 * period) / (points - 1)
    else:
        points = (1.0 * period) / step
        if points % 1 != 0:
            step = step + (step * (points % 1)) / int(points)
            points = int((1.0 * period) / step)
            printing.print_warning("adapted step is %g" % (step, ))
        else:
            points = int(points)
        points = points + \
            1  # 0 - N where xN is in reality the first point of the second period!!

    return (points, step)
Exemplo n.º 8
0
def run(circ, an_list=None):
    """ Processes an analysis vector:
    circ: the circuit instance
    an_queue: the list of analyses to be performed, if unset defaults to those queued
              with queue_analysis()

    Returns: the results (in dict form)
    """
    results = {}

    if not an_list:
        an_list = _queue
    else:
        if type(an_list) == tuple:
            an_list = list(an_list)
        elif type(an_list) == dict:
            an_list = [an_list]  # run(mycircuit, op1)
        elif type(an_list) == list:
            pass

    while len(an_list):
        an_item = an_list.pop(0)
        an_type = an_item.pop('type')
        if 'x0' in an_item and isinstance(an_item['x0'], str):
            printing.print_warning(
                "%s has x0 set to %s, unavailable. Using 'None'." %
                (an_type.upper(), an_item['x0']))
            an_item['x0'] = None
        r = analysis[an_type](circ, **an_item)
        results.update({an_type: r})
        if an_type == 'op':
            _x0s.update({'op': r})
            _x0s.update({'op+ic': icmodified_x0(circ, r)})
            _handle_netlist_ics(circ, an_list, ic_list=[])
    return results
Exemplo n.º 9
0
	def add(self, atuple):
		if not len(atuple) == self._width:
			printing.print_warning("Attempted to add a element of wrong size to LIFO buffer. BUG?")
			return False
		else:
			self._the_real_buffer.insert(0, atuple)
			if len(self._the_real_buffer) > self._length:
				self._the_real_buffer = self._the_real_buffer[:self._length]
			return True
Exemplo n.º 10
0
 def add(self, atuple):
     if not len(atuple) == self._width:
         printing.print_warning(
             "Attempted to add a element of wrong size to LIFO buffer. BUG?"
         )
         return False
     else:
         self._the_real_buffer.insert(0, atuple)
         if len(self._the_real_buffer) > self._length:
             self._the_real_buffer = self._the_real_buffer[:self._length]
         return True
Exemplo n.º 11
0
def plot_results(title, y2y1_list, results, outfilename):
    """Plot the results.
    """
    if results is None:
        printing.print_warning("No results available for plotting. Skipping.")
        return
    fig = pylab.figure()
    analysis = results.get_type().upper()
    gdata = []
    x, xlabel = results.get_x(), results.get_xlabel()
    xunit = results.units[xlabel]
    yvu = []

    for y2label, y1label in y2y1_list:
        if y1label is not None and y1label != '':
            data1 = results[y1label]
            line_label = y2label + "-" + y1label
        else:
            line_label = y2label
            data1 = 0
        data2 = results[y2label]
        yvu += [(line_label, results.units[y2label])]
        gdata.append((data2 - data1, line_label))

    if xlabel == 'w':
        xlog = True
    else:
        xlog = False
    setup_plot(fig, title, (xlabel, xunit), yvu, xlog=xlog)

    pylab.hold(True)
    ymax, ymin = None, None
    for y, label in gdata:
        [line] = pylab.plot(x,
                            y,
                            options.plotting_style,
                            label=label + " (" + analysis + ")",
                            mfc='w',
                            lw=options.plotting_lw,
                            mew=options.plotting_lw)
        line.set_mec(line.get_color())  # nice empty circles
        ymax = y.max() if ymax is None or y.max() > ymax else ymax
        ymin = y.min() if ymin is None or y.min() < ymin else ymin
    pylab.xlim((x.min(), x.max()))
    pylab.ylim((ymin - (ymax - ymin) * .01, ymax + (ymax - ymin) * .01))
    pylab.hold(False)
    pylab.legend()

    if outfilename is not None and options.plotting_outtype is not None:
        save_figure(outfilename, fig)
    return
Exemplo n.º 12
0
def plot_results(title, y2y1_list, results, outfilename):
    """Plot the results.
    """
    if results is None:
        printing.print_warning("No results available for plotting. Skipping.")
        return
    fig = pylab.figure()
    analysis = results.get_type().upper()
    gdata = []
    x, xlabel = results.get_x(), results.get_xlabel()
    xunit = results.units[xlabel]
    yvu = []

    for y2label, y1label in y2y1_list:
        if y1label is not None and y1label != '':
            data1 = results[y1label]
            line_label = y2label + "-" + y1label
        else:
            line_label = y2label
            data1 = 0
        data2 = results[y2label]
        yvu += [(line_label, results.units[y2label])]
        gdata.append((data2 - data1, line_label))

    if xlabel == 'w':
        xlog = True
    else:
        xlog = False
    setup_plot(fig, title, (xlabel, xunit), yvu, xlog=xlog)

    pylab.hold(True)
    ymax, ymin = None, None
    for y, label in gdata:
        [line] = pylab.plot(
            x, y, options.plotting_style, label=label +
            " (" + analysis + ")",
            mfc='w', lw=options.plotting_lw, mew=options.plotting_lw)
        line.set_mec(line.get_color())  # nice empty circles
        ymax = y.max() if ymax is None or y.max() > ymax else ymax
        ymin = y.min() if ymin is None or y.min() < ymin else ymin
    pylab.xlim((x.min(), x.max()))
    pylab.ylim((ymin - (ymax - ymin) * .01, ymax + (ymax - ymin) * .01))
    pylab.hold(False)
    pylab.legend()

    if outfilename is not None and options.plotting_outtype is not None:
        save_figure(outfilename, fig)
    return
Exemplo n.º 13
0
Arquivo: ahkab.py Projeto: vovkd/ahkab
def main(filename, outfile="stdout", tran_method=transient.TRAP.lower(), no_step_control=False, dc_guess='guess', print_circuit=False, remote=True, verbose=3):
	"""This method allows calling ahkab from a Python script.
	"""
	printing.print_info_line(("This is ahkab %s running with:" %(__version__),6), verbose)
	printing.print_info_line(("  Python %s" % (sys.version.split('\n')[0],),6), verbose)
	printing.print_info_line(("  Numpy %s"  % (numpy.__version__),6), verbose)
	printing.print_info_line(("  Sympy %s"  % (sympy.__version__),6), verbose)
	printing.print_info_line(("  Matplotlib %s"  % (matplotlib.__version__),6), verbose)

	utilities._set_execution_lock()

	read_netlist_from_stdin = (filename is None or filename == "-")
	(circ, directives, postproc_direct) = netlist_parser.parse_circuit(filename, read_netlist_from_stdin)
	
	check, reason = dc_analysis.check_circuit(circ)
	if not check:
		printing.print_general_error(reason)
		printing.print_circuit(circ)
		sys.exit(3)
	
	if verbose > 3 or print_circuit:
		print "Parsed circuit:"
		printing.print_circuit(circ)
	elif verbose > 1:
		print circ.title.upper()
	
	an_list = netlist_parser.parse_analysis(circ, directives)
	postproc_list = netlist_parser.parse_postproc(circ, an_list, postproc_direct)
	if len(an_list) > 0: 
		printing.print_info_line(("Requested an.:", 4), verbose)
		if verbose >= 4:
			map(printing.print_analysis, an_list)
	else:
		if verbose:
			printing.print_warning("No analysis requested.")
	if len(an_list) > 0:
		results = process_analysis(an_list, circ, outfile, verbose, guess=dc_guess.lower()=="guess", \
		cli_tran_method=tran_method, disable_step_control=no_step_control)
	else:
		printing.print_warning("Nothing to do. Quitting.")

	if len(an_list) > 0 and len(postproc_list) > 0 and len(results):
		process_postproc(postproc_list, circ.title, results, outfile, remote)

	utilities._unset_execution_lock()

	return results
Exemplo n.º 14
0
def plot_results(title, xvarname, y2y1_list, results, outfilename):
    """Plot the results.
	"""
    if results is None:
        printing.print_warning("No results available for plotting. Skipping.")
        return
    fig = pylab.figure()
    analysis = results.get_type().upper()
    xunit = results.units[xvarname]
    gdata = []
    x = results[xvarname]
    yvu = []

    for y2label, y1label in y2y1_list:
        if y1label is not None and y1label != '':
            data1 = results[y1label]
            line_label = y2label + "-" + y1label
        else:
            line_label = y2label
            data1 = 0
        data2 = results[y2label]
        yvu += [(line_label, results.units[y2label])]
        gdata.append((data2 - data1, line_label))

    if xvarname == 'w':
        xlog = True
    else:
        xlog = False
    setup_plot(fig, title, (xvarname, xunit), yvu, xlog=xlog)

    pylab.hold(True)
    for y, label in gdata:
        # pylab wants matrices in the form: N,1, while results come as (1, N) -> Transpose
        pylab.plot(
            x.T,
            y.T,
            options.plotting_style,
            label=label + " (" + analysis + ")",
        )
    pylab.xlim((x.min(), x.max()))
    pylab.hold(False)
    pylab.legend()

    if outfilename is not None and options.plotting_outtype is not None:
        save_figure(outfilename, fig)
    return
Exemplo n.º 15
0
def check_ground_paths(mna, circ, reduced_mna=True, verbose=3):
    """Checks that every node has a DC path to ground, wheather through
    nonlinear or linear elements.
    - This does not ensure that the circuit will have a DC solution.
    - A node without DC path to ground would be rescued (likely) by GMIN
      so (for the time being at least) we do *not* halt the execution.
    - Also, two series capacitors always fail this check (GMIN saves us)

    Bottom line: if there is no DC path to ground, there is probably a
    mistake in the netlist. Print a warning.
    """
    test_passed = True
    if reduced_mna:
        # reduced_correction
        r_c = 1
    else:
        r_c = 0
    to_be_checked_for_nonlinear_paths = []
    for node in circ.nodes_dict.iterkeys():
        if node == 0:
            continue
            # ground
        if mna[node - r_c,
               node - r_c] == 0 and not mna[node - r_c,
                                            len(circ.nodes_dict) - r_c:].any():
            to_be_checked_for_nonlinear_paths.append(node)
    for node in to_be_checked_for_nonlinear_paths:
        node_is_nl_op = False
        for elem in circ:
            if not elem.is_nonlinear:
                continue
            ops = elem.get_output_ports()
            for op in ops:
                if op.count(node):
                    node_is_nl_op = True
        if not node_is_nl_op:
            if verbose:
                printing.print_warning("No path to ground from node " +
                                       circ.nodes_dict[node])
            test_passed = False
    return test_passed
Exemplo n.º 16
0
def plot_results(title, xvarname, y2y1_list, results, outfilename):
    """Plot the results.
	"""
    if results is None:
        printing.print_warning("No results available for plotting. Skipping.")
        return
    fig = pylab.figure()
    analysis = results.get_type().upper()
    xunit = results.units[xvarname]
    gdata = []
    x = results[xvarname]
    yvu = []

    for y2label, y1label in y2y1_list:
        if y1label is not None and y1label != "":
            data1 = results[y1label]
            line_label = y2label + "-" + y1label
        else:
            line_label = y2label
            data1 = 0
        data2 = results[y2label]
        yvu += [(line_label, results.units[y2label])]
        gdata.append((data2 - data1, line_label))

    if xvarname == "w":
        xlog = True
    else:
        xlog = False
    setup_plot(fig, title, (xvarname, xunit), yvu, xlog=xlog)

    pylab.hold(True)
    for y, label in gdata:
        # pylab wants matrices in the form: N,1, while results come as (1, N) -> Transpose
        pylab.plot(x.T, y.T, options.plotting_style, label=label + " (" + analysis + ")")
    pylab.xlim((x.min(), x.max()))
    pylab.hold(False)
    pylab.legend()

    if outfilename is not None and options.plotting_outtype is not None:
        save_figure(outfilename, fig)
    return
Exemplo n.º 17
0
def process_postproc(postproc_list, title, results, outfilename):
    """Runs the post-processing operations, such as plotting.
    postproc_list: list of post processing operations as returned by main()
    title: the deck title
    results: the results to be plotted (including the ones that are not needed)
    outfilename: if the plots are saved to disk, this is the filename without extension

    Returns: None
    """
    index = 0
    if outfilename == 'stdout':
        printing.print_warning(
            "Plotting and printing the results to stdout are incompatible options. Plotting skipped.")
        return
    for postproc in postproc_list:
        plotting.plot_results(title, postproc["l2l1"], results[
                              postproc["analysis"]], "%s-%d.%s" % (outfilename, index, options.plotting_outtype))
        index = index + 1
    if len(postproc_list) and options.plotting_show_plots:
        plotting.show_plots()
    return None
Exemplo n.º 18
0
Arquivo: ahkab.py Projeto: vovkd/ahkab
def process_postproc(postproc_list, title, results, outfilename, remote=False):
	"""Runs the post-processing operations, such as plotting.
	postproc_list: list of post processing operations as returned by main()
	title: the deck title
	results: the results to be plotted (including the ones that are not needed)
	outfilename: if the plots are saved to disk, this is the filename without extension
	remote: boolean, do not show plots if True (such as ssh without X11 forwarding)

	Returns: None
	"""
	index = 0
	if outfilename == 'stdout':
		printing.print_warning("Plotting and printing the results to stdout are incompatible options. Plotting skipped.")
		return
	for postproc in postproc_list:
		#print postproc["analysis"], results.keys(), results.has_key(postproc["analysis"]), results[postproc["analysis"]] is None #DEBUG
		plotting.plot_results(title, postproc["x"], postproc["l2l1"], results[postproc["analysis"]], "%s-%d.%s" % (outfilename, index, options.plotting_outtype))
		index = index +1
	if len(postproc_list) and not remote:
		plotting.show_plots()
	return None
Exemplo n.º 19
0
def process_postproc(postproc_list, title, results, outfilename):
    """Runs the post-processing operations, such as plotting.
    postproc_list: list of post processing operations as returned by main()
    title: the deck title
    results: the results to be plotted (including the ones that are not needed)
    outfilename: if the plots are saved to disk, this is the filename without extension

    Returns: None
    """
    index = 0
    if outfilename == 'stdout':
        printing.print_warning(
            "Plotting and printing the results to stdout are incompatible options. Plotting skipped."
        )
        return
    for postproc in postproc_list:
        plotting.plot_results(
            title, postproc["l2l1"], results[postproc["analysis"]],
            "%s-%d.%s" % (outfilename, index, options.plotting_outtype))
        index = index + 1
    if len(postproc_list) and options.plotting_show_plots:
        plotting.show_plots()
    return None
Exemplo n.º 20
0
def check_ground_paths(mna, circ, reduced_mna=True):
    """Checks that every node has a DC path to ground, wheather through
	nonlinear or linear elements.
	- This does not ensure that the circuit will have a DC solution.
	- A node without DC path to ground would be rescued (likely) by GMIN
	  so (for the time being at least) we do *not* halt the execution.
	- Also, two series capacitors always fail this check (GMIN saves us)

	Bottom line: if there is no DC path to ground, there is probably a 
	mistake in the netlist. Print a warning.
	"""
    test_passed = True
    if reduced_mna:
        # reduced_correction
        r_c = 1
    else:
        r_c = 0
    to_be_checked_for_nonlinear_paths = []
    for node in circ.nodes_dict.iterkeys():
        if node == 0:
            continue
            # ground
        if mna[node - r_c, node - r_c] == 0 and not mna[node - r_c, len(circ.nodes_dict) - r_c :].any():
            to_be_checked_for_nonlinear_paths.append(node)
    for node in to_be_checked_for_nonlinear_paths:
        node_is_nl_op = False
        for elem in circ.elements:
            if not elem.is_nonlinear:
                continue
            ops = elem.get_output_ports()
            for op in ops:
                if op.count(node):
                    node_is_nl_op = True
        if not node_is_nl_op:
            printing.print_warning("No path to ground from node " + circ.nodes_dict[node])
            test_passed = False
    return test_passed
Exemplo n.º 21
0
def generate_mna_and_N(circ, opts, ac=False):
	"""Generates a symbolic Modified Nodal Analysis matrix and N vector.
	"""
	#print options
	n_of_nodes = len(circ.nodes_dict)
	mna = smzeros(n_of_nodes)
	N = smzeros((n_of_nodes, 1))
	s = sympy.Symbol("s", complex=True)
	subs_g = {}
	#process_elements() 	
	for elem in circ.elements:
		#if elem.is_nonlinear and not (isinstance(elem, mosq.mosq_device) or isinstance(elem, ekv.ekv_device)): 
		#	print "Skipped elem "+elem.letter_id.upper()+elem.descr + ": not implemented."	
		#	continue
		if isinstance(elem, devices.resistor):
			# we use conductances instead of 1/R because there is a significant
			# overhead handling many 1/R terms in sympy.
			if elem.is_symbolic:
				R = sympy.Symbol(elem.letter_id.upper()+elem.descr, real=True)
				G = sympy.Symbol("G"+elem.descr, real=True)
				# but we keep track of which is which and substitute back after solving.
				subs_g.update({G:1/R})
			else:
				R = elem.R
				G = 1.0/R
			#mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1/R
			#mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1/R
			#mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1/R
			#mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1/R
			mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + G
			mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - G
			mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - G
			mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + G
		elif isinstance(elem, devices.capacitor):
			if ac:
				if elem.is_symbolic:
					capa = sympy.Symbol(elem.letter_id.upper()+elem.descr, real=True)
				else:
					capa = elem.C
				mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + s*capa
				mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - s*capa
				mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + s*capa
				mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - s*capa
			else:
				pass
		elif isinstance(elem, devices.inductor):
			pass
		elif isinstance(elem, devices.gisource):
			if elem.is_symbolic:
				alpha = sympy.Symbol(elem.letter_id+elem.descr, real=True)
			else:
				alpha = elem.alpha
			mna[elem.n1, elem.sn1] = mna[elem.n1, elem.sn1] + alpha
			mna[elem.n1, elem.sn2] = mna[elem.n1, elem.sn2] - alpha
			mna[elem.n2, elem.sn1] = mna[elem.n2, elem.sn1] - alpha
			mna[elem.n2, elem.sn2] = mna[elem.n2, elem.sn2] + alpha
		elif isinstance(elem, devices.isource):
			if elem.is_symbolic:
				IDC = sympy.Symbol(elem.letter_id.upper()+elem.descr, real=True)
			else:
				IDC = elem.idc
			N[elem.n1, 0] = N[elem.n1, 0] + IDC
			N[elem.n2, 0] = N[elem.n2, 0] - IDC
		elif isinstance(elem, mosq.mosq_device) or isinstance(elem, ekv.ekv_device):
			gm = sympy.Symbol('gm_'+elem.letter_id+elem.descr, real=True)
			mna[elem.n1, elem.ng] = mna[elem.n1, elem.ng] + gm
			mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gm
			mna[elem.n2, elem.ng] = mna[elem.n2, elem.ng] - gm
			mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gm
			if opts['r0s']:
				r0 = sympy.Symbol('r0_'+elem.letter_id+elem.descr, real=True)
				mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1/r0
				mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1/r0
				mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1/r0
				mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1/r0
		elif isinstance(elem, diode.diode):
			gd = sympy.Symbol("g"+elem.letter_id+elem.descr)
			mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + gd
			mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gd
			mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - gd
			mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gd
		elif isinstance(elem, devices.inductor_coupling):
			pass
			# this is taken care of within the inductors
		elif circuit.is_elem_voltage_defined(elem):
			pass
			#we'll add its lines afterwards
		else:
			printing.print_warning("Skipped elem %s: not implemented." % (elem.letter_id.upper()+elem.descr,))

	pre_vde = mna.shape[0]
	for elem in circ.elements:
		if circuit.is_elem_voltage_defined(elem):
			index = mna.shape[0] #get_matrix_size(mna)[0]
			mna = expand_matrix(mna, add_a_row=True, add_a_col=True)
			N = expand_matrix(N, add_a_row=True, add_a_col=False)
			# KCL
			mna[elem.n1, index] = +1
			mna[elem.n2, index] = -1
			# KVL
			mna[index, elem.n1] = +1
			mna[index, elem.n2] = -1
			if isinstance(elem, devices.vsource):
				if elem.is_symbolic:
					VDC = sympy.Symbol(elem.letter_id.upper() + elem.descr, real=True)
				else:
					VDC = elem.vdc
				N[index, 0] = -VDC
			elif isinstance(elem, devices.evsource):
				if elem.is_symbolic:
					alpha = sympy.Symbol(elem.letter_id.upper() + elem.descr, real=True)
				else:
					alpha = elem.alpha
				mna[index, elem.sn1] = -alpha
				mna[index, elem.sn2] = +alpha
			elif isinstance(elem, devices.inductor):
				if ac:
					if elem.is_symbolic:
						L = sympy.Symbol(elem.letter_id.upper() + elem.descr, real=True)
					else:
						L = elem.L
					mna[index, index] = -s*L
				else: 
					pass
					# already so: commented out				
					# N[index,0] = 0
			elif isinstance(elem, devices.hvsource):
				printing.print_warning("symbolic.py: BUG - hvsources are not implemented yet.")
				sys.exit(33)
	
	for elem in circ.elements:
		if circuit.is_elem_voltage_defined(elem):
			if isinstance(elem, devices.inductor):
				if ac:
					# find its index to know which column corresponds to its current
					this_index = circ.find_vde_index("L"+elem.descr, verbose=0)
					for cd in elem.coupling_devices:
						if cd.is_symbolic:
							M = sympy.Symbol("M" + cd.descr, real=True)
						else:
							M = cd.K
						# get id+descr of the other inductor (eg. "L32")
						other_id_wdescr = cd.get_other_inductor("L"+elem.descr)
						# find its index to know which column corresponds to its current
						other_index = circ.find_vde_index(other_id_wdescr, verbose=0)
						# add the term.
						#print "other_index: "+str(other_index)
						#print "this_index: "+str(this_index)
						mna[pre_vde+this_index,pre_vde+other_index] += -s*M
						#print mna
				else: 
					pass
					# already so: commented out				
					# N[index,0] = 0
			
	
	#all done
	return (mna, N, subs_g)
Exemplo n.º 22
0
def mdn_solver(x,
               mna,
               circ,
               T,
               MAXIT,
               nv,
               locked_nodes,
               time=None,
               print_steps=False,
               vector_norm=lambda v: max(abs(v)),
               debug=True):
    """
    Solves a problem like F(x) = 0 using the Newton Algorithm with a variable damping td.

    Where:

    F(x) = mna*x + T + T(x)
    mna is the Modified Network Analysis matrix of the circuit
    T(x) is the contribute of nonlinear elements to KCL
    T -> independent sources, time invariant and invariant

    x is the initial guess.

    Every x is given by:
    x = x + td*dx
    Where td is a damping coefficient to avoid overflow in non-linear components and
    excessive oscillation in the very first iteration. Afterwards td=1
    To calculate td, an array of locked nodes is needed.

    The convergence check is done this way:
    if (vector_norm(dx) < alpha*vector_norm(x) + beta) and (vector_norm(residuo) < alpha*vector_norm(x) + beta):
    beta should be the machine precision, alpha 1e-(N+1) where N is the number of the significative
    digits you wish to have.

    Parameters:
    x: the initial guess. If set to None, it will be initialized to all zeros. Specifying a initial guess
    may improve the convergence time of the algorithm and determine which solution (if any)
    is found if there are more than one.
    mna: the Modified Network Analysis matrix of the circuit, reduced, see above
    element_list:
    T: see above.
    MAXIT: Maximum iterations that the method may perform.
    nv: number of nodes in the circuit (counting the ref, 0)
    locked_nodes: see get_td() and dc_solve(), generated by circ.get_locked_nodes()
    time: the value of time to be passed to non_linear _and_ time variant elements.
    print_steps: show a progress indicator
    vector_norm:

    Returns a tuple with:
    the solution,
    the remaining error,
    a boolean that is true whenever the method exits because of a successful convergence check
    the number of NR iterations performed

    """
    # OLD COMMENT: FIXME REWRITE: solve through newton
    # problem is F(x)= mna*x +H(x) = 0
    # H(x) = N + T(x)
    # lets say: J = dF/dx = mna + dT(x)/dx
    # J*dx = -1*(mna*x+N+T(x))
    # dT/dx � lo jacobiano -> g_eq (o gm)
    # print_steps = False
    # locked_nodes = get_locked_nodes(element_list)
    mna_size = mna.shape[0]
    nonlinear_circuit = circ.is_nonlinear()
    tick = ticker.ticker(increments_for_step=1)
    tick.display(print_steps)
    if x is None:
        x = numpy.mat(numpy.zeros((mna_size, 1)))
        # if no guess was specified, its all zeros
    else:
        if not x.shape[0] == mna_size:
            raise Exception, "x0s size is different from expected: " + \
                str(x.shape[0]) + " " + str(mna_size)
    if T is None:
        printing.print_warning(
            "dc_analysis.mdn_solver called with T==None, setting T=0. BUG or no sources in circuit?"
        )
        T = numpy.mat(numpy.zeros((mna_size, 1)))

    converged = False
    iteration = 0L
    while iteration < MAXIT:  # newton iteration counter
        iteration += 1
        tick.step(print_steps)
        if nonlinear_circuit:
            # build dT(x)/dx (stored in J) and Tx(x)
            J, Tx = build_J_and_Tx(x, mna_size, circ, time)
            J = J + mna
        else:
            J = mna
            Tx = 0
        residuo = mna * x + T + Tx
        dx = numpy.linalg.inv(J) * (-1 * residuo)
        x = x + get_td(dx, locked_nodes, n=iteration) * dx
        if not nonlinear_circuit:
            converged = True
            break
        elif convergence_check(x, dx, residuo, nv - 1)[0]:
            converged = True
            break
        # if vector_norm(dx) == numpy.nan: #Overflow
        #   raise OverflowError
    tick.hide(print_steps)
    if debug and not converged:
        # re-run the convergence check, only this time get the results
        # by node, so we can show to the users which nodes are misbehaving.
        converged, convergence_by_node = convergence_check(x,
                                                           dx,
                                                           residuo,
                                                           nv - 1,
                                                           debug=True)
    else:
        convergence_by_node = []
    return (x, residuo, converged, iteration, convergence_by_node)
Exemplo n.º 23
0
def process_analysis(an_list,
                     circ,
                     outfile,
                     verbose,
                     cli_tran_method=None,
                     guess=True,
                     disable_step_control=False):
    """ Processes an analysis vector:
	an_list: the list of analysis to be performed, as returned by netlist_parser
	circ: the circuit instance, returned by netlist_parser
	outfile: a filename. Results will be written to it. If set to stdout, prints to stdout
	verbose: verbosity level
	cli_tran_method: force the specified method in each tran analysis (see transient.py)
	guess: use the builtin method get_dc_guess to guess x0
	
	Returns: None
	"""
    x0_op = None
    x0_ic_dict = {}
    results = {}

    for directive in [x for x in an_list if x["type"] == "ic"]:
        x0_ic_dict.update({
         directive["name"]:\
         dc_analysis.build_x0_from_user_supplied_ic(circ, voltages_dict=directive["vdict"], currents_dict=directive["cdict"])
         })

    for an in an_list:
        if outfile != 'stdout':
            data_filename = outfile + "." + an["type"]
        else:
            data_filename = outfile

        if an["type"] == "ic":
            continue

        if an["type"] == "op":
            if not an.has_key('guess_label') or an["guess_label"] is None:
                x0_op = dc_analysis.op_analysis(circ,
                                                guess=guess,
                                                data_filename=data_filename,
                                                verbose=verbose)
            else:
                if not an["guess_label"] in x0_ic_dict:
                    printing.print_warning(
                        "op: guess is set but no matching .ic directive was found."
                    )
                    printing.print_warning(
                        "op: using built-in guess method: " + str(guess))
                    x0_op = dc_analysis.op_analysis(circ,
                                                    guess=guess,
                                                    verbose=verbose)
                else:
                    x0_op = dc_analysis.op_analysis(
                        circ,
                        guess=False,
                        x0=x0_ic_dict[an["guess_label"]],
                        verbose=verbose)
            sol = x0_op

        elif an["type"] == "dc":
            if an["source_name"][0].lower() == "v":
                elem_type = "vsource"
            elif an["source_name"][0].lower() == "i":
                elem_type = "isource"
            else:
                printing.print_general_error(
                    "Type of sweep source is unknown: " + an[1][0])
                sys.exit(1)
            sol = dc_analysis.dc_analysis(
              circ, start=an["start"], stop=an["stop"], step=an["step"], \
              type_descr=(elem_type, an["source_name"][1:]),
              xguess=x0_op, data_filename=data_filename, guess=guess,
              stype=an['stype'], verbose=verbose)

        #{"type":"tran", "tstart":tstart, "tstop":tstop, "tstep":tstep, "uic":uic, "method":method, "ic_label":ic_label}
        elif an["type"] == "tran":
            if cli_tran_method is not None:
                tran_method = cli_tran_method.upper()
            elif an["method"] is not None:
                tran_method = an["method"].upper()
            else:
                tran_method = options.default_tran_method

            # setup the initial condition (t=0) according to uic
            # uic = 0 -> all node voltages and currents are zero
            # uic = 1 -> node voltages and currents are those computed in the last OP analysis
            # uic = 2 -> node voltages and currents are those computed in the last OP analysis
            #            combined with the ic=XX directive found in capacitors and inductors
            # uic = 3 -> use a .ic directive defined by the user
            uic = an["uic"]
            if uic == 0:
                x0 = None
            elif uic == 1:
                if x0_op is None:
                    printing.print_general_error(
                        "uic is set to 1, but no op has been calculated yet.")
                    sys.exit(51)
                x0 = x0_op
            elif uic == 2:
                if x0_op is None:
                    printing.print_general_error(
                        "uic is set to 2, but no op has been calculated yet.")
                    sys.exit(51)
                x0 = dc_analysis.modify_x0_for_ic(circ, x0_op)
            elif uic == 3:
                if an["ic_label"] is None:
                    printing.print_general_error(
                        "uic is set to 3, but param ic=<ic_label> was not defined."
                    )
                    sys.exit(53)
                elif not an["ic_label"] in x0_ic_dict:
                    printing.print_general_error("uic is set to 3, but no .ic directive named %s was found." \
                     %(str(an["ic_label"]),))
                    sys.exit(54)
                x0 = x0_ic_dict[an["ic_label"]]

            sol = transient.transient_analysis(circ, \
             tstart=an["tstart"], tstep=an["tstep"], tstop=an["tstop"], \
             x0=x0, mna=None, N=None, verbose=verbose, data_filename=data_filename, \
             use_step_control=(not disable_step_control), method=tran_method)

        elif an["type"] == "shooting":
            if an["method"] == "brute-force":
                sol = bfpss.bfpss(circ, period=an["period"], step=an["step"], mna=None, Tf=None, \
                 D=None, points=an["points"], autonomous=an["autonomous"], x0=x0_op, \
                 data_filename=data_filename, verbose=verbose)
            elif an["method"] == "shooting":
                sol = shooting.shooting(circ, period=an["period"], step=an["step"], mna=None, \
                 Tf=None, D=None, points=an["points"], autonomous=an["autonomous"], \
                 data_filename=data_filename, verbose=verbose)
        elif an["type"] == "symbolic":
            if not 'subs' in an.keys():
                an.update({'subs': None})
            sol = symbolic.solve(circ,
                                 an['source'],
                                 opts={'ac': an['ac']},
                                 subs=an['subs'],
                                 verbose=verbose)
        elif an["type"] == "ac":
            sol = ac.ac_analysis(circ=circ, start=an['start'], nsteps=an['nsteps'], \
             stop=an['stop'], step_type='LOG', xop=x0_op, mna=None,\
                    data_filename=data_filename, verbose=verbose)
        elif an["type"] == "temp":
            constants.T = utilities.Celsius2Kelvin(an['temp'])
        results.update({an["type"]: sol})
    return results
Exemplo n.º 24
0
def solve(circ, tf_source=None, subs=None, opts=None, verbose=3):
	"""Attempt a symbolic solution of the circuit.
	circ: the circuit instance to be simulated.
	tf_source: the name (string) of the source to be used as input for the transfer
		   function. If None, no transfer function is evaluated.
	subs: a dictionary of sympy Symbols to be substituted. It makes solving the circuit 
	      easier. Eg. {R1:R2} - replace R1 with R2. It can be generated with 
	      parse_substitutions()
	opts: dict of 'option':boolean to be taken into account in simulation.
	      currently 'r0s' and 'ac' are the only options considered.
	verbose: verbosity level 0 (silent) to 6 (painful).
	
	Returns: a dictionary with the solutions.
	"""
	if opts is None:
		# load the defaults
		opts = {'r0s':True, 'ac':False}
	if not 'r0s' in opts.keys():
		opts.update({'r0s':True})
	if not 'ac' in opts.keys():
		opts.update({'ac':False})
	if subs is None:
		subs = {} # no subs by default

	if not opts['ac']:
		printing.print_info_line(("Starting symbolic DC...", 1), verbose)
	else:
		printing.print_info_line(("Starting symbolic AC...", 1), verbose)		
		
	printing.print_info_line(("Building symbolic MNA, N and x...", 2), verbose, print_nl=False)
	mna, N, subs_g = generate_mna_and_N(circ, opts, opts['ac'])
	x = get_variables(circ)
	mna = mna[1:, 1:]
	N = N[1:, :]
	printing.print_info_line((" done.", 2), verbose)	

	printing.print_info_line(("Performing variable substitutions...", 5), verbose)
	mna, N = apply_substitutions(mna, N, subs)

	printing.print_info_line(("MNA matrix (reduced):", 5), verbose)	
	if verbose > 5:	print sympy.sstr(mna)
	printing.print_info_line(("N matrix (reduced):", 5), verbose)	
	if verbose > 5:	print sympy.sstr(N)

	printing.print_info_line(("Building equations...", 2), verbose)	
	eq = []
	for i in to_real_list(mna * x + N):
		eq.append(sympy.Eq(i, 0))

	x = to_real_list(x)
	if verbose > 4:
		printing.print_symbolic_equations(eq)
		print "To be solved for:"
		print x
		#print "Matrix is singular: ", (mna.det() == 0)
	#print -1.0*mna.inv()*N #too heavy
	#print sympy.solve_linear_system(mna.row_join(-N), x)
	printing.print_info_line(("Performing auxiliary simplification...", 2), verbose)	
	eq, x, sol_h = help_the_solver(eq, x)
		
	if len(eq):
		if verbose > 3:
			print "Symplified sytem:"
			printing.print_symbolic_equations(eq)
			print "To be solved for:"
			print x
			printing.print_info_line(("Solving...", 2), verbose)	

		if options.symb_internal_solver:
			sol = local_solve(eq, x)
		else:
			sol = sympy.solve(eq, x, manual=options.symb_sympy_manual_solver, simplify=True)
		if sol is not None:		
			sol.update(sol_h)
		else:
			sol = sol_h
	else:
		printing.print_info_line(("Auxiliary simplification solved the problem.", 3), verbose)	
		sol = sol_h

	for ks in sol.keys():
		sol.update({ks:sol[ks].subs(subs_g)})

	#sol = sol_to_dict(sol, x)

	if sol == {}:
		printing.print_warning("No solutions. Check the netlist.")
	else:
		printing.print_info_line(("Success!", 2), verbose)	
		if verbose > 1:
			print "Results:"
		printing.print_symbolic_results(sol)

	if tf_source is not None:
		src = sympy.Symbol(tf_source.upper(), real=True)
		printing.print_info_line(("Calculating small-signal symbolic transfer functions (%s))..."%(str(src),), 2), verbose, print_nl=False)
		tfs = calculate_gains(sol, src)
		printing.print_info_line(("done.", 2), verbose)	
		printing.print_info_line(("Small-signal symbolic transfer functions:", 1), verbose)	
		printing.print_symbolic_transfer_functions(tfs)
	else:
		tfs = None
	
	return sol, tfs
Exemplo n.º 25
0
def set_temperature(T):
    T = float(T)
    if T > 300:
        printing.print_warning(u"The temperature will be set to %f \xB0 C.")
    constants.T = utilities.Celsius2Kelvin(T)
Exemplo n.º 26
0
Arquivo: ahkab.py Projeto: vovkd/ahkab
def process_analysis(an_list, circ, outfile, verbose, cli_tran_method=None, guess=True, disable_step_control=False):
	""" Processes an analysis vector:
	an_list: the list of analysis to be performed, as returned by netlist_parser
	circ: the circuit instance, returned by netlist_parser
	outfile: a filename. Results will be written to it. If set to stdout, prints to stdout
	verbose: verbosity level
	cli_tran_method: force the specified method in each tran analysis (see transient.py)
	guess: use the builtin method get_dc_guess to guess x0
	
	Returns: None
	"""
	x0_op = None
	x0_ic_dict = {}
	results = {}

	for directive in [ x for x in an_list if x["type"] == "ic" ]:
		x0_ic_dict.update({
			directive["name"]:\
			dc_analysis.build_x0_from_user_supplied_ic(circ, voltages_dict=directive["vdict"], currents_dict=directive["cdict"])
			})
	
	for an in an_list:
		if outfile != 'stdout':
			data_filename = outfile + "." + an["type"]
		else:
			data_filename = outfile

		if an["type"] == "ic":
			continue

		if an["type"] == "op":
			if not an.has_key('guess_label') or an["guess_label"] is None:
				x0_op = dc_analysis.op_analysis(circ, guess=guess, data_filename=data_filename, verbose=verbose)
			else:
				if not an["guess_label"] in x0_ic_dict:
					printing.print_warning("op: guess is set but no matching .ic directive was found.")
					printing.print_warning("op: using built-in guess method: "+str(guess))
					x0_op = dc_analysis.op_analysis(circ, guess=guess, verbose=verbose)
				else:
					x0_op = dc_analysis.op_analysis(circ, guess=False, x0=x0_ic_dict[an["guess_label"]], verbose=verbose)
			sol = x0_op
		
		elif an["type"] == "dc":
			if an["source_name"][0].lower() == "v":
				elem_type = "vsource"
			elif an["source_name"][0].lower() == "i":
				elem_type = "isource"
			else:
				printing.print_general_error("Type of sweep source is unknown: " + an[1][0])
				sys.exit(1)
			sol = dc_analysis.dc_analysis(
					circ, start=an["start"], stop=an["stop"], step=an["step"], \
					type_descr=(elem_type, an["source_name"][1:]), 
					xguess=x0_op, data_filename=data_filename, guess=guess, 
					stype=an['stype'], verbose=verbose)
			
		
		#{"type":"tran", "tstart":tstart, "tstop":tstop, "tstep":tstep, "uic":uic, "method":method, "ic_label":ic_label}
		elif an["type"] == "tran":
			if cli_tran_method is not None:
				tran_method = cli_tran_method.upper()
			elif an["method"] is not None:
				tran_method = an["method"].upper()
			else:
				tran_method = options.default_tran_method
			
			# setup the initial condition (t=0) according to uic
			# uic = 0 -> all node voltages and currents are zero
			# uic = 1 -> node voltages and currents are those computed in the last OP analysis
			# uic = 2 -> node voltages and currents are those computed in the last OP analysis
			#            combined with the ic=XX directive found in capacitors and inductors
			# uic = 3 -> use a .ic directive defined by the user
			uic = an["uic"]
			if uic == 0:
				x0 = None
			elif uic == 1:
				if x0_op is None:
					printing.print_general_error("uic is set to 1, but no op has been calculated yet.")
					sys.exit(51)
				x0 = x0_op
			elif uic == 2:
				if x0_op is None:
					printing.print_general_error("uic is set to 2, but no op has been calculated yet.")
					sys.exit(51)
				x0 = dc_analysis.modify_x0_for_ic(circ, x0_op)
			elif uic == 3:
				if an["ic_label"] is None:
					printing.print_general_error("uic is set to 3, but param ic=<ic_label> was not defined.")
					sys.exit(53)
				elif not an["ic_label"] in x0_ic_dict:
					printing.print_general_error("uic is set to 3, but no .ic directive named %s was found." \
						%(str(an["ic_label"]),))
					sys.exit(54)
				x0 = x0_ic_dict[an["ic_label"]]
			
			sol = transient.transient_analysis(circ, \
				tstart=an["tstart"], tstep=an["tstep"], tstop=an["tstop"], \
				x0=x0, mna=None, N=None, verbose=verbose, data_filename=data_filename, \
				use_step_control=(not disable_step_control), method=tran_method)
		
		elif an["type"] == "shooting":
			if an["method"]=="brute-force":
				sol = bfpss.bfpss(circ, period=an["period"], step=an["step"], mna=None, Tf=None, \
					D=None, points=an["points"], autonomous=an["autonomous"], x0=x0_op, \
					data_filename=data_filename, verbose=verbose)
			elif an["method"]=="shooting":	
				sol = shooting.shooting(circ, period=an["period"], step=an["step"], mna=None, \
					Tf=None, D=None, points=an["points"], autonomous=an["autonomous"], \
					data_filename=data_filename, verbose=verbose)
		elif an["type"] == "symbolic":
			if not 'subs' in an.keys():
				an.update({'subs':None})
			sol = symbolic.solve(circ, an['source'], opts={'ac':an['ac']}, subs=an['subs'], verbose=verbose)
		elif an["type"] == "ac":
			sol = ac.ac_analysis(circ=circ, start=an['start'], nsteps=an['nsteps'], \
				stop=an['stop'], step_type='LOG', xop=x0_op, mna=None,\
			        data_filename=data_filename, verbose=verbose)
		elif an["type"] == "temp":
			constants.T = utilities.Celsius2Kelvin(an['temp'])
		results.update({an["type"]:sol})
	return results
Exemplo n.º 27
0
def generate_mna_and_N(circ, opts, ac=False, verbose=3):
    """Generates a symbolic Modified Nodal Analysis matrix and N vector.
    """
    #   print options
    n_of_nodes = len(circ.nodes_dict)
    mna = smzeros(n_of_nodes)
    N = smzeros((n_of_nodes, 1))
    s = sympy.Symbol('s', complex=True)
    subs_g = {}

    for elem in circ:
        if isinstance(elem, devices.Resistor):
            # we use conductances instead of 1/R because there is a significant
            # overhead handling many 1/R terms in sympy.
            if elem.is_symbolic:
                R = sympy.Symbol(elem.part_id.upper(),
                                 real=True,
                                 positive=True)
                G = sympy.Symbol('G' + elem.part_id[1:],
                                 real=True,
                                 positive=True)
                # but we keep track of which is which and substitute back after
                # solving.
                subs_g.update({G: 1 / R})
            else:
                R = elem.value
                G = 1.0 / R
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + G
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - G
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - G
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + G
        elif isinstance(elem, devices.Capacitor):
            if ac:
                if elem.is_symbolic:
                    capa = sympy.Symbol(elem.part_id.upper(),
                                        real=True,
                                        positive=True)
                else:
                    capa = elem.value
                mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + s * capa
                mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - s * capa
                mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + s * capa
                mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - s * capa
            else:
                pass
        elif isinstance(elem, devices.Inductor):
            pass
        elif isinstance(elem, devices.GISource):
            if elem.is_symbolic:
                alpha = sympy.Symbol(elem.part_id.upper(), real=True)
            else:
                alpha = elem.value
            mna[elem.n1, elem.sn1] = mna[elem.n1, elem.sn1] + alpha
            mna[elem.n1, elem.sn2] = mna[elem.n1, elem.sn2] - alpha
            mna[elem.n2, elem.sn1] = mna[elem.n2, elem.sn1] - alpha
            mna[elem.n2, elem.sn2] = mna[elem.n2, elem.sn2] + alpha
        elif isinstance(elem, devices.ISource):
            if elem.is_symbolic:
                IDC = sympy.Symbol(elem.part_id.upper(), real=True)
            else:
                IDC = elem.dc_value
            N[elem.n1, 0] = N[elem.n1, 0] + IDC
            N[elem.n2, 0] = N[elem.n2, 0] - IDC
        elif isinstance(elem, mosq.mosq_device) or isinstance(
                elem, ekv.ekv_device):
            gm = sympy.Symbol('gm_' + elem.part_id, real=True, positive=True)
            mna[elem.n1, elem.ng] = mna[elem.n1, elem.ng] + gm
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gm
            mna[elem.n2, elem.ng] = mna[elem.n2, elem.ng] - gm
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gm
            if opts['r0s']:
                r0 = sympy.Symbol('r0_' + elem.part_id,
                                  real=True,
                                  positive=True)
                mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1 / r0
                mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1 / r0
                mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1 / r0
                mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1 / r0
        elif isinstance(elem, diode.diode):
            gd = sympy.Symbol("g" + elem.part_id, positive=True)
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + gd
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gd
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - gd
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gd
        elif isinstance(elem, devices.InductorCoupling):
            pass
            # this is taken care of within the inductors
        elif circuit.is_elem_voltage_defined(elem):
            pass
            # we'll add its lines afterwards
        elif verbose:
            printing.print_warning("Skipped elem %s: not implemented." %
                                   (elem.part_id.upper(), ))

    pre_vde = mna.shape[0]
    for elem in circ:
        if circuit.is_elem_voltage_defined(elem):
            index = mna.shape[0]  # get_matrix_size(mna)[0]
            mna = expand_matrix(mna, add_a_row=True, add_a_col=True)
            N = expand_matrix(N, add_a_row=True, add_a_col=False)
            # KCL
            mna[elem.n1, index] = +1
            mna[elem.n2, index] = -1
            # KVL
            mna[index, elem.n1] = +1
            mna[index, elem.n2] = -1
            if isinstance(elem, devices.VSource):
                if elem.is_symbolic:
                    VDC = sympy.Symbol(elem.part_id.upper(), real=True)
                else:
                    VDC = elem.dc_value
                N[index, 0] = -VDC
            elif isinstance(elem, devices.EVSource):
                if elem.is_symbolic:
                    alpha = sympy.Symbol(elem.part_id.upper(), real=True)
                else:
                    alpha = elem.alpha
                mna[index, elem.sn1] = -alpha
                mna[index, elem.sn2] = +alpha
            elif isinstance(elem, devices.Inductor):
                if ac:
                    if elem.is_symbolic:
                        L = sympy.Symbol(elem.part_id.upper(),
                                         real=True,
                                         positive=True)
                    else:
                        L = elem.L
                    mna[index, index] = -s * L
                else:
                    pass
                    # already so: commented out
                    # N[index,0] = 0
            elif isinstance(elem, devices.HVSource):
                printing.print_warning(
                    "symbolic.py: BUG - hvsources are not implemented yet.")
                sys.exit(33)

    for elem in circ:
        if circuit.is_elem_voltage_defined(elem):
            if isinstance(elem, devices.Inductor):
                if ac:
                    # find its index to know which column corresponds to its
                    # current
                    this_index = circ.find_vde_index(elem.part_id, verbose=0)
                    for cd in elem.coupling_devices:
                        if cd.is_symbolic:
                            M = sympy.Symbol(cd.part_id,
                                             real=True,
                                             positive=True)
                        else:
                            M = cd.K
                        # get `part_id` of the other inductor (eg. "L32")
                        other_id_wdescr = cd.get_other_inductor(elem.part_id)
                        # find its index to know which column corresponds to
                        # its current
                        other_index = circ.find_vde_index(other_id_wdescr,
                                                          verbose=0)
                        # add the term.
                        mna[pre_vde + this_index,
                            pre_vde + other_index] += -s * M
                else:
                    pass

    # all done
    return (mna, N, subs_g)
Exemplo n.º 28
0
def mdn_solver(
    x,
    mna,
    circ,
    T,
    MAXIT,
    nv,
    locked_nodes,
    time=None,
    print_steps=False,
    vector_norm=lambda v: max(abs(v)),
    debug=True,
):
    """
	Solves a problem like F(x) = 0 using the Newton Algorithm with a variable damping td.
	
	Where:
	
	F(x) = mna*x + T + T(x)
	mna is the Modified Network Analysis matrix of the circuit
	T(x) is the contribute of nonlinear elements to KCL
	T -> independent sources, time invariant and invariant
	
	x is the initial guess.
	
	Every x is given by:
	x = x + td*dx
	Where td is a damping coefficient to avoid overflow in non-linear components and
	excessive oscillation in the very first iteration. Afterwards td=1
	To calculate td, an array of locked nodes is needed.
	
	The convergence check is done this way:
	if (vector_norm(dx) < alpha*vector_norm(x) + beta) and (vector_norm(residuo) < alpha*vector_norm(x) + beta):
	beta should be the machine precision, alpha 1e-(N+1) where N is the number of the significative 
	digits you wish to have.
	
	Parameters:
	x: the initial guess. If set to None, it will be initialized to all zeros. Specifying a initial guess
	may improve the convergence time of the algorithm and determine which solution (if any) 
	is found if there are more than one.
	mna: the Modified Network Analysis matrix of the circuit, reduced, see above
	element_list:
	T: see above.
	MAXIT: Maximum iterations that the method may perform.
	nv: number of nodes in the circuit (counting the ref, 0)
	locked_nodes: see get_td() and dc_solve(), generated by circ.get_locked_nodes()
	time: the value of time to be passed to non_linear _and_ time variant elements.
	print_steps: show a progress indicator
	vector_norm:
	
	Returns a tuple with:
	the solution, 
	the remaining error, 
	a boolean that is true whenever the method exits because of a successful convergence check
	the number of NR iterations performed
	
	"""
    # OLD COMMENT: FIXME REWRITE: solve through newton
    # problem is F(x)= mna*x +H(x) = 0
    # H(x) = N + T(x)
    # lets say: J = dF/dx = mna + dT(x)/dx
    # J*dx = -1*(mna*x+N+T(x))
    # dT/dx � lo jacobiano -> g_eq (o gm)
    # print_steps = False
    # locked_nodes = get_locked_nodes(element_list)
    mna_size = mna.shape[0]
    nonlinear_circuit = circ.is_nonlinear()
    tick = ticker.ticker(increments_for_step=1)
    tick.display(print_steps)
    if x is None:
        x = numpy.mat(numpy.zeros((mna_size, 1)))  # if no guess was specified, its all zeros
    else:
        if not x.shape[0] == mna_size:
            raise Exception, "x0s size is different from expected: " + str(x.shape[0]) + " " + str(mna_size)
    if T is None:
        printing.print_warning("dc_analysis.mdn_solver called with T==None, setting T=0. BUG or no sources in circuit?")
        T = numpy.mat(numpy.zeros((mna_size, 1)))

    converged = False
    iteration = 0
    for iteration in xrange(MAXIT):  # newton iteration counter
        tick.step(print_steps)
        if nonlinear_circuit:
            # build dT(x)/dx (stored in J) and Tx(x)
            J, Tx = build_J_and_Tx(x, mna_size, circ.elements, time)
            J = J + mna
        else:
            J = mna
            Tx = 0
        residuo = mna * x + T + Tx
        dx = numpy.linalg.inv(J) * (-1 * residuo)
        x = x + get_td(dx, locked_nodes, n=iteration) * dx
        if iteration > 0:
            if convergence_check(x, dx, residuo, nv - 1)[0]:
                converged = True
                break
        if vector_norm(dx) is numpy.nan:  # Overflow
            raise OverflowError
    tick.hide(print_steps)
    if debug and not converged:
        convergence_by_node = convergence_check(x, dx, residuo, nv - 1, debug=True)[1]
    else:
        convergence_by_node = []
    return (x, residuo, converged, iteration + 1, convergence_by_node)
Exemplo n.º 29
0
def set_temperature(T):
    T = float(T)
    if T > 300:
        printing.print_warning(u"The temperature will be set to %f \xB0 C.")
    constants.T = utilities.Celsius2Kelvin(T)
Exemplo n.º 30
0
def transient_analysis(circ, tstart, tstep, tstop, method=TRAP, x0=None, mna=None, N=None, \
	D=None, data_filename="stdout", use_step_control=True, return_req_dict=None, verbose=3):
	"""Performs a transient analysis of the circuit described by circ.
	
	Important parameters:
	- tstep is the maximum step to be allowed during simulation.
	- print_step_and_lte is a boolean value. Is set to true, the step and the LTE of the first
	element of x will be printed out to step_and_lte.graph in the current directory.
	
	"""
	if data_filename == "stdout":
		verbose = 0
	_debug = False
	if _debug:
		print_step_and_lte = True
	else:
		print_step_and_lte = False
	
	HMAX = tstep
	
	#check parameters
	if tstart > tstop:
		printing.print_general_error("tstart > tstop")
		sys.exit(1)
	if tstep < 0:
		printing.print_general_error("tstep < 0")
		sys.exit(1)

	if verbose > 4:
		tmpstr = "Vea = %g Ver = %g Iea = %g Ier = %g max_time_iter = %g HMIN = %g" % \
		(options.vea, options.ver, options.iea, options.ier, options.transient_max_time_iter, options.hmin)
		printing.print_info_line((tmpstr, 5), verbose)
	
	locked_nodes = circ.get_locked_nodes()
	
	if print_step_and_lte:
		flte = open("step_and_lte.graph", "w")
		flte.write("#T\tStep\tLTE\n")
	
	printing.print_info_line(("Starting transient analysis: ", 3), verbose)
	printing.print_info_line(("Selected method: %s" % (method,), 3), verbose)
	#It's a good idea to call transient with prebuilt MNA and N matrix
	#the analysis will be slightly faster (long netlists). 
	if mna is None or N is None:
		(mna, N) = dc_analysis.generate_mna_and_N(circ)
		mna = utilities.remove_row_and_col(mna)
		N = utilities.remove_row(N, rrow=0)
	elif not mna.shape[0] == N.shape[0]:
		printing.print_general_error("mna matrix and N vector have different number of columns.")
		sys.exit(0)
	if D is None:
		# if you do more than one tran analysis, output streams should be changed...
		# this needs to be fixed
		D = generate_D(circ, [mna.shape[0], mna.shape[0]])
		D = utilities.remove_row_and_col(D)

	# setup x0
	if x0 is None:
		printing.print_info_line(("Generating x(t=%g) = 0" % (tstart,), 5), verbose)
		x0 = numpy.matrix(numpy.zeros((mna.shape[0], 1)))
		opsol =  results.op_solution(x=x0, error=x0, circ=circ, outfile=None)
	else:
		if isinstance(x0, results.op_solution):
			opsol = x0
			x0 = x0.asmatrix()
		else:
			opsol =  results.op_solution(x=x0, error=numpy.matrix(numpy.zeros((mna.shape[0], 1))), circ=circ, outfile=None)
		printing.print_info_line(("Using the supplied op as x(t=%g)." % (tstart,), 5), verbose)
		
	if verbose > 4:
		print "x0:"
		opsol.print_short()
	
	# setup the df method
	printing.print_info_line(("Selecting the appropriate DF ("+method+")... ", 5), verbose, print_nl=False)
	if method == IMPLICIT_EULER:
		import implicit_euler as df
	elif method == TRAP:
		import trap as df
	elif method == GEAR1:
		import gear as df
		df.order = 1
	elif method == GEAR2:
		import gear as df
		df.order = 2
	elif method == GEAR3:
		import gear as df
		df.order = 3
	elif method == GEAR4:
		import gear as df
		df.order = 4
	elif method == GEAR5:
		import gear as df
		df.order = 5
	elif method == GEAR6:
		import gear as df
		df.order = 6
	else:
		df = import_custom_df_module(method, print_out=(data_filename != "stdout"))
		# df is none if module is not found
	
	if df is None:
		sys.exit(23)
		
	if not df.has_ff() and use_step_control:
		printing.print_warning("The chosen DF does not support step control. Turning off the feature.")
		use_step_control = False
		#use_aposteriori_step_control = False

	printing.print_info_line(("done.", 5), verbose)
		
	# setup the data buffer
	# if you use the step control, the buffer has to be one point longer.
	# That's because the excess point is used by a FF in the df module to predict the next value.
	printing.print_info_line(("Setting up the buffer... ", 5), verbose, print_nl=False)
	((max_x, max_dx), (pmax_x, pmax_dx)) = df.get_required_values()
	if max_x is None and max_dx is None:
		printing.print_general_error("df doesn't need any value?")
		sys.exit(1)
	if use_step_control:
		thebuffer = dfbuffer(length=max(max_x, max_dx, pmax_x, pmax_dx) + 1, width=3)
	else:
		thebuffer = dfbuffer(length=max(max_x, max_dx) + 1, width=3)
	thebuffer.add((tstart, x0, None)) #setup the first values
	printing.print_info_line(("done.", 5), verbose) #FIXME
	
	#setup the output buffer
	if return_req_dict:
		output_buffer = dfbuffer(length=return_req_dict["points"], width=1)
		output_buffer.add((x0,))
	else:
		output_buffer = None
	
	# import implicit_euler to be used in the first iterations
	# this is because we don't have any dx when we start, nor any past point value
	if (max_x is not None and max_x > 0) or max_dx is not None:
		import implicit_euler
	
	printing.print_info_line(("MNA (reduced):", 5), verbose)
	printing.print_info_line((str(mna), 5), verbose)
	printing.print_info_line(("D (reduced):", 5), verbose)
	printing.print_info_line((str(D), 5), verbose)
	
	# setup the initial values to start the iteration:
	x = None
	time = tstart
	nv = len(circ.nodes_dict)

	Gmin_matrix = dc_analysis.build_gmin_matrix(circ, options.gmin, mna.shape[0], verbose)

	# lo step viene generato automaticamente, ma non superare mai quello fornito.
	if use_step_control:
		#tstep = min((tstop-tstart)/9999.0, HMAX, 100.0 * options.hmin)
		tstep = min((tstop-tstart)/9999.0, HMAX)
	printing.print_info_line(("Initial step: %g"% (tstep,), 5), verbose)

	if max_dx is None:
		max_dx_plus_1 = None
	else:
		max_dx_plus_1 = max_dx +1
	if pmax_dx is None:
		pmax_dx_plus_1 = None
	else:
		pmax_dx_plus_1 = pmax_dx +1
	
	# setup error vectors
	aerror = numpy.mat(numpy.zeros((x0.shape[0], 1)))
	aerror[:nv-1, 0] = options.vea
	aerror[nv-1:, 0] = options.vea
	rerror = numpy.mat(numpy.zeros((x0.shape[0], 1)))
	rerror[:nv-1, 0] = options.ver
	rerror[nv-1:, 0] = options.ier
	
	iter_n = 0  # contatore d'iterazione
	lte = None
	sol = results.tran_solution(circ, tstart, tstop, op=x0, method=method, outfile=data_filename)
	printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
	tick = ticker.ticker(increments_for_step=1)
	tick.display(verbose > 1)
	while time < tstop:
		if iter_n < max(max_x, max_dx_plus_1):
			x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff = \
			implicit_euler.get_df((thebuffer.get_df_vector()[0],), tstep, \
			predict=(use_step_control and (iter_n >= max(pmax_x, pmax_dx_plus_1))))
			
		else:
			[x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff] = \
			df.get_df(thebuffer.get_df_vector(), tstep, predict=use_step_control)
		
		if options.transient_prediction_as_x0 and use_step_control and prediction is not None:
			x0 = prediction
		elif x is not None:
			x0 = x
		
		(x1, error, solved, n_iter) = dc_analysis.dc_solve(mna=(mna + numpy.multiply(x_coeff, D)) , Ndc=N,  Ntran=D*const, circ=circ, Gmin=Gmin_matrix, x0=x0, time=(time + tstep), locked_nodes=locked_nodes, MAXIT=options.transient_max_nr_iter, verbose=0)
		
		if solved:
			old_step = tstep #we will modify it, if we're using step control otherwise it's the same
			# step control (yeah)
			if use_step_control:
				if x_lte_coeff is not None and pred_lte_coeff is not None and prediction is not None:
					# this is the Local Truncation Error :)
					lte = abs((x_lte_coeff / (pred_lte_coeff - x_lte_coeff)) * (prediction - x1))
					# it should NEVER happen that new_step > 2*tstep, for stability
					new_step_coeff = 2 
					for index in xrange(x.shape[0]):
						if lte[index, 0] != 0:
							new_value = ((aerror[index, 0] + rerror[index, 0]*abs(x[index, 0])) / lte[index, 0]) \
							** (1.0 / (df.order+1))
							if new_value < new_step_coeff:
								new_step_coeff = new_value
							#print new_value
					new_step = tstep * new_step_coeff
					if options.transient_use_aposteriori_step_control and new_step < options.transient_aposteriori_step_threshold * tstep: 
						#don't recalculate a x for a small change
						tstep = check_step(new_step, time, tstop, HMAX)
						#print "Apost. (reducing) step = "+str(tstep)
						continue
					tstep = check_step(new_step, time, tstop, HMAX) # used in the next iteration
					#print "Apriori tstep = "+str(tstep)
				else:
					#print "LTE not calculated."
					lte = None
			if print_step_and_lte and lte is not None: 
				#if you wish to look at the step. We print just a lte
				flte.write(str(time)+"\t"+str(old_step)+"\t"+str(lte.max())+"\n")
			# if we get here, either aposteriori_step_control is 
			# disabled, or it's enabled and the error is small
			# enough. Anyway, the result is GOOD, STORE IT.
			time = time + old_step
			x = x1
			iter_n = iter_n + 1
			sol.add_line(time, x)
			
			dxdt = numpy.multiply(x_coeff, x) + const
			thebuffer.add((time, x, dxdt))
			if output_buffer is not None:
				output_buffer.add((x, ))
			tick.step(verbose > 1)
		else:
			# If we get here, Newton failed to converge. We need to reduce the step...
			if use_step_control:
				tstep = tstep/5.0
				tstep = check_step(tstep, time, tstop, HMAX)
				printing.print_info_line(("At %g s reducing step: %g s (convergence failed)" % (time, tstep), 5), verbose)
			else: #we can't reduce the step
				printing.print_general_error("Can't converge with step "+str(tstep)+".")
				printing.print_general_error("Try setting --t-max-nr to a higher value or set step to a lower one.")
				solved = False
				break
		if options.transient_max_time_iter and iter_n == options.transient_max_time_iter:
			printing.print_general_error("MAX_TIME_ITER exceeded ("+str(options.transient_max_time_iter)+"), iteration halted.")
			solved = False
			break
	
	if print_step_and_lte:
		flte.close()
	
	tick.hide(verbose > 1)
	
	if solved:
		printing.print_info_line(("done.", 3), verbose)
		printing.print_info_line(("Average time step: %g" % ((tstop - tstart)/iter_n,), 3), verbose)

		if output_buffer:
			ret_value = output_buffer.get_as_matrix()
		else:
			ret_value = sol
	else:
		print "failed."
		ret_value =  None
	
	return ret_value
Exemplo n.º 31
0
def solve(circ, tf_source=None, subs=None, opts=None, verbose=3):
	"""Attempt a symbolic solution of the circuit.
	circ: the circuit instance to be simulated.
	tf_source: the name (string) of the source to be used as input for the transfer
		   function. If None, no transfer function is evaluated.
	subs: a dictionary of sympy Symbols to be substituted. It makes solving the circuit 
	      easier. Eg. {R1:R2} - replace R1 with R2. It can be generated with 
	      parse_substitutions()
	opts: dict of 'option':boolean to be taken into account in simulation.
	      currently 'r0s' and 'ac' are the only options considered.
	verbose: verbosity level 0 (silent) to 6 (painful).
	
	Returns: a dictionary with the solutions.
	"""
	if opts is None:
		# load the defaults
		opts = {'r0s':True, 'ac':False}
	if not 'r0s' in opts.keys():
		opts.update({'r0s':True})
	if not 'ac' in opts.keys():
		opts.update({'ac':False})
	if subs is None:
		subs = {} # no subs by default

	if not opts['ac']:
		printing.print_info_line(("Starting symbolic DC analysis...", 1), verbose)
	else:
		printing.print_info_line(("Starting symbolic AC analysis...", 1), verbose)		
		
	printing.print_info_line(("Building symbolic MNA, N and x...", 3), verbose, print_nl=False)
	mna, N, subs_g = generate_mna_and_N(circ, opts, opts['ac'])
	x = get_variables(circ)
	mna = mna[1:, 1:]
	N = N[1:, :]
	printing.print_info_line((" done.", 3), verbose)	

	printing.print_info_line(("Performing variable substitutions...", 5), verbose)
	mna, N = apply_substitutions(mna, N, subs)

	printing.print_info_line(("MNA matrix (reduced):", 5), verbose)	
	if verbose > 5:	print sympy.sstr(mna)
	printing.print_info_line(("N matrix (reduced):", 5), verbose)	
	if verbose > 5:	print sympy.sstr(N)

	printing.print_info_line(("Building equations...", 3), verbose)	
	eq = []
	for i in to_real_list(mna * x + N):
		eq.append(sympy.Eq(i, 0))

	x = to_real_list(x)
	if verbose > 4:
		printing.print_symbolic_equations(eq)
		print "To be solved for:"
		print x
		#print "Matrix is singular: ", (mna.det() == 0)
	#print -1.0*mna.inv()*N #too heavy
	#print sympy.solve_linear_system(mna.row_join(-N), x)
	printing.print_info_line(("Performing auxiliary simplification...", 3), verbose)	
	eq, x, sol_h = help_the_solver(eq, x)
		
	if len(eq):
		if verbose > 3:
			print "Symplified sytem:"
			printing.print_symbolic_equations(eq)
			print "To be solved for:"
			print x
			printing.print_info_line(("Solving...", 1), verbose)	

		if options.symb_internal_solver:
			sol = local_solve(eq, x)
		else:
			sol = sympy.solve(eq, x, manual=options.symb_sympy_manual_solver, simplify=True)
		if sol is not None:		
			sol.update(sol_h)
		else:
			sol = sol_h
	else:
		printing.print_info_line(("Auxiliary simplification solved the problem.", 3), verbose)	
		sol = sol_h

	for ks in sol.keys():
		sol.update({ks:sol[ks].subs(subs_g)})

	#sol = sol_to_dict(sol, x)

	if sol == {}:
		printing.print_warning("No solutions. Check the netlist.")
	else:
		printing.print_info_line(("Success!", 2), verbose)	
		if verbose > 1:
			print "Results:"
		printing.print_symbolic_results(sol)

	if tf_source is not None:
		src = sympy.Symbol(tf_source.upper(), real=True)
		printing.print_info_line(("Calculating small-signal symbolic transfer functions (%s))..."%(str(src),), 2), verbose, print_nl=False)
		tfs = calculate_gains(sol, src)
		printing.print_info_line(("done.", 2), verbose)	
		printing.print_info_line(("Small-signal symbolic transfer functions:", 1), verbose)	
		printing.print_symbolic_transfer_functions(tfs)
	else:
		tfs = None
	
	# convert to a results instance
	sol = results.symbolic_solution(sol, subs, circ)
	return sol, tfs
Exemplo n.º 32
0
def symbolic_analysis(circ,
                      source=None,
                      ac_enable=True,
                      r0s=False,
                      subs=None,
                      outfile=None,
                      verbose=3):
    """Attempt a symbolic solution of the circuit.
    circ: the circuit instance to be simulated.
    source: the name (string) of the source to be used as input for the transfer
           function. If None, no transfer function is evaluated.
    ac_enable: take frequency dependency into consideration (default: True)
    r0s: take transistors' output impedance into consideration (default: False)
    subs: a dictionary of sympy Symbols to be substituted. It makes solving the circuit
          easier. Eg. {R1:R2} - replace R1 with R2. It can be generated with
          parse_substitutions()
    outfile: output filename ('stdout' means print to stdout).
    verbose: verbosity level 0 (silent) to 6 (painful).

    Returns: a dictionary with the solutions.
    """
    if subs is None:
        subs = {}  # no subs by default

    if not ac_enable:
        printing.print_info_line(("Starting symbolic DC analysis...", 1),
                                 verbose)
    else:
        printing.print_info_line(("Starting symbolic AC analysis...", 1),
                                 verbose)

    printing.print_info_line(("Building symbolic MNA, N and x...", 3),
                             verbose,
                             print_nl=False)
    mna, N, subs_g = generate_mna_and_N(circ,
                                        opts={'r0s': r0s},
                                        ac=ac_enable,
                                        verbose=verbose)
    x = get_variables(circ)
    mna = mna[1:, 1:]
    N = N[1:, :]
    printing.print_info_line((" done.", 3), verbose)

    printing.print_info_line(("Performing variable substitutions...", 5),
                             verbose)
    mna, N = apply_substitutions(mna, N, subs)

    printing.print_info_line(("MNA matrix (reduced):", 5), verbose)
    printing.print_info_line((sympy.sstr(mna), 5), verbose)
    printing.print_info_line(("N matrix (reduced):", 5), verbose)
    printing.print_info_line((sympy.sstr(N), 5), verbose)

    printing.print_info_line(("Building equations...", 3), verbose)
    eq = []
    for i in to_real_list(mna * x + N):
        eq.append(sympy.Eq(i, 0))

    x = to_real_list(x)
    if verbose > 4:
        printing.print_symbolic_equations(eq)
        print "To be solved for:"
        print x
        # print "Matrix is singular: ", (mna.det() == 0)
    # print -1.0*mna.inv()*N #too heavy
    # print sympy.solve_linear_system(mna.row_join(-N), x)
    printing.print_info_line(("Performing auxiliary simplification...", 3),
                             verbose)
    eq, x, sol_h = help_the_solver(eq, x)

    if len(eq):
        printing.print_info_line(("Symplified sytem:", 3), verbose)
        if verbose > 3:
            printing.print_symbolic_equations(eq)
        printing.print_info_line(("To be solved for:", 3), verbose)
        printing.print_info_line((str(x), 3), verbose)
        printing.print_info_line(("Solving...", 1), verbose)

        if options.symb_internal_solver:
            sol = local_solve(eq, x)
        else:
            sol = sympy.solve(eq,
                              x,
                              manual=options.symb_sympy_manual_solver,
                              simplify=True)
        if sol is not None:
            sol.update(sol_h)
        else:
            sol = sol_h
    else:
        printing.print_info_line(
            ("Auxiliary simplification solved the problem.", 3), verbose)
        sol = sol_h

    for ks in sol.keys():
        sol.update({ks: sol[ks].subs(subs_g)})

    # sol = sol_to_dict(sol, x)

    if sol == {}:
        printing.print_warning("No solutions. Check the netlist.")
    else:
        printing.print_info_line(("Success!", 2), verbose)
        printing.print_info_line(("Results:", 1), verbose)
        if options.cli:
            printing.print_symbolic_results(sol)

    if source is not None:
        src = sympy.Symbol(source.upper(), real=True)
        printing.print_info_line(
            ("Calculating small-signal symbolic transfer functions (%s))..." %
             (str(src), ), 2),
            verbose,
            print_nl=False)
        tfs = calculate_gains(sol, src)
        printing.print_info_line(("done.", 2), verbose)
        printing.print_info_line(
            ("Small-signal symbolic transfer functions:", 1), verbose)
        if options.cli:
            printing.print_symbolic_transfer_functions(tfs)
    else:
        tfs = None

    # convert to a results instance
    sol = results.symbolic_solution(sol, subs, circ, outfile)
    if tfs:
        if outfile and outfile != 'stdout':
            outfile += ".tfs"
        tfs = results.symbolic_solution(tfs, subs, circ, outfile, tf=True)
    return sol, tfs
Exemplo n.º 33
0
def transient_analysis(circ, tstart, tstep, tstop, method=TRAP, x0=None, mna=None, N=None, \
 D=None, data_filename="stdout", use_step_control=True, return_req_dict=None, verbose=3):
    """Performs a transient analysis of the circuit described by circ.
	
	Important parameters:
	- tstep is the maximum step to be allowed during simulation.
	- print_step_and_lte is a boolean value. Is set to true, the step and the LTE of the first
	element of x will be printed out to step_and_lte.graph in the current directory.
	
	"""
    if data_filename == "stdout":
        verbose = 0
    _debug = False
    if _debug:
        print_step_and_lte = True
    else:
        print_step_and_lte = False

    HMAX = tstep

    #check parameters
    if tstart > tstop:
        printing.print_general_error("tstart > tstop")
        sys.exit(1)
    if tstep < 0:
        printing.print_general_error("tstep < 0")
        sys.exit(1)

    if verbose > 4:
        tmpstr = "Vea = %g Ver = %g Iea = %g Ier = %g max_time_iter = %g HMIN = %g" % \
        (options.vea, options.ver, options.iea, options.ier, options.transient_max_time_iter, options.hmin)
        printing.print_info_line((tmpstr, 5), verbose)

    locked_nodes = circ.get_locked_nodes()

    if print_step_and_lte:
        flte = open("step_and_lte.graph", "w")
        flte.write("#T\tStep\tLTE\n")

    printing.print_info_line(("Starting transient analysis: ", 3), verbose)
    printing.print_info_line(("Selected method: %s" % (method, ), 3), verbose)
    #It's a good idea to call transient with prebuilt MNA and N matrix
    #the analysis will be slightly faster (long netlists).
    if mna is None or N is None:
        (mna, N) = dc_analysis.generate_mna_and_N(circ)
        mna = utilities.remove_row_and_col(mna)
        N = utilities.remove_row(N, rrow=0)
    elif not mna.shape[0] == N.shape[0]:
        printing.print_general_error(
            "mna matrix and N vector have different number of columns.")
        sys.exit(0)
    if D is None:
        # if you do more than one tran analysis, output streams should be changed...
        # this needs to be fixed
        D = generate_D(circ, [mna.shape[0], mna.shape[0]])
        D = utilities.remove_row_and_col(D)

    # setup x0
    if x0 is None:
        printing.print_info_line(("Generating x(t=%g) = 0" % (tstart, ), 5),
                                 verbose)
        x0 = numpy.matrix(numpy.zeros((mna.shape[0], 1)))
        opsol = results.op_solution(x=x0, error=x0, circ=circ, outfile=None)
    else:
        if isinstance(x0, results.op_solution):
            opsol = x0
            x0 = x0.asmatrix()
        else:
            opsol = results.op_solution(x=x0,
                                        error=numpy.matrix(
                                            numpy.zeros((mna.shape[0], 1))),
                                        circ=circ,
                                        outfile=None)
        printing.print_info_line(
            ("Using the supplied op as x(t=%g)." % (tstart, ), 5), verbose)

    if verbose > 4:
        print "x0:"
        opsol.print_short()

    # setup the df method
    printing.print_info_line(
        ("Selecting the appropriate DF (" + method + ")... ", 5),
        verbose,
        print_nl=False)
    if method == IMPLICIT_EULER:
        import implicit_euler as df
    elif method == TRAP:
        import trap as df
    elif method == GEAR1:
        import gear as df
        df.order = 1
    elif method == GEAR2:
        import gear as df
        df.order = 2
    elif method == GEAR3:
        import gear as df
        df.order = 3
    elif method == GEAR4:
        import gear as df
        df.order = 4
    elif method == GEAR5:
        import gear as df
        df.order = 5
    elif method == GEAR6:
        import gear as df
        df.order = 6
    else:
        df = import_custom_df_module(method,
                                     print_out=(data_filename != "stdout"))
        # df is none if module is not found

    if df is None:
        sys.exit(23)

    if not df.has_ff() and use_step_control:
        printing.print_warning(
            "The chosen DF does not support step control. Turning off the feature."
        )
        use_step_control = False
        #use_aposteriori_step_control = False

    printing.print_info_line(("done.", 5), verbose)

    # setup the data buffer
    # if you use the step control, the buffer has to be one point longer.
    # That's because the excess point is used by a FF in the df module to predict the next value.
    printing.print_info_line(("Setting up the buffer... ", 5),
                             verbose,
                             print_nl=False)
    ((max_x, max_dx), (pmax_x, pmax_dx)) = df.get_required_values()
    if max_x is None and max_dx is None:
        printing.print_general_error("df doesn't need any value?")
        sys.exit(1)
    if use_step_control:
        thebuffer = dfbuffer(length=max(max_x, max_dx, pmax_x, pmax_dx) + 1,
                             width=3)
    else:
        thebuffer = dfbuffer(length=max(max_x, max_dx) + 1, width=3)
    thebuffer.add((tstart, x0, None))  #setup the first values
    printing.print_info_line(("done.", 5), verbose)  #FIXME

    #setup the output buffer
    if return_req_dict:
        output_buffer = dfbuffer(length=return_req_dict["points"], width=1)
        output_buffer.add((x0, ))
    else:
        output_buffer = None

    # import implicit_euler to be used in the first iterations
    # this is because we don't have any dx when we start, nor any past point value
    if (max_x is not None and max_x > 0) or max_dx is not None:
        import implicit_euler

    printing.print_info_line(("MNA (reduced):", 5), verbose)
    printing.print_info_line((str(mna), 5), verbose)
    printing.print_info_line(("D (reduced):", 5), verbose)
    printing.print_info_line((str(D), 5), verbose)

    # setup the initial values to start the iteration:
    x = None
    time = tstart
    nv = len(circ.nodes_dict)

    Gmin_matrix = dc_analysis.build_gmin_matrix(circ, options.gmin,
                                                mna.shape[0], verbose)

    # lo step viene generato automaticamente, ma non superare mai quello fornito.
    if use_step_control:
        #tstep = min((tstop-tstart)/9999.0, HMAX, 100.0 * options.hmin)
        tstep = min((tstop - tstart) / 9999.0, HMAX)
    printing.print_info_line(("Initial step: %g" % (tstep, ), 5), verbose)

    if max_dx is None:
        max_dx_plus_1 = None
    else:
        max_dx_plus_1 = max_dx + 1
    if pmax_dx is None:
        pmax_dx_plus_1 = None
    else:
        pmax_dx_plus_1 = pmax_dx + 1

    # setup error vectors
    aerror = numpy.mat(numpy.zeros((x0.shape[0], 1)))
    aerror[:nv - 1, 0] = options.vea
    aerror[nv - 1:, 0] = options.vea
    rerror = numpy.mat(numpy.zeros((x0.shape[0], 1)))
    rerror[:nv - 1, 0] = options.ver
    rerror[nv - 1:, 0] = options.ier

    iter_n = 0  # contatore d'iterazione
    lte = None
    sol = results.tran_solution(circ,
                                tstart,
                                tstop,
                                op=x0,
                                method=method,
                                outfile=data_filename)
    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick = ticker.ticker(increments_for_step=1)
    tick.display(verbose > 1)
    while time < tstop:
        if iter_n < max(max_x, max_dx_plus_1):
            x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff = \
            implicit_euler.get_df((thebuffer.get_df_vector()[0],), tstep, \
            predict=(use_step_control and (iter_n >= max(pmax_x, pmax_dx_plus_1))))

        else:
            [x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff] = \
            df.get_df(thebuffer.get_df_vector(), tstep, predict=use_step_control)

        if options.transient_prediction_as_x0 and use_step_control and prediction is not None:
            x0 = prediction
        elif x is not None:
            x0 = x

        (x1, error, solved,
         n_iter) = dc_analysis.dc_solve(mna=(mna + numpy.multiply(x_coeff, D)),
                                        Ndc=N,
                                        Ntran=D * const,
                                        circ=circ,
                                        Gmin=Gmin_matrix,
                                        x0=x0,
                                        time=(time + tstep),
                                        locked_nodes=locked_nodes,
                                        MAXIT=options.transient_max_nr_iter,
                                        verbose=0)

        if solved:
            old_step = tstep  #we will modify it, if we're using step control otherwise it's the same
            # step control (yeah)
            if use_step_control:
                if x_lte_coeff is not None and pred_lte_coeff is not None and prediction is not None:
                    # this is the Local Truncation Error :)
                    lte = abs((x_lte_coeff / (pred_lte_coeff - x_lte_coeff)) *
                              (prediction - x1))
                    # it should NEVER happen that new_step > 2*tstep, for stability
                    new_step_coeff = 2
                    for index in xrange(x.shape[0]):
                        if lte[index, 0] != 0:
                            new_value = ((aerror[index, 0] + rerror[index, 0]*abs(x[index, 0])) / lte[index, 0]) \
                            ** (1.0 / (df.order+1))
                            if new_value < new_step_coeff:
                                new_step_coeff = new_value
                            #print new_value
                    new_step = tstep * new_step_coeff
                    if options.transient_use_aposteriori_step_control and new_step < options.transient_aposteriori_step_threshold * tstep:
                        #don't recalculate a x for a small change
                        tstep = check_step(new_step, time, tstop, HMAX)
                        #print "Apost. (reducing) step = "+str(tstep)
                        continue
                    tstep = check_step(new_step, time, tstop,
                                       HMAX)  # used in the next iteration
                    #print "Apriori tstep = "+str(tstep)
                else:
                    #print "LTE not calculated."
                    lte = None
            if print_step_and_lte and lte is not None:
                #if you wish to look at the step. We print just a lte
                flte.write(
                    str(time) + "\t" + str(old_step) + "\t" + str(lte.max()) +
                    "\n")
            # if we get here, either aposteriori_step_control is
            # disabled, or it's enabled and the error is small
            # enough. Anyway, the result is GOOD, STORE IT.
            time = time + old_step
            x = x1
            iter_n = iter_n + 1
            sol.add_line(time, x)

            dxdt = numpy.multiply(x_coeff, x) + const
            thebuffer.add((time, x, dxdt))
            if output_buffer is not None:
                output_buffer.add((x, ))
            tick.step(verbose > 1)
        else:
            # If we get here, Newton failed to converge. We need to reduce the step...
            if use_step_control:
                tstep = tstep / 5.0
                tstep = check_step(tstep, time, tstop, HMAX)
                printing.print_info_line(
                    ("At %g s reducing step: %g s (convergence failed)" %
                     (time, tstep), 5), verbose)
            else:  #we can't reduce the step
                printing.print_general_error("Can't converge with step " +
                                             str(tstep) + ".")
                printing.print_general_error(
                    "Try setting --t-max-nr to a higher value or set step to a lower one."
                )
                solved = False
                break
        if options.transient_max_time_iter and iter_n == options.transient_max_time_iter:
            printing.print_general_error("MAX_TIME_ITER exceeded (" +
                                         str(options.transient_max_time_iter) +
                                         "), iteration halted.")
            solved = False
            break

    if print_step_and_lte:
        flte.close()

    tick.hide(verbose > 1)

    if solved:
        printing.print_info_line(("done.", 3), verbose)
        printing.print_info_line(
            ("Average time step: %g" % ((tstop - tstart) / iter_n, ), 3),
            verbose)

        if output_buffer:
            ret_value = output_buffer.get_as_matrix()
        else:
            ret_value = sol
    else:
        print "failed."
        ret_value = None

    return ret_value