Qucs-core  0.0.18
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
nasolver.cpp
Go to the documentation of this file.
1 /*
2  * nasolver.cpp - nodal analysis solver class implementation
3  *
4  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Stefan Jahn <stefan@lkcc.org>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this package; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * $Id$
22  *
23  */
24 
25 // the types required for qucs library files are defined
26 // in qucs_typedefs.h, created by configure from
27 // qucs_typedefs.h.in
28 #include "qucs_typedefs.h"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <cmath>
34 #include <float.h>
35 #include <assert.h>
36 
37 #include "logging.h"
38 #include "complex.h"
39 #include "object.h"
40 #include "node.h"
41 #include "circuit.h"
42 #include "vector.h"
43 #include "dataset.h"
44 #include "net.h"
45 #include "analysis.h"
46 #include "nodelist.h"
47 #include "nodeset.h"
48 #include "strlist.h"
49 #include "tvector.h"
50 #include "tmatrix.h"
51 #include "eqnsys.h"
52 #include "precision.h"
53 #include "operatingpoint.h"
54 #include "exception.h"
55 #include "exceptionstack.h"
56 #include "nasolver.h"
57 #include "constants.h"
58 
59 namespace qucs {
60 
61 // Constructor creates an unnamed instance of the nasolver class.
62 template <class nr_type_t>
64 {
65  nlist = NULL;
66  A = C = NULL;
67  z = x = xprev = zprev = NULL;
68  reltol = abstol = vntol = 0;
69  desc = NULL;
70  calculate_func = NULL;
71  convHelper = fixpoint = 0;
73  updateMatrix = 1;
74  gMin = srcFactor = 0;
75  eqns = new eqnsys<nr_type_t> ();
76 }
77 
78 // Constructor creates a named instance of the nasolver class.
79 template <class nr_type_t>
80 nasolver<nr_type_t>::nasolver (char * n) : analysis (n)
81 {
82  nlist = NULL;
83  A = C = NULL;
84  z = x = xprev = zprev = NULL;
85  reltol = abstol = vntol = 0;
86  desc = NULL;
87  calculate_func = NULL;
88  convHelper = fixpoint = 0;
90  updateMatrix = 1;
91  gMin = srcFactor = 0;
92  eqns = new eqnsys<nr_type_t> ();
93 }
94 
95 // Destructor deletes the nasolver class object.
96 template <class nr_type_t>
98 {
99  if (nlist) delete nlist;
100  if (C) delete C;
101  delete A;
102  delete z;
103  delete x;
104  delete xprev;
105  delete zprev;
106  delete eqns;
107 }
108 
109 /* The copy constructor creates a new instance of the nasolver class
110  based on the given nasolver object. */
111 template <class nr_type_t>
113 {
114  nlist = o.nlist ? new nodelist (*(o.nlist)) : NULL;
115  A = o.A ? new tmatrix<nr_type_t> (*(o.A)) : NULL;
116  C = o.C ? new tmatrix<nr_type_t> (*(o.C)) : NULL;
117  z = o.z ? new tvector<nr_type_t> (*(o.z)) : NULL;
118  x = o.x ? new tvector<nr_type_t> (*(o.x)) : NULL;
119  xprev = zprev = NULL;
120  reltol = o.reltol;
121  abstol = o.abstol;
122  vntol = o.vntol;
123  desc = o.desc;
126  eqnAlgo = o.eqnAlgo;
128  fixpoint = o.fixpoint;
129  gMin = o.gMin;
130  srcFactor = o.srcFactor;
131  eqns = new eqnsys<nr_type_t> (*(o.eqns));
133 }
134 
135 /* The function runs the nodal analysis solver once, reports errors if
136  any and save the results into each circuit. */
137 template <class nr_type_t>
139 {
140  qucs::exception * e;
141  int error = 0, d;
142 
143  // run the calculation function for each circuit
144  calculate ();
145 
146  // generate A matrix and z vector
147  createMatrix ();
148 
149  // solve equation system
150  try_running ()
151  {
152  runMNA ();
153  }
154  // appropriate exception handling
155  catch_exception ()
156  {
157  case EXCEPTION_PIVOT:
160  d = top_exception()->getData ();
161  pop_exception ();
162  if (d >= countNodes ())
163  {
164  d -= countNodes ();
165  e->setText ("voltage source `%s' conflicts with some other voltage "
166  "source", findVoltageSource(d)->getName ());
167  }
168  else
169  {
170  e->setText ("circuit admittance matrix in %s solver is singular at "
171  "node `%s' connected to [%s]", desc, nlist->get (d),
172  nlist->getNodeString (d));
173  }
174  throw_exception (e);
175  error++;
176  break;
177  case EXCEPTION_SINGULAR:
178  do
179  {
180  d = top_exception()->getData ();
181  pop_exception ();
182  if (d < countNodes ())
183  {
184  logprint (LOG_ERROR, "WARNING: %s: inserted virtual resistance at "
185  "node `%s' connected to [%s]\n", getName (), nlist->get (d),
186  nlist->getNodeString (d));
187  }
188  }
189  while (top_exception() != NULL &&
190  top_exception()->getCode () == EXCEPTION_SINGULAR);
191  break;
192  default:
193  estack.print ();
194  break;
195  }
196 
197  // save results into circuits
198  if (!error) saveSolution ();
199  return error;
200 }
201 
202 /* Run this function after the actual solver run and before evaluating
203  the results. */
204 template <class nr_type_t>
206 {
207  delete nlist;
208  nlist = NULL;
209 }
210 
211 /* Run this function before the actual solver. */
212 template <class nr_type_t>
214 {
215  // create node list, enumerate nodes and voltage sources
216 #if DEBUG
217  logprint (LOG_STATUS, "NOTIFY: %s: creating node list for %s analysis\n",
218  getName (), desc);
219 #endif
220  nlist = new nodelist (subnet);
221  nlist->assignNodes ();
222  assignVoltageSources ();
223 #if DEBUG && 0
224  nlist->print ();
225 #endif
226 
227  // create matrix, solution vector and right hand side vector
228  int M = countVoltageSources ();
229  int N = countNodes ();
230  if (A != NULL) delete A;
231  A = new tmatrix<nr_type_t> (M + N);
232  if (z != NULL) delete z;
233  z = new tvector<nr_type_t> (N + M);
234  if (x != NULL) delete x;
235  x = new tvector<nr_type_t> (N + M);
236 
237 #if DEBUG
238  logprint (LOG_STATUS, "NOTIFY: %s: solving %s netlist\n", getName (), desc);
239 #endif
240 }
241 
242 /* This function goes through the nodeset list of the current netlist
243  and applies the stored values to the current solution vector. Then
244  the function saves the solution vector back into the actual
245  component nodes. */
246 template <class nr_type_t>
248 {
249  if (x == NULL || nlist == NULL) return;
250 
251  // set each solution to zero
252  if (nokeep) for (int i = 0; i < x->getSize (); i++) x->set (i, 0);
253 
254  // then apply the nodeset itself
255  for (nodeset * n = subnet->getNodeset (); n; n = n->getNext ())
256  {
257  struct nodelist_t * nl = nlist->getNode (n->getName ());
258  if (nl != NULL)
259  {
260  x->set (nl->n, n->getValue ());
261  }
262  else
263  {
264  logprint (LOG_ERROR, "WARNING: %s: no such node `%s' found, cannot "
265  "initialize node\n", getName (), n->getName ());
266  }
267  }
268  if (xprev != NULL) *xprev = *x;
269  saveSolution ();
270 }
271 
272 /* The following function uses the gMin-stepping algorithm in order to
273  solve the given non-linear netlist by continuous iterations. */
274 template <class nr_type_t>
276 {
277  qucs::exception * e;
278  int convergence, run = 0, MaxIterations, error = 0;
279  nr_double_t gStep, gPrev;
280 
281  // fetch simulation properties
282  MaxIterations = getPropertyInteger ("MaxIter") / 4 + 1;
283  updateMatrix = 1;
284  fixpoint = 0;
285 
286  // initialize the stepper
287  gPrev = gMin = 0.01;
288  gStep = gMin / 100;
289  gMin -= gStep;
290 
291  do
292  {
293  // run solving loop until convergence is reached
294  run = 0;
295  do
296  {
297  error = solve_once ();
298  if (!error)
299  {
300  // convergence check
301  convergence = (run > 0) ? checkConvergence () : 0;
302  savePreviousIteration ();
303  run++;
304  }
305  else break;
306  }
307  while (!convergence && run < MaxIterations);
308  iterations += run;
309 
310  // not yet converged, so decreased the gMin-step
311  if (run >= MaxIterations || error)
312  {
313  gStep /= 2;
314  // here the absolute minimum step checker
315  if (gStep < NR_EPSI)
316  {
317  error = 1;
319  e->setText ("no convergence in %s analysis after %d gMinStepping "
320  "iterations", desc, iterations);
321  throw_exception (e);
322  break;
323  }
324  gMin = MAX (gPrev - gStep, 0);
325  }
326  // converged, increased the gMin-step
327  else
328  {
329  gPrev = gMin;
330  gMin = MAX (gMin - gStep, 0);
331  gStep *= 2;
332  }
333  }
334  // continue until no additional resistances is necessary
335  while (gPrev > 0);
336 
337  return error;
338 }
339 
340 /* The following function uses the source-stepping algorithm in order
341  to solve the given non-linear netlist by continuous iterations. */
342 template <class nr_type_t>
344 {
345  qucs::exception * e;
346  int convergence, run = 0, MaxIterations, error = 0;
347  nr_double_t sStep, sPrev;
348 
349  // fetch simulation properties
350  MaxIterations = getPropertyInteger ("MaxIter") / 4 + 1;
351  updateMatrix = 1;
352  fixpoint = 0;
353 
354  // initialize the stepper
355  sPrev = srcFactor = 0;
356  sStep = 0.01;
357  srcFactor += sStep;
358 
359  do
360  {
361  // run solving loop until convergence is reached
362  run = 0;
363  do
364  {
365  subnet->setSrcFactor (srcFactor);
366  error = solve_once ();
367  if (!error)
368  {
369  // convergence check
370  convergence = (run > 0) ? checkConvergence () : 0;
371  savePreviousIteration ();
372  run++;
373  }
374  else break;
375  }
376  while (!convergence && run < MaxIterations);
377  iterations += run;
378 
379  // not yet converged, so decreased the source-step
380  if (run >= MaxIterations || error)
381  {
382  if (error)
383  sStep *= 0.1;
384  else
385  sStep *= 0.5;
386  restorePreviousIteration ();
387  saveSolution ();
388  // here the absolute minimum step checker
389  if (sStep < NR_EPSI)
390  {
391  error = 1;
393  e->setText ("no convergence in %s analysis after %d sourceStepping "
394  "iterations", desc, iterations);
395  throw_exception (e);
396  break;
397  }
398  srcFactor = MIN (sPrev + sStep, 1);
399  }
400  // converged, increased the source-step
401  else if (run < MaxIterations / 4)
402  {
403  sPrev = srcFactor;
404  srcFactor = MIN (srcFactor + sStep, 1);
405  sStep *= 1.5;
406  }
407  else
408  {
409  srcFactor = MIN (srcFactor + sStep, 1);
410  }
411  }
412  // continue until no source factor is necessary
413  while (sPrev < 1);
414 
415  subnet->setSrcFactor (1);
416  return error;
417 }
418 
419 /* The function returns an appropriate text representation for the
420  currently used convergence helper algorithm. */
421 template <class nr_type_t>
423 {
424  if (convHelper == CONV_Attenuation)
425  {
426  return "RHS attenuation";
427  }
428  else if (convHelper == CONV_LineSearch)
429  {
430  return "line search";
431  }
432  else if (convHelper == CONV_SteepestDescent)
433  {
434  return "steepest descent";
435  }
436  else if (convHelper == CONV_GMinStepping)
437  {
438  return "gMin stepping";
439  }
440  else if (convHelper == CONV_SourceStepping)
441  {
442  return "source stepping";
443  }
444  return "none";
445 }
446 
447 /* This is the non-linear iterative nodal analysis netlist solver. */
448 template <class nr_type_t>
450 {
451  qucs::exception * e;
452  int convergence, run = 0, MaxIterations, error = 0;
453 
454  // fetch simulation properties
455  MaxIterations = getPropertyInteger ("MaxIter");
456  reltol = getPropertyDouble ("reltol");
457  abstol = getPropertyDouble ("abstol");
458  vntol = getPropertyDouble ("vntol");
459  updateMatrix = 1;
460 
461  if (convHelper == CONV_GMinStepping)
462  {
463  // use the alternative non-linear solver solve_nonlinear_continuation_gMin
464  // instead of the basic solver provided by this function
465  iterations = 0;
466  error = solve_nonlinear_continuation_gMin ();
467  return error;
468  }
469  else if (convHelper == CONV_SourceStepping)
470  {
471  // use the alternative non-linear solver solve_nonlinear_continuation_Source
472  // instead of the basic solver provided by this function
473  iterations = 0;
474  error = solve_nonlinear_continuation_Source ();
475  return error;
476  }
477 
478  // run solving loop until convergence is reached
479  do
480  {
481  error = solve_once ();
482  if (!error)
483  {
484  // convergence check
485  convergence = (run > 0) ? checkConvergence () : 0;
486  savePreviousIteration ();
487  run++;
488  // control fixpoint iterations
489  if (fixpoint)
490  {
491  if (convergence && !updateMatrix)
492  {
493  updateMatrix = 1;
494  convergence = 0;
495  }
496  else
497  {
498  updateMatrix = 0;
499  }
500  }
501  }
502  else
503  {
504  break;
505  }
506  }
507  while (!convergence &&
508  run < MaxIterations * (1 + convHelper ? 1 : 0));
509 
510  if (run >= MaxIterations || error)
511  {
513  e->setText ("no convergence in %s analysis after %d iterations",
514  desc, run);
515  throw_exception (e);
516  error++;
517  }
518 
519  iterations = run;
520  return error;
521 }
522 
523 /* This is the linear nodal analysis netlist solver. */
524 template <class nr_type_t>
526 {
527  updateMatrix = 1;
528  return solve_once ();
529 }
530 
531 /* Applying the MNA (Modified Nodal Analysis) to a circuit with
532  passive elements and independent current and voltage sources
533  results in a matrix equation of the form Ax = z. This function
534  generates the A and z matrix. */
535 template <class nr_type_t>
537 {
538 
539  /* Generate the A matrix. The A matrix consists of four (4) minor
540  matrices in the form +- -+
541  A = | G B |
542  | C D |
543  +- -+.
544  Each of these minor matrices is going to be generated here. */
545  if (updateMatrix)
546  {
547  createGMatrix ();
548  createBMatrix ();
549  createCMatrix ();
550  createDMatrix ();
551  }
552 
553  /* Adjust G matrix if requested. */
554  if (convHelper == CONV_GMinStepping)
555  {
556  int N = countNodes ();
557  int M = countVoltageSources ();
558  for (int n = 0; n < N + M; n++)
559  {
560  A->set (n, n, A->get (n, n) + gMin);
561  }
562  }
563 
564  /* Generate the z Matrix. The z Matrix consists of two (2) minor
565  matrices in the form +- -+
566  z = | i |
567  | e |
568  +- -+.
569  Each of these minor matrices is going to be generated here. */
570  createZVector ();
571 }
572 
573 /* This MatVal() functionality is just helper to get the correct
574  values from the circuit's matrices. The additional (unused)
575  argument is used to differentiate between the two possible
576  types. */
577 #define MatVal(x) MatValX (x, (nr_type_t *) 0)
578 
579 template <class nr_type_t>
581 {
582  return z;
583 }
584 
585 template <class nr_type_t>
586 nr_type_t nasolver<nr_type_t>::MatValX (nr_complex_t z, nr_double_t *)
587 {
588  return real (z);
589 }
590 
591 /* The B matrix is an MxN matrix with only 0, 1 and -1 elements. Each
592  location in the matrix corresponds to a particular voltage source
593  (first dimension) or a node (second dimension). If the positive
594  terminal of the ith voltage source is connected to node k, then the
595  element (i,k) in the B matrix is a 1. If the negative terminal of
596  the ith voltage source is connected to node k, then the element
597  (i,k) in the B matrix is a -1. Otherwise, elements of the B matrix
598  are zero. */
599 template <class nr_type_t>
601 {
602  int N = countNodes ();
603  int M = countVoltageSources ();
604  circuit * vs;
605  struct nodelist_t * n;
606  nr_type_t val;
607 
608  // go through each voltage sources (first dimension)
609  for (int c = 0; c < M; c++)
610  {
611  vs = findVoltageSource (c);
612  // go through each node (second dimension)
613  for (int r = 0; r < N; r++)
614  {
615  val = 0.0;
616  n = nlist->getNode (r);
617  for (int i = 0; i < n->nNodes; i++)
618  {
619  // is voltage source connected to node ?
620  if (n->nodes[i]->getCircuit () == vs)
621  {
622  val += MatVal (vs->getB (n->nodes[i]->getPort (), c));
623  }
624  }
625  // put value into B matrix
626  A->set (r, c + N, val);
627  }
628  }
629 }
630 
631 /* The C matrix is an NxM matrix with only 0, 1 and -1 elements. Each
632  location in the matrix corresponds to a particular node (first
633  dimension) or a voltage source (first dimension). If the positive
634  terminal of the ith voltage source is connected to node k, then the
635  element (k,i) in the C matrix is a 1. If the negative terminal of
636  the ith voltage source is connected to node k, then the element
637  (k,i) in the C matrix is a -1. Otherwise, elements of the C matrix
638  are zero. */
639 template <class nr_type_t>
641 {
642  int N = countNodes ();
643  int M = countVoltageSources ();
644  circuit * vs;
645  struct nodelist_t * n;
646  nr_type_t val;
647 
648  // go through each voltage sources (second dimension)
649  for (int r = 0; r < M; r++)
650  {
651  vs = findVoltageSource (r);
652  // go through each node (first dimension)
653  for (int c = 0; c < N; c++)
654  {
655  val = 0.0;
656  n = nlist->getNode (c);
657  for (int i = 0; i < n->nNodes; i++)
658  {
659  // is voltage source connected to node ?
660  if (n->nodes[i]->getCircuit () == vs)
661  {
662  val += MatVal (vs->getC (r, n->nodes[i]->getPort ()));
663  }
664  }
665  // put value into C matrix
666  A->set (r + N, c, val);
667  }
668  }
669 }
670 
671 /* The D matrix is an MxM matrix that is composed entirely of zeros.
672  It can be non-zero if dependent sources are considered. */
673 template <class nr_type_t>
675 {
676  int M = countVoltageSources ();
677  int N = countNodes ();
678  circuit * vsr, * vsc;
679  nr_type_t val;
680  for (int r = 0; r < M; r++)
681  {
682  vsr = findVoltageSource (r);
683  for (int c = 0; c < M; c++)
684  {
685  vsc = findVoltageSource (c);
686  val = 0.0;
687  if (vsr == vsc)
688  {
689  val = MatVal (vsr->getD (r, c));
690  }
691  A->set (r + N, c + N, val);
692  }
693  }
694 }
695 
696 /* The G matrix is an NxN matrix formed in two steps.
697  1. Each element in the diagonal matrix is equal to the sum of the
698  conductance of each element connected to the corresponding node.
699  2. The off diagonal elements are the negative conductance of the
700  element connected to the pair of corresponding nodes. Therefore a
701  resistor between nodes 1 and 2 goes into the G matrix at location
702  (1,2) and location (2,1). If an element is grounded, it will only
703  have contribute to one entry in the G matrix -- at the appropriate
704  location on the diagonal. */
705 template <class nr_type_t>
707 {
708  int pr, pc, N = countNodes ();
709  nr_type_t g;
710  struct nodelist_t * nr, * nc;
711  circuit * ct;
712 
713  // go through each column of the G matrix
714  for (int c = 0; c < N; c++)
715  {
716  nc = nlist->getNode (c);
717  // go through each row of the G matrix
718  for (int r = 0; r < N; r++)
719  {
720  nr = nlist->getNode (r);
721  g = 0.0;
722  // sum up the conductance of each connected circuit
723  for (int a = 0; a < nc->nNodes; a++)
724  for (int b = 0; b < nr->nNodes; b++)
725  if (nc->nodes[a]->getCircuit () == nr->nodes[b]->getCircuit ())
726  {
727  ct = nc->nodes[a]->getCircuit ();
728  pc = nc->nodes[a]->getPort ();
729  pr = nr->nodes[b]->getPort ();
730  g += MatVal (ct->getY (pr, pc));
731  }
732  // put value into G matrix
733  A->set (r, c, g);
734  }
735  }
736 }
737 
738 /* The following function creates the (N+M)x(N+M) noise current
739  correlation matrix used during the AC noise computations. */
740 template <class nr_type_t>
742 {
743  int pr, pc, N = countNodes ();
744  int M = countVoltageSources ();
745  struct nodelist_t * n;
746  nr_type_t val;
747  int r, c, a, b, ri, ci, i;
748  struct nodelist_t * nr, * nc;
749  circuit * ct;
750 
751  // create new Cy matrix if necessary
752  if (C != NULL) delete C;
753  C = new tmatrix<nr_type_t> (N + M);
754 
755  // go through each column of the Cy matrix
756  for (c = 0; c < N; c++)
757  {
758  nc = nlist->getNode (c);
759  // go through each row of the Cy matrix
760  for (r = 0; r < N; r++)
761  {
762  nr = nlist->getNode (r);
763  val = 0.0;
764  // sum up the noise-correlation of each connected circuit
765  for (a = 0; a < nc->nNodes; a++)
766  for (b = 0; b < nr->nNodes; b++)
767  if (nc->nodes[a]->getCircuit () == nr->nodes[b]->getCircuit ())
768  {
769  ct = nc->nodes[a]->getCircuit ();
770  pc = nc->nodes[a]->getPort ();
771  pr = nr->nodes[b]->getPort ();
772  val += MatVal (ct->getN (pr, pc));
773  }
774  // put value into Cy matrix
775  C->set (r, c, val);
776  }
777  }
778 
779  // go through each additional voltage source and put coefficients into
780  // the noise current correlation matrix
781  circuit * vsr, * vsc;
782  for (r = 0; r < M; r++)
783  {
784  vsr = findVoltageSource (r);
785  for (c = 0; c < M; c++)
786  {
787  vsc = findVoltageSource (c);
788  val = 0.0;
789  if (vsr == vsc)
790  {
791  ri = vsr->getSize () + r - vsr->getVoltageSource ();
792  ci = vsc->getSize () + c - vsc->getVoltageSource ();
793  val = MatVal (vsr->getN (ri, ci));
794  }
795  C->set (r + N, c + N, val);
796  }
797  }
798 
799  // go through each additional voltage source
800  for (r = 0; r < M; r++)
801  {
802  vsr = findVoltageSource (r);
803  // go through each node
804  for (c = 0; c < N; c++)
805  {
806  val = 0.0;
807  n = nlist->getNode (c);
808  for (i = 0; i < n->nNodes; i++)
809  {
810  // is voltage source connected to node ?
811  if (n->nodes[i]->getCircuit () == vsr)
812  {
813  ri = vsr->getSize () + r - vsr->getVoltageSource ();
814  ci = n->nodes[i]->getPort ();
815  val += MatVal (vsr->getN (ri, ci));
816  }
817  }
818  // put value into Cy matrix
819  C->set (r + N, c, val);
820  }
821  }
822 
823  // go through each voltage source
824  for (c = 0; c < M; c++)
825  {
826  vsc = findVoltageSource (c);
827  // go through each node
828  for (r = 0; r < N; r++)
829  {
830  val = 0.0;
831  n = nlist->getNode (r);
832  for (i = 0; i < n->nNodes; i++)
833  {
834  // is voltage source connected to node ?
835  if (n->nodes[i]->getCircuit () == vsc)
836  {
837  ci = vsc->getSize () + c - vsc->getVoltageSource ();
838  ri = n->nodes[i]->getPort ();
839  val += MatVal (vsc->getN (ri, ci));
840  }
841  }
842  // put value into Cy matrix
843  C->set (r, c + N, val);
844  }
845  }
846 
847 }
848 
849 /* The i matrix is an 1xN matrix with each element of the matrix
850  corresponding to a particular node. The value of each element of i
851  is determined by the sum of current sources into the corresponding
852  node. If there are no current sources connected to the node, the
853  value is zero. */
854 template <class nr_type_t>
856 {
857  int N = countNodes ();
858  nr_type_t val;
859  struct nodelist_t * n;
860  circuit * is;
861 
862  // go through each node
863  for (int r = 0; r < N; r++)
864  {
865  val = 0.0;
866  n = nlist->getNode (r);
867  // go through each circuit connected to the node
868  for (int i = 0; i < n->nNodes; i++)
869  {
870  is = n->nodes[i]->getCircuit ();
871  // is this a current source ?
872  if (is->isISource () || is->isNonLinear ())
873  {
874  val += MatVal (is->getI (n->nodes[i]->getPort ()));
875  }
876  }
877  // put value into i vector
878  z->set (r, val);
879  }
880 }
881 
882 /* The e matrix is a 1xM matrix with each element of the matrix equal
883  in value to the corresponding independent voltage source. */
884 template <class nr_type_t>
886 {
887  int N = countNodes ();
888  int M = countVoltageSources ();
889  nr_type_t val;
890  circuit * vs;
891 
892  // go through each voltage source
893  for (int r = 0; r < M; r++)
894  {
895  vs = findVoltageSource (r);
896  val = MatVal (vs->getE (r));
897  // put value into e vector
898  z->set (r + N, val);
899  }
900 }
901 
902 // The function loads the right hand side vector.
903 template <class nr_type_t>
905 {
906  createIVector ();
907  createEVector ();
908 }
909 
910 // Returns the number of nodes in the nodelist, excluding the ground node.
911 template <class nr_type_t>
913 {
914  return nlist->length () - 1;
915 }
916 
917 // Returns the node number of the give node name.
918 template <class nr_type_t>
920 {
921  return nlist->getNodeNr (str);
922 }
923 
924 /* The function returns the assigned node number for the port of the
925  given circuits. It returns -1 if there is no such node. */
926 template <class nr_type_t>
928 {
929  int N = countNodes ();
930  struct nodelist_t * n;
931  for (int r = 0; r < N; r++)
932  {
933  n = nlist->getNode (r);
934  for (int i = 0; i < n->nNodes; i++)
935  if (c == n->nodes[i]->getCircuit ())
936  if (port == n->nodes[i]->getPort ())
937  return r;
938  }
939  return -1;
940 }
941 
942 // Returns the number of voltage sources in the nodelist.
943 template <class nr_type_t>
945 {
946  return subnet->getVoltageSources ();
947 }
948 
949 /* The function returns the voltage source circuit object
950  corresponding to the given number. If there is no such voltage
951  source it returns NULL. */
952 template <class nr_type_t>
954 {
955  circuit * root = subnet->getRoot ();
956  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
957  {
958  if (n >= c->getVoltageSource () &&
959  n <= c->getVoltageSource () + c->getVoltageSources () - 1)
960  return c;
961  }
962  return NULL;
963 }
964 
965 /* The function applies unique voltage source identifiers to each
966  voltage source (explicit and built in internal ones) in the list of
967  registered circuits. */
968 template <class nr_type_t>
970 {
971  circuit * root = subnet->getRoot ();
972  int nSources = 0;
973  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
974  {
975  if (c->getVoltageSources () > 0)
976  {
977  c->setVoltageSource (nSources);
978  nSources += c->getVoltageSources ();
979  }
980  }
981  subnet->setVoltageSources (nSources);
982 }
983 
984 /* The matrix equation Ax = z is solved by x = A^-1*z. The function
985  applies the operation to the previously generated matrices. */
986 template <class nr_type_t>
988 {
989 
990  // just solve the equation system here
991  eqns->setAlgo (eqnAlgo);
992  eqns->passEquationSys (updateMatrix ? A : NULL, x, z);
993  eqns->solve ();
994 
995  // if damped Newton-Raphson is requested
996  if (xprev != NULL && top_exception () == NULL)
997  {
998  if (convHelper == CONV_Attenuation)
999  {
1000  applyAttenuation ();
1001  }
1002  else if (convHelper == CONV_LineSearch)
1003  {
1004  lineSearch ();
1005  }
1006  else if (convHelper == CONV_SteepestDescent)
1007  {
1008  steepestDescent ();
1009  }
1010  }
1011 }
1012 
1013 /* This function applies a damped Newton-Raphson (limiting scheme) to
1014  the current solution vector in the form x1 = x0 + a * (x1 - x0). This
1015  convergence helper is heuristic and does not ensure global convergence. */
1016 template <class nr_type_t>
1018 {
1019  nr_double_t alpha = 1.0, nMax;
1020 
1021  // create solution difference vector and find maximum deviation
1022  tvector<nr_type_t> dx = *x - *xprev;
1023  nMax = maxnorm (dx);
1024 
1025  // compute appropriate damping factor
1026  if (nMax > 0.0)
1027  {
1028  nr_double_t g = 1.0;
1029  alpha = MIN (0.9, g / nMax);
1030  if (alpha < 0.1) alpha = 0.1;
1031  }
1032 
1033  // apply damped solution vector
1034  *x = *xprev + alpha * dx;
1035 }
1036 
1037 /* This is damped Newton-Raphson using nested iterations in order to
1038  find a better damping factor. It identifies a damping factor in
1039  the interval [0,1] which minimizes the right hand side vector. The
1040  algorithm actually ensures global convergence but pushes the
1041  solution to local minimums, i.e. where the Jacobian matrix A may be
1042  singular. */
1043 template <class nr_type_t>
1045 {
1046  nr_double_t alpha = 0.5, n, nMin, aprev = 1.0, astep = 0.5, adiff;
1047  int dir = -1;
1048 
1049  // compute solution deviation vector
1050  tvector<nr_type_t> dx = *x - *xprev;
1051  nMin = NR_MAX;
1052 
1053  do
1054  {
1055  // apply current damping factor and see what happens
1056  *x = *xprev + alpha * dx;
1057 
1058  // recalculate Jacobian and right hand side
1059  saveSolution ();
1060  calculate ();
1061  createZVector ();
1062 
1063  // calculate norm of right hand side vector
1064  n = norm (*z);
1065 
1066  // TODO: this is not perfect, but usable
1067  astep /= 2;
1068  adiff = fabs (alpha - aprev);
1069  if (adiff > 0.005)
1070  {
1071  aprev = alpha;
1072  if (n < nMin)
1073  {
1074  nMin = n;
1075  if (alpha == 1) dir = -dir;
1076  alpha += astep * dir;
1077  }
1078  else
1079  {
1080  dir = -dir;
1081  alpha += 1.5 * astep * dir;
1082  }
1083  }
1084  }
1085  while (adiff > 0.005);
1086 
1087  // apply final damping factor
1088  assert (alpha > 0 && alpha <= 1);
1089  *x = *xprev + alpha * dx;
1090 }
1091 
1092 /* The function looks for the optimal gradient for the right hand side
1093  vector using the so-called 'steepest descent' method. Though
1094  better than the one-dimensional linesearch (it doesn't push
1095  iterations into local minimums) it converges painfully slow. */
1096 template <class nr_type_t>
1098 {
1099  nr_double_t alpha = 1.0, sl, n;
1100 
1101  // compute solution deviation vector
1102  tvector<nr_type_t> dx = *x - *xprev;
1103  tvector<nr_type_t> dz = *z - *zprev;
1104  n = norm (*zprev);
1105 
1106  do
1107  {
1108  // apply current damping factor and see what happens
1109  *x = *xprev + alpha * dx;
1110 
1111  // recalculate Jacobian and right hand side
1112  saveSolution ();
1113  calculate ();
1114  createZVector ();
1115 
1116  // check gradient criteria, ThinkME: Is this correct?
1117  dz = *z - *zprev;
1118  sl = real (sum (dz * -dz));
1119  if (norm (*z) < n + alpha * sl) break;
1120  alpha *= 0.7;
1121  }
1122  while (alpha > 0.001);
1123 
1124  // apply final damping factor
1125  *x = *xprev + alpha * dx;
1126 }
1127 
1128 /* The function checks whether the iterative algorithm for linearizing
1129  the non-linear components in the network shows convergence. It
1130  returns non-zero if it converges and zero otherwise. */
1131 template <class nr_type_t>
1133 {
1134 
1135  int N = countNodes ();
1136  int M = countVoltageSources ();
1137  nr_double_t v_abs, v_rel, i_abs, i_rel;
1138  int r;
1139 
1140  // check the nodal voltage changes against the allowed absolute
1141  // and relative tolerance values
1142  for (r = 0; r < N; r++)
1143  {
1144  v_abs = abs (x->get (r) - xprev->get (r));
1145  v_rel = abs (x->get (r));
1146  if (v_abs >= vntol + reltol * v_rel) return 0;
1147  if (!convHelper)
1148  {
1149  i_abs = abs (z->get (r) - zprev->get (r));
1150  i_rel = abs (z->get (r));
1151  if (i_abs >= abstol + reltol * i_rel) return 0;
1152  }
1153  }
1154 
1155  for (r = 0; r < M; r++)
1156  {
1157  i_abs = abs (x->get (r + N) - xprev->get (r + N));
1158  i_rel = abs (x->get (r + N));
1159  if (i_abs >= abstol + reltol * i_rel) return 0;
1160  if (!convHelper)
1161  {
1162  v_abs = abs (z->get (r + N) - zprev->get (r + N));
1163  v_rel = abs (z->get (r + N));
1164  if (v_abs >= vntol + reltol * v_rel) return 0;
1165  }
1166  }
1167  return 1;
1168 }
1169 
1170 /* The function saves the solution and right hand vector of the previous
1171  iteration. */
1172 template <class nr_type_t>
1174 {
1175  if (xprev != NULL)
1176  *xprev = *x;
1177  else
1178  xprev = new tvector<nr_type_t> (*x);
1179  if (zprev != NULL)
1180  *zprev = *z;
1181  else
1182  zprev = new tvector<nr_type_t> (*z);
1183 }
1184 
1185 /* The function restores the solution and right hand vector of the
1186  previous (successful) iteration. */
1187 template <class nr_type_t>
1189 {
1190  if (xprev != NULL) *x = *xprev;
1191  if (zprev != NULL) *z = *zprev;
1192 }
1193 
1194 /* The function restarts the NR iteration for each non-linear
1195  circuit. */
1196 template <class nr_type_t>
1198 {
1199  circuit * root = subnet->getRoot ();
1200  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
1201  {
1202  if (c->isNonLinear ()) c->restartDC ();
1203  }
1204 }
1205 
1206 /* This function goes through solution (the x vector) and saves the
1207  node voltages of the last iteration into each non-linear
1208  circuit. */
1209 template <class nr_type_t>
1211 {
1212  int N = countNodes ();
1213  struct nodelist_t * n;
1214  // save all nodes except reference node
1215  for (int r = 0; r < N; r++)
1216  {
1217  n = nlist->getNode (r);
1218  for (int i = 0; i < n->nNodes; i++)
1219  {
1220  n->nodes[i]->getCircuit()->setV (n->nodes[i]->getPort (), x->get (r));
1221  }
1222  }
1223  // save reference node
1224  n = nlist->getNode (-1);
1225  for (int i = 0; i < n->nNodes; i++)
1226  {
1227  n->nodes[i]->getCircuit()->setV (n->nodes[i]->getPort (), 0.0);
1228  }
1229 }
1230 
1231 /* This function goes through solution (the x vector) and saves the
1232  branch currents through the voltage sources of the last iteration
1233  into each circuit. */
1234 template <class nr_type_t>
1236 {
1237  int N = countNodes ();
1238  int M = countVoltageSources ();
1239  circuit * vs;
1240  // save all branch currents of voltage sources
1241  for (int r = 0; r < M; r++)
1242  {
1243  vs = findVoltageSource (r);
1244  vs->setJ (r, x->get (r + N));
1245  }
1246 }
1247 
1248 // The function saves the solution vector into each circuit.
1249 template <class nr_type_t>
1251 {
1252  saveNodeVoltages ();
1253  saveBranchCurrents ();
1254 }
1255 
1256 // This function stores the solution (node voltages and branch currents).
1257 template <class nr_type_t>
1259 {
1260  // cleanup solution previously
1261  solution.clear ();
1262  int r;
1263  int N = countNodes ();
1264  int M = countVoltageSources ();
1265  // store all nodes except reference node
1266  for (r = 0; r < N; r++)
1267  {
1268  struct nodelist_t * n = nlist->getNode (r);
1269  solution.add (n->name, x->get (r), 0);
1270  }
1271  // store all branch currents of voltage sources
1272  for (r = 0; r < M; r++)
1273  {
1274  circuit * vs = findVoltageSource (r);
1275  int vn = r - vs->getVoltageSource () + 1;
1276  solution.add (vs->getName (), x->get (r + N), vn);
1277  }
1278 }
1279 
1280 // This function recalls the solution (node voltages and branch currents).
1281 template <class nr_type_t>
1283 {
1284  int r;
1285  int N = countNodes ();
1286  int M = countVoltageSources ();
1287  naentry<nr_type_t> * na;
1288  // store all nodes except reference node
1289  for (r = 0; r < N; r++)
1290  {
1291  struct nodelist_t * n = nlist->getNode (r);
1292  if ((na = solution.find (n->name, 0)) != NULL)
1293  x->set (r, na->value);
1294  }
1295  // store all branch currents of voltage sources
1296  for (r = 0; r < M; r++)
1297  {
1298  circuit * vs = findVoltageSource (r);
1299  int vn = r - vs->getVoltageSource () + 1;
1300  if ((na = solution.find (vs->getName (), vn)) != NULL)
1301  x->set (r + N, na->value);
1302  }
1303 }
1304 
1305 /* This function saves the results of a single solve() functionality
1306  into the output dataset. */
1307 template <class nr_type_t>
1308 void nasolver<nr_type_t>::saveResults (const char * volts, const char * amps,
1309  int saveOPs, qucs::vector * f)
1310 {
1311  int N = countNodes ();
1312  int M = countVoltageSources ();
1313  char * n;
1314 
1315  // add node voltage variables
1316  if (volts)
1317  {
1318  for (int r = 0; r < N; r++)
1319  {
1320  if ((n = createV (r, volts, saveOPs)) != NULL)
1321  {
1322  saveVariable (n, x->get (r), f);
1323  free (n);
1324  }
1325  }
1326  }
1327 
1328  // add branch current variables
1329  if (amps)
1330  {
1331  for (int r = 0; r < M; r++)
1332  {
1333  if ((n = createI (r, amps, saveOPs)) != NULL)
1334  {
1335  saveVariable (n, x->get (r + N), f);
1336  free (n);
1337  }
1338  }
1339  }
1340 
1341  // add voltage probe data
1342  if (volts)
1343  {
1344  circuit * root = subnet->getRoot ();
1345  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
1346  {
1347  if (!c->isProbe ()) continue;
1348  if (c->getSubcircuit () && !(saveOPs & SAVE_ALL)) continue;
1349  if (strcmp (volts, "vn"))
1350  c->saveOperatingPoints ();
1351  n = createOP (c->getName (), volts);
1352  saveVariable (n, nr_complex_t (c->getOperatingPoint ("Vr"),
1353  c->getOperatingPoint ("Vi")), f);
1354  free (n);
1355  }
1356  }
1357 
1358  // save operating points of non-linear circuits if requested
1359  if (saveOPs & SAVE_OPS)
1360  {
1361  circuit * root = subnet->getRoot ();
1362  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ())
1363  {
1364  if (!c->isNonLinear ()) continue;
1365  if (c->getSubcircuit () && !(saveOPs & SAVE_ALL)) continue;
1366  c->calcOperatingPoints ();
1367  valuelistiterator<operatingpoint> it (c->getOperatingPoints ());
1368  for (; *it; ++it)
1369  {
1370  operatingpoint * p = it.currentVal ();
1371  n = createOP (c->getName (), p->getName ());
1372  saveVariable (n, p->getValue (), f);
1373  free (n);
1374  }
1375  }
1376  }
1377 }
1378 
1379 /* Create an appropriate variable name for operating points. The
1380  caller is responsible to free() the returned string. */
1381 template <class nr_type_t>
1382 char * nasolver<nr_type_t>::createOP (const char * c, const char * n)
1383 {
1384  char * text = (char *) malloc (strlen (c) + strlen (n) + 2);
1385  sprintf (text, "%s.%s", c, n);
1386  return text;
1387 }
1388 
1389 /* Creates an appropriate variable name for voltages. The caller is
1390  responsible to free() the returned string. */
1391 template <class nr_type_t>
1392 char * nasolver<nr_type_t>::createV (int n, const char * volts, int saveOPs)
1393 {
1394  if (nlist->isInternal (n)) return NULL;
1395  char * node = nlist->get (n);
1396  if (strchr (node, '.') && !(saveOPs & SAVE_ALL)) return NULL;
1397  char * text = (char *) malloc (strlen (node) + 2 + strlen (volts));
1398  sprintf (text, "%s.%s", node, volts);
1399  return text;
1400 }
1401 
1402 /* Create an appropriate variable name for currents. The caller is
1403  responsible to free() the returned string. */
1404 template <class nr_type_t>
1405 char * nasolver<nr_type_t>::createI (int n, const char * amps, int saveOPs)
1406 {
1407  circuit * vs = findVoltageSource (n);
1408 
1409  // don't output internal (helper) voltage sources
1410  if (vs->isInternalVoltageSource ())
1411  return NULL;
1412 
1413  /* save only current through real voltage sources and explicit
1414  current probes */
1415  if (!vs->isVSource () && !(saveOPs & SAVE_OPS))
1416  return NULL;
1417 
1418  // don't output subcircuit components if not requested
1419  if (vs->getSubcircuit () && !(saveOPs & SAVE_ALL))
1420  return NULL;
1421 
1422  // create appropriate current name for single/multiple voltage sources
1423  char * name = vs->getName ();
1424  char * text = (char *) malloc (strlen (name) + 4 + strlen (amps));
1425  if (vs->getVoltageSources () > 1)
1426  sprintf (text, "%s.%s%d", name, amps, n - vs->getVoltageSource () + 1);
1427  else
1428  sprintf (text, "%s.%s", name, amps);
1429  return text;
1430 }
1431 
1432 
1433 /* Alternaive to countNodes () */
1434 template <class nr_type_t>
1436 {
1437  return countNodes ();
1438 }
1439 
1440 /* Alternative to countVoltageSources () */
1441 template <class nr_type_t>
1443 {
1444  return countVoltageSources ();
1445 }
1446 
1447 } // namespace qucs
std::complex< nr_double_t > nr_complex_t
Definition: complex.h:31
exceptionstack estack
matrix real(matrix a)
Real part matrix.
Definition: matrix.cpp:568
matrix abs(matrix a)
Computes magnitude of each matrix element.
Definition: matrix.cpp:531
#define N(n)
Definition: equation.cpp:58
name
Definition: parse_mdl.y:352
void createMatrix(void)
Definition: nasolver.cpp:536
int updateMatrix
Definition: nasolver.h:131
void recallSolution(void)
Definition: nasolver.cpp:1282
int getN()
Returns the number of node voltages in the circuit.
Definition: nasolver.cpp:1435
nodelist * nlist
Definition: nasolver.h:134
#define C(c)
Definition: eqndefined.cpp:73
void applyNodeset(bool nokeep=true)
Definition: nasolver.cpp:247
nr_double_t vntol
Definition: nasolver.h:140
#define CONV_GMinStepping
Definition: nasolver.h:40
int solve_nonlinear_continuation_gMin(void)
Definition: nasolver.cpp:275
nr_complex_t sum(vector)
Definition: vector.cpp:251
void restorePreviousIteration(void)
Definition: nasolver.cpp:1188
char * createV(int, const char *, int)
Definition: nasolver.cpp:1392
bool isInternalVoltageSource(void)
Definition: circuit.h:185
Global physical constants header file.
void createGMatrix(void)
Definition: nasolver.cpp:706
void runMNA(void)
Definition: nasolver.cpp:987
int countNodes(void)
Definition: nasolver.cpp:912
int getVoltageSource(void)
Definition: circuit.h:187
eqnsys< nr_type_t > * eqns
Definition: nasolver.h:137
#define catch_exception()
n
Definition: parse_citi.y:147
r
Definition: parse_mdl.y:515
nr_complex_t getN(int, int)
Definition: circuit.cpp:592
tmatrix< nr_type_t > * A
Definition: nasolver.h:125
nr_type_t value
Definition: nasolution.h:45
tmatrix< nr_type_t > * C
Definition: nasolver.h:126
void setJ(int, nr_complex_t)
Definition: circuit.cpp:430
int getSize(void)
Get the number of ports the circuit element has.
Definition: circuit.h:143
#define throw_exception(e)
#define try_running()
void storeSolution(void)
Definition: nasolver.cpp:1258
nr_double_t maxnorm(tvector< nr_type_t > a)
Definition: tvector.cpp:387
i
Definition: parse_mdl.y:516
nr_type_t MatValX(nr_complex_t, nr_complex_t *)
Definition: nasolver.cpp:580
int getVoltageSources(void)
Definition: circuit.cpp:602
#define CONV_Attenuation
Definition: nasolver.h:37
nr_complex_t getC(int, int)
Definition: circuit.cpp:355
#define pop_exception()
void createCMatrix(void)
Definition: nasolver.cpp:640
base class for qucs circuit elements.
Definition: circuit.h:92
void createIVector(void)
Definition: nasolver.cpp:855
void solve_pre(void)
Definition: nasolver.cpp:213
char * getSubcircuit(void)
Definition: circuit.h:176
node ** nodes
Definition: nodelist.h:36
tvector< nr_type_t > * zprev
Definition: nasolver.h:124
nasolution< nr_type_t > solution
Definition: nasolver.h:141
nr_complex_t getI(int)
Definition: circuit.cpp:391
void saveResults(const char *, const char *, int, qucs::vector *f=NULL)
Definition: nasolver.cpp:1308
void createEVector(void)
Definition: nasolver.cpp:885
free($1)
int solve_once(void)
Definition: nasolver.cpp:138
tvector< nr_type_t > * z
Definition: nasolver.h:121
bool isNonLinear(void)
Definition: circuit.h:299
The analysis class header file.
void applyAttenuation(void)
Definition: nasolver.cpp:1017
x
Definition: parse_mdl.y:498
circuit * findVoltageSource(int)
Definition: nasolver.cpp:953
nr_complex_t getE(int)
Definition: circuit.cpp:379
void print(const char *prefix=NULL)
int solve_linear(void)
Definition: nasolver.cpp:525
The circuit class header file.
int solve_nonlinear(void)
Definition: nasolver.cpp:449
const char * desc
Definition: nasolver.h:133
#define MatVal(x)
Definition: nasolver.cpp:577
bool isISource(void)
Definition: circuit.h:193
#define top_exception()
nr_complex_t getD(int, int)
Definition: circuit.cpp:367
#define CONV_SourceStepping
Definition: nasolver.h:41
char * getName(void)
Definition: pair.cpp:76
calculate_func_t calculate_func
Definition: nasolver.h:145
tvector< nr_type_t > * xprev
Definition: nasolver.h:123
int countVoltageSources(void)
Definition: nasolver.cpp:944
#define SAVE_OPS
Definition: analysis.h:36
#define MIN(x, y)
Minimum of x and y.
Definition: constants.h:132
void saveNodeVoltages(void)
Definition: nasolver.cpp:1210
const char * getHelperDescription(void)
Definition: nasolver.cpp:422
#define CONV_LineSearch
Definition: nasolver.h:38
eqns
nr_complex_t getB(int, int)
Definition: circuit.cpp:343
nr_double_t norm(const nr_complex_t z)
Compute euclidian norm of complex number.
Definition: complex.cpp:283
void createDMatrix(void)
Definition: nasolver.cpp:674
void saveBranchCurrents(void)
Definition: nasolver.cpp:1235
void lineSearch(void)
Definition: nasolver.cpp:1044
#define A(a)
Definition: eqndefined.cpp:72
nr_double_t getValue(void)
Definition: pair.h:41
void setText(const char *,...)
Definition: exception.cpp:67
void createNoiseMatrix(void)
Definition: nasolver.cpp:741
char * createI(int, const char *, int)
Definition: nasolver.cpp:1405
#define strchr
Definition: compat.h:33
int checkConvergence(void)
Definition: nasolver.cpp:1132
void assignVoltageSources(void)
Definition: nasolver.cpp:969
#define LOG_ERROR
Definition: logging.h:28
char * getName(void)
Definition: object.cpp:84
nr_double_t srcFactor
Definition: nasolver.h:132
char * createOP(const char *, const char *)
Definition: nasolver.cpp:1382
int getM()
Returns the number of branch currents in the circuit.
Definition: nasolver.cpp:1442
void solve_post(void)
Definition: nasolver.cpp:205
#define LOG_STATUS
Definition: logging.h:29
nr_complex_t getY(int, int)
Definition: circuit.cpp:446
void saveSolution(void)
Definition: nasolver.cpp:1250
#define CONV_SteepestDescent
Definition: nasolver.h:39
nr_double_t reltol
Definition: nasolver.h:138
void savePreviousIteration(void)
Definition: nasolver.cpp:1173
#define M(con)
Definition: evaluate.cpp:64
void logprint(int level, const char *format,...)
Definition: logging.c:37
tvector< nr_type_t > * x
Definition: nasolver.h:122
void createZVector(void)
Definition: nasolver.cpp:904
int getNodeNr(char *)
Definition: nasolver.cpp:919
void restartNR(void)
Definition: nasolver.cpp:1197
int findAssignedNode(circuit *, int)
Definition: nasolver.cpp:927
#define SAVE_ALL
Definition: analysis.h:37
void createBMatrix(void)
Definition: nasolver.cpp:600
void steepestDescent(void)
Definition: nasolver.cpp:1097
bool isVSource(void)
Definition: circuit.h:191
int solve_nonlinear_continuation_Source(void)
Definition: nasolver.cpp:343
nr_double_t gMin
Definition: nasolver.h:132
#define MAX(x, y)
Maximum of x and y.
Definition: constants.h:127
nr_double_t abstol
Definition: nasolver.h:139