My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
hbsolver.cpp
Go to the documentation of this file.
1 /*
2  * hbsolver.cpp - harmonic balance solver class implementation
3  *
4  * Copyright (C) 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: hbsolver.cpp 1825 2011-03-11 20:42:14Z ela $
22  *
23  */
24 
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 
31 #include "object.h"
32 #include "logging.h"
33 #include "complex.h"
34 #include "vector.h"
35 #include "node.h"
36 #include "circuit.h"
37 #include "component_id.h"
38 #include "net.h"
39 #include "netdefs.h"
40 #include "strlist.h"
41 #include "ptrlist.h"
42 #include "tvector.h"
43 #include "tmatrix.h"
44 #include "eqnsys.h"
45 #include "analysis.h"
46 #include "dataset.h"
47 #include "fourier.h"
48 #include "hbsolver.h"
49 
50 #define HB_DEBUG 0
51 
52 using namespace fourier;
53 
54 // Constructor creates an unnamed instance of the hbsolver class.
56  type = ANALYSIS_HBALANCE;
57  frequency = 0;
58  nlnodes = lnnodes = banodes = nanodes = NULL;
59  Y = Z = A = NULL;
60  NA = YV = JQ = JG = JF = NULL;
61  OM = IR = QR = RH = IG = FQ = VS = VP = FV = IL = IN = IC = IS = NULL;
62  vs = x = NULL;
63  runs = 0;
64  ndfreqs = NULL;
65 }
66 
67 // Constructor creates a named instance of the hbsolver class.
68 hbsolver::hbsolver (char * n) : analysis (n) {
70  frequency = 0;
71  nlnodes = lnnodes = banodes = nanodes = NULL;
72  Y = Z = A = NULL;
73  NA = YV = JQ = JG = JF = NULL;
74  OM = IR = QR = RH = IG = FQ = VS = VP = FV = IL = IN = IC = IS = NULL;
75  vs = x = NULL;
76  runs = 0;
77  ndfreqs = NULL;
78 }
79 
80 // Destructor deletes the hbsolver class object.
82  // delete nodelists
83  if (nlnodes) delete nlnodes;
84  if (lnnodes) delete lnnodes;
85  if (banodes) delete banodes;
86  if (nanodes) delete nanodes;
87 
88  // delete temporary matrices
89  if (A) delete A;
90  if (Z) delete Z;
91  if (Y) delete Y;
92 
93  // delete matrices
94  if (NA) delete NA;
95  if (YV) delete YV;
96  if (JQ) delete JQ;
97  if (JG) delete JG;
98  if (JF) delete JF;
99 
100  // delete vectors
101  if (IC) delete IC;
102  if (IS) delete IS;
103  if (FV) delete FV;
104  if (IL) delete IL;
105  if (IN) delete IN;
106  if (IG) delete IG;
107  if (FQ) delete FQ;
108  if (VS) delete VS;
109  if (VP) delete VP;
110  if (vs) delete vs;
111  if (OM) delete OM;
112  if (IR) delete IR;
113  if (QR) delete QR;
114  if (RH) delete RH;
115 
116  if (x) delete x;
117  if (ndfreqs) delete[] ndfreqs;
118 }
119 
120 /* The copy constructor creates a new instance of the hbsolver class
121  based on the given hbsolver object. */
123  frequency = o.frequency;
124  negfreqs = o.negfreqs;
125  posfreqs = o.posfreqs;
126  nlnodes = o.nlnodes;
127  lnnodes = o.lnnodes;
128  banodes = o.banodes;
129  nanodes = o.nanodes;
130  Y = Z = A = NULL;
131  NA = YV = JQ = JG = JF = NULL;
132  OM = IR = QR = RH = IG = FQ = VS = VP = FV = IL = IN = IC = IS = NULL;
133  vs = x = NULL;
134  runs = o.runs;
135  ndfreqs = NULL;
136 }
137 
138 #define VS_(r) (*VS) (r)
139 #define OM_(r) (*OM) (r)
140 
141 /* This is the HB netlist solver. It prepares the circuit list and
142  solves it then. */
143 int hbsolver::solve (void) {
144 
145  int iterations = 0, done = 0;
146  int MaxIterations = getPropertyInteger ("MaxIter");
147 
148  // collect different parts of the circuit
149  splitCircuits ();
150 
151  // create frequency array
153 
154  // find interconnects between the linear and non-linear subcircuit
155  getNodeLists ();
156 
157  // prepares the linear part --> 0 = IC + [YV] * VS
158  prepareLinear ();
159 
160  runs++;
161  logprint (LOG_STATUS, "NOTIFY: %s: solving for %d frequencies\n",
162  getName (), lnfreqs);
163 
164  if (nbanodes > 0) {
165 
166  // start balancing
167  logprint (LOG_STATUS, "NOTIFY: %s: balancing at %d nodes\n", getName (),
168  nbanodes);
169 
170  // prepares the non-linear part
171  prepareNonLinear ();
172 
173 #if HB_DEBUG
174  fprintf (stderr, "YV -- transY in f:\n"); YV->print ();
175  fprintf (stderr, "IC -- constant current in f:\n"); IC->print ();
176 #endif
177 
178  // start iteration
179  do {
180  iterations++;
181 
182 #if HB_DEBUG
183  fprintf (stderr, "\n -- iteration step: %d\n", iterations);
184  fprintf (stderr, "vs -- voltage in t:\n"); vs->print ();
185 #endif
186 
187  // evaluate component functionality and fill matrices and vectors
188  loadMatrices ();
189 
190 #if HB_DEBUG
191  fprintf (stderr, "FQ -- charge in t:\n"); FQ->print ();
192  fprintf (stderr, "IG -- current in t:\n"); IG->print ();
193 #endif
194 
195  // currents into frequency domain
196  VectorFFT (IG);
197 
198  // charges into frequency domain
199  VectorFFT (FQ);
200 
201  // right hand side currents and charges into the frequency domain
202  VectorFFT (IR);
203  VectorFFT (QR);
204 
205 #if HB_DEBUG
206  fprintf (stderr, "VS -- voltage in f:\n"); VS->print ();
207  fprintf (stderr, "FQ -- charge in f:\n"); FQ->print ();
208  fprintf (stderr, "IG -- current in f:\n"); IG->print ();
209  fprintf (stderr, "IR -- corrected Jacobi current in f:\n"); IR->print ();
210 #endif
211 
212  // solve HB equation --> FV = IC + [YV] * VS + j[O] * FQ + IG
213  solveHB ();
214 
215 #if HB_DEBUG
216  fprintf (stderr, "FV -- error vector F(V) in f:\n"); FV->print ();
217  fprintf (stderr, "IL -- linear currents in f:\n"); IL->print ();
218  fprintf (stderr, "IN -- non-linear currents in f:\n"); IN->print ();
219  fprintf (stderr, "RH -- right-hand side currents in f:\n"); RH->print ();
220 #endif
221 
222  // termination criteria met
223  if (iterations > 1 && checkBalance ()) {
224  done = 1;
225  break;
226  }
227 
228 #if HB_DEBUG
229  fprintf (stderr, "JG -- G-Jacobian in t:\n"); JG->print ();
230  fprintf (stderr, "JQ -- C-Jacobian in t:\n"); JQ->print ();
231 #endif
232 
233  // G-Jacobian into frequency domain
234  MatrixFFT (JG);
235 
236  // C-Jacobian into frequency domain
237  MatrixFFT (JQ);
238 
239 #if HB_DEBUG
240  fprintf (stderr, "JQ -- dQ/dV C-Jacobian in f:\n"); JQ->print ();
241  fprintf (stderr, "JG -- dI/dV G-Jacobian in f:\n"); JG->print ();
242 #endif
243 
244  // calculate Jacobian --> JF = [YV] + j[O] * JQ + JG
245  calcJacobian ();
246 
247 #if HB_DEBUG
248  fprintf (stderr, "JF -- full Jacobian in f:\n"); JF->print ();
249 #endif
250 
251  // solve equation system --> JF * VS(n+1) = JF * VS(n) - FV
252  solveVoltages ();
253 
254 #if HB_DEBUG
255  fprintf (stderr, "VS -- next voltage in f:\n"); VS->print ();
256 #endif
257 
258  // inverse FFT of frequency domain voltage vector VS(n+1)
259  VectorIFFT (vs);
260  }
261  // check termination criteria (balanced frequency domain currents)
262  while (!done && iterations < MaxIterations);
263 
264  if (iterations >= MaxIterations) {
266  e->setText ("no convergence in %s analysis after %d iterations",
267  getName (), iterations);
268  throw_exception (e);
269  logprint (LOG_ERROR, "%s: no convergence after %d iterations\n",
270  getName (), iterations);
271  }
272  else {
273  logprint (LOG_STATUS, "%s: convergence reached after %d iterations\n",
274  getName (), iterations);
275  }
276  }
277  else {
278  // no balancing necessary
279  logprint (LOG_STATUS, "NOTIFY: %s: no balancing necessary\n", getName ());
280  }
281 
282  // print exception stack
283  estack.print ();
284 
285  // apply AC analysis to the complete network in order to obtain the
286  // final results
287  finalSolution ();
288 
289  // save results into dataset
290  saveResults ();
291  return 0;
292 }
293 
294 /* Goes through the list of circuit objects and runs its calcHB()
295  function. */
296 void hbsolver::calc (hbsolver * self) {
297  circuit * root = self->getNet()->getRoot ();
298  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
299  c->calcHB (self->frequency);
300  }
301 }
302 
303 /* Goes through the list of circuit objects and runs its initHB()
304  function. */
305 void hbsolver::initHB (void) {
306  circuit * root = subnet->getRoot ();
307  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
308  c->initHB ();
309  }
310 }
311 
312 /* Goes through the list of circuit objects and runs its initDC()
313  function. */
314 void hbsolver::initDC (void) {
315  circuit * root = subnet->getRoot ();
316  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
317  c->initDC ();
318  }
319 }
320 
321 // Returns true if circuit is a HB source.
323  int type = c->getType ();
324  if (type == CIR_PAC || type == CIR_VAC || type == CIR_VDC)
325  return true;
326  return false;
327 }
328 
329 // Expands the frequency array using the given frequency and the order.
330 void hbsolver::expandFrequencies (nr_double_t f, int n) {
331  tvector<nr_double_t> nfreqs = negfreqs;
332  tvector<nr_double_t> pfreqs = posfreqs;
333  int i, k, len = nfreqs.getSize ();
334  negfreqs.clear ();
335  posfreqs.clear ();
336  if (len > 0) {
337  // frequency expansion for full frequency sets
338  for (i = 0; i <= n + 1; i++) {
339  for (k = 0; k < len; k++) {
340  negfreqs.add (i * f + nfreqs.get (k));
341  }
342  }
343  for (i = -n; i < 0; i++) {
344  for (k = 0; k < len; k++) {
345  negfreqs.add (i * f + nfreqs.get (k));
346  }
347  }
348  for (i = 0; i <= 2 * n + 1; i++) {
349  for (k = 0; k < len; k++) {
350  posfreqs.add (i * f + pfreqs.get (k));
351  }
352  }
353  }
354  else {
355  // first frequency
356  for (i = 0; i <= n + 1; i++) negfreqs.add (i * f);
357  for (i = -n; i < 0; i++) negfreqs.add (i * f);
358  for (i = 0; i <= 2 * n + 1; i++) posfreqs.add (i * f);
359  }
360 }
361 
362 // Calculates an order fulfilling the "power of two" requirement.
364  int o, order = n * 2; // current order + DC + negative freqencies
365  for (o = 1; o < order; o <<= 1) ; // a power of 2
366  return o / 2 - 1;
367 }
368 
369 /* The function computes the harmonic frequencies excited in the
370  circuit list depending on the maximum number of harmonics per
371  exitation and saves its results into the 'negfreqs' vector. */
373 
374  // initialization
375  negfreqs.clear ();
376  posfreqs.clear ();
377  rfreqs.clear ();
378  dfreqs.clear ();
379  if (ndfreqs) delete[] ndfreqs;
380 
381  // obtain order
382  int i, n = calcOrder (getPropertyInteger ("n"));
383 
384  // expand frequencies for each exitation
385  nr_double_t f;
386  for (ptrlistiterator<circuit> it (excitations); *it; ++it) {
387  circuit * c = it.current ();
388  if (c->getType () != CIR_VDC) { // no extra DC sources
389  if ((f = c->getPropertyDouble ("f")) != 0.0) {
390  if (!dfreqs.contains (f)) { // no double frequencies
391  dfreqs.add (f);
392  expandFrequencies (f, n);
393  }
394  }
395  }
396  }
397 
398  // no excitations
399  if (negfreqs.getSize () == 0) {
400  // use specified frequency
401  f = getPropertyDouble ("f");
402  dfreqs.add (f);
403  expandFrequencies (f, n);
404  }
405 
406  // build frequency dimension lengths
407  ndfreqs = new int[dfreqs.getSize ()];
408  for (i = 0; i < dfreqs.getSize (); i++) {
409  ndfreqs[i] = (n + 1) * 2;
410  }
411 
412 #if HB_DEBUG
413  fprintf (stderr, "%d frequencies: [ ", negfreqs.getSize ());
414  for (i = 0; i < negfreqs.getSize (); i++) {
415  fprintf (stderr, "%g ", (double) real (negfreqs.get (i)));
416  }
417  fprintf (stderr, "]\n");
418 #endif /* HB_DEBUG */
419 
420  // build list of positive frequencies including DC
421  for (n = 0; n < negfreqs.getSize (); n++) {
422  if ((f = negfreqs (n)) < 0.0) continue;
423  rfreqs.add (f);
424  }
425  lnfreqs = rfreqs.getSize ();
426  nlfreqs = negfreqs.getSize ();
427 
428  // pre-calculate the j[O] vector
429  OM = new tvector<nr_complex_t> (nlfreqs);
430  for (n = i = 0; n < nlfreqs; n++, i++)
431  OM_(n) = rect (0, 2 * M_PI * negfreqs (i));
432 }
433 
434 // Split netlist into excitation, linear and non-linear part.
436  circuit * root = subnet->getRoot ();
437  for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
438  if (c->isNonLinear ()) {
439  // non-linear part
440  nolcircuits.add (c);
441  }
442  else if (isExcitation (c)) {
443  // get sinusoidal sources
444  excitations.add (c);
445  }
446  else if (c->getType () != CIR_GROUND) {
447  // linear part
448  lincircuits.add (c);
449  }
450  }
451 }
452 
453 // Creates a nodelist for the given circuit list.
455  strlist * nodes = new strlist ();
456  for (ptrlistiterator<circuit> it (circuits); *it; ++it) {
457  circuit * c = it.current ();
458  for (int i = 0; i < c->getSize (); i++) {
459  char * n = c->getNode(i)->getName ();
460  if (strcmp (n, "gnd")) {
461  if (!nodes->contains (n)) nodes->add (n);
462  }
463  }
464  }
465  return nodes;
466 }
467 
468 // Obtain node lists for linear and non-linear part.
470  // non-linear nodes
471  nlnodes = circuitNodes (nolcircuits);
472  // linear nodes
473  lnnodes = circuitNodes (lincircuits);
474  // excitation nodes
475  exnodes = circuitNodes (excitations);
476 
477 #if DEBUG && 0
478  fprintf (stderr, "nonlinear nodes: [ %s ]\n", nlnodes->toString ());
479  fprintf (stderr, " linear nodes: [ %s ]\n", lnnodes->toString ());
480 #endif
481 
482  // organization of the nodes for the MNA:
483  // --------------------------------------
484  // 1.) balanced nodes: all connected to at least one non-linear device
485  // 2.a) the excitation nodes
486  // 2.b) all linear nodes not contained in 1. and 2.a
487  // 2.c) additional gyrators of linear nodes (built-in voltage sources)
488  // please note: excitation nodes also in 2.b; 1. and 2.a are 'ports'
489 
490  nanodes = new strlist (*nlnodes); // list 1.
491  strlistiterator it;
492  // add excitation nodes; list 2.a
493  for (it = strlistiterator (exnodes); *it; ++it)
494  nanodes->append (*it);
495  // add linear nodes; list 2.b
496  for (it = strlistiterator (lnnodes); *it; ++it) {
497  if (!nanodes->contains (*it))
498  nanodes->append (*it);
499  }
500 
501  banodes = new strlist (*nlnodes);
502 #if DEBUG && 0
503  fprintf (stderr, " balanced nodes: [ %s ]\n", banodes->toString ());
504  fprintf (stderr, " exnodes nodes: [ %s ]\n", exnodes->toString ());
505  fprintf (stderr, " nanodes nodes: [ %s ]\n", nanodes->toString ());
506 #endif
507 }
508 
509 /* The function applies unique voltage source identifiers to each
510  built in internal voltage source in the list of circuits. */
512  int sources = 0;
513  for (ptrlistiterator<circuit> it (circuits); *it; ++it) {
514  circuit * c = it.current ();
515  if (c->getVoltageSources () > 0) {
516  c->setVoltageSource (sources);
517  sources += c->getVoltageSources ();
518  }
519  }
520  return sources;
521 }
522 
523 /* The function assigns unique node identifiers to each circuit node. */
525  int offset) {
526  // through all collected nodes
527  for (int nr = 0; nr < nodes->length (); nr++) {
528  char * nn = nodes->get (nr);
529  // through all circuits
530  for (ptrlistiterator<circuit> it (circuits); *it; ++it) {
531  circuit * c = it.current ();
532  // assign current identifier if any of the circuit nodes equals
533  // the current one
534  for (int i = 0; i < c->getSize (); i++) {
535  node * n = c->getNode (i);
536  if (!strcmp (n->getName (), nn)) n->setNode (offset + nr + 1);
537  }
538  }
539  }
540  return nodes->length ();
541 }
542 
543 // Prepares the linear operations.
545  for (ptrlistiterator<circuit> it (lincircuits); *it; ++it) (*it)->initHB ();
546  nlnvsrcs = assignVoltageSources (lincircuits);
547  nnlvsrcs = excitations.length ();
548  nnanodes = nanodes->length ();
549  nexnodes = exnodes->length ();
550  nbanodes = banodes->length ();
551  assignNodes (lincircuits, nanodes);
552  assignNodes (excitations, nanodes);
556 }
557 
558 /* The function creates the complex linear network MNA matrix. It
559  contains the MNA entries for all linear components for each
560  requested frequency. */
562  int M = nlnvsrcs;
563  int N = nnanodes;
564  int f = 0;
565  nr_double_t freq;
566 
567  // create new MNA matrix
568  A = new tmatrix<nr_complex_t> ((N + M) * lnfreqs);
569 
570  // through each frequency
571  for (int i = 0; i < rfreqs.getSize (); i++) {
572  freq = rfreqs (i);
573  // calculate components' MNA matrix for the given frequency
574  for (ptrlistiterator<circuit> it (lincircuits); *it; ++it)
575  (*it)->calcHB (freq);
576  // fill in all matrix entries for the given frequency
577  fillMatrixLinearA (A, f++);
578  }
579 
580  // save a copy of the original MNA matrix
581  NA = new tmatrix<nr_complex_t> (*A);
582 }
583 
584 // some definitions for the linear matrix filler
585 #undef A_
586 #undef B_
587 #define A_(r,c) (*A) ((r)*lnfreqs+f,(c)*lnfreqs+f)
588 #define G_(r,c) A_(r,c)
589 #define B_(r,c) A_(r,c+N)
590 #define C_(r,c) A_(r+N,c)
591 #define D_(r,c) A_(r+N,c+N)
592 
593 /* This function fills in the MNA matrix entries into the A matrix for
594  a given frequency index. */
596  int N = nnanodes;
597 
598  // through each linear circuit
599  for (ptrlistiterator<circuit> it (lincircuits); *it; ++it) {
600  circuit * cir = it.current ();
601  int s = cir->getSize ();
602  int nr, nc, r, c, v;
603 
604  // apply G-matrix entries
605  for (r = 0; r < s; r++) {
606  if ((nr = cir->getNode(r)->getNode () - 1) < 0) continue;
607  for (c = 0; c < s; c++) {
608  if ((nc = cir->getNode(c)->getNode () - 1) < 0) continue;
609  G_(nr, nc) += cir->getY (r, c);
610  }
611  }
612 
613  // augmented part -- built in voltage sources
614  if ((v = cir->getVoltageSources ()) > 0) {
615 
616  // apply B-matrix entries
617  for (r = 0; r < s; r++) {
618  if ((nr = cir->getNode(r)->getNode () - 1) < 0) continue;
619  for (c = 0; c < v; c++) {
620  nc = cir->getVoltageSource () + c;
621  B_(nr, nc) += cir->getB (r, nc);
622  }
623  }
624 
625  // apply C-matrix entries
626  for (r = 0; r < v; r++) {
627  nr = cir->getVoltageSource () + r;
628  for (c = 0; c < s; c++) {
629  if ((nc = cir->getNode(c)->getNode () - 1) < 0) continue;
630  C_(nr, nc) += cir->getC (nr, c);
631  }
632  }
633 
634  // apply D-matrix entries
635  for (r = 0; r < v; r++) {
636  nr = cir->getVoltageSource () + r;
637  for (c = 0; c < v; c++) {
638  nc = cir->getVoltageSource () + c;
639  D_(nr, nc) += cir->getD (nr, nc);
640  }
641  }
642  }
643  }
644 }
645 
646 // The function inverts the given matrix A into the matrix H.
650  int N = A->getCols ();
653 
654  try_running () {
655  // create LU decomposition of the A matrix
657  eqns.passEquationSys (A, x, z);
658  eqns.solve ();
659  }
660  // appropriate exception handling
661  catch_exception () {
662  case EXCEPTION_PIVOT:
663  default:
664  logprint (LOG_ERROR, "WARNING: %s: during TI inversion\n", getName ());
665  estack.print ();
666  }
667 
668  // use the LU decomposition to obtain the inverse H
670  for (int c = 0; c < N; c++) {
671  z->set (0.0);
672  z->set (c, 1.0);
673  eqns.passEquationSys (A, x, z);
674  eqns.solve ();
675  for (int r = 0; r < N; r++) H->set (r, c, x->get (r));
676  }
677  delete x;
678  delete z;
679 }
680 
681 // Some defines for matrix element access.
682 #define V_(r) (*V) (r)
683 #define I_(r) (*I) (r)
684 #undef A_
685 #define A_(r,c) (*A) (r,c)
686 
687 #define Z_(r,c) (*Z) (r,c)
688 #define Y_(r,c) (*Y) (r,c)
689 
690 #define ZVU_(r,c) Z_(r,c)
691 #define ZVL_(r,c) Z_((r)*lnfreqs+f+sn,c)
692 #define ZCU_(r,c) Z_(r,(c)*lnfreqs+f+sn)
693 #define ZCL_(r,c) Z_((r)*lnfreqs+f+sn,(c)*lnfreqs+f+sn)
694 
695 #define YV_(r,c) (*YV) (r,c)
696 #define NA_(r,c) (*NA) (r,c)
697 #define JF_(r,c) (*JF) (r,c)
698 
699 /* The following function performs the following steps:
700  1. form the MNA matrix A including all nodes (linear, non-linear and
701  excitations)
702  2. compute the variable transimpedance matrix entries for the nodes
703  to be balanced
704  3. compute the constant transimpedance matrix entries for the constant
705  current vector caused by the excitations
706  4. invert this overall transimpedance matrix
707  5. extract the variable transadmittance matrix entries
708 */
710  int M = nlnvsrcs;
711  int N = nnanodes;
712  int c, r, f;
714 
715  // size of overall MNA matrix
716  int sa = (N + M) * lnfreqs;
717  int sv = nbanodes;
718  int se = nnlvsrcs;
719  int sy = sv + se;
720 
721  // allocate new transimpedance matrix
722  Z = new tmatrix<nr_complex_t> (sy * lnfreqs);
723 
724  // prepare equation system
725  eqnsys<nr_complex_t> eqns;
728 
729  // 1. create variable transimpedance matrix entries relating
730  // voltages at the balanced nodes to the currents through these
731  // nodes into the non-linear part
732  int sn = sv * lnfreqs;
733  V = new tvector<nr_complex_t> (sa);
734  I = new tvector<nr_complex_t> (sa);
735 
736  // connect a 100 Ohm resistor (to ground) to balanced node in the MNA matrix
737  for (c = 0; c < sv * lnfreqs; c++) A_(c, c) += 0.01;
738 
739  // connect a 100 Ohm resistor (in parallel) to each excitation
740  for (ite = ptrlistiterator<circuit> (excitations); *ite; ++ite) {
741  circuit * vs = ite.current ();
742  // get positive and negative node
743  int pnode = vs->getNode(NODE_1)->getNode ();
744  int nnode = vs->getNode(NODE_2)->getNode ();
745  for (f = 0; f < lnfreqs; f++) { // for each frequency
746  int pn = (pnode - 1) * lnfreqs + f;
747  int nn = (nnode - 1) * lnfreqs + f;
748  if (pnode) A_(pn, pn) += 0.01;
749  if (nnode) A_(nn, nn) += 0.01;
750  if (pnode && nnode) {
751  A_(pn, nn) -= 0.01;
752  A_(nn, pn) -= 0.01;
753  }
754  }
755  }
756 
757  // LU decompose the MNA matrix
758  try_running () {
759  eqns.setAlgo (ALGO_LU_FACTORIZATION_CROUT);
760  eqns.passEquationSys (A, V, I);
761  eqns.solve ();
762  }
763  // appropriate exception handling
764  catch_exception () {
765  case EXCEPTION_PIVOT:
766  default:
767  logprint (LOG_ERROR, "WARNING: %s: during A factorization\n", getName ());
768  estack.print ();
769  }
770 
771  // aquire variable transimpedance matrix entries
772  eqns.setAlgo (ALGO_LU_SUBSTITUTION_CROUT);
773  for (c = 0; c < sn; c++) {
774  I->set (0.0);
775  I_(c) = 1.0;
776  eqns.passEquationSys (A, V, I);
777  eqns.solve ();
778  // ZV | ..
779  // ---+---
780  // .. | ..
781  for (r = 0; r < sn; r++) ZVU_(r, c) = V_(r);
782  // .. | ..
783  // ---+---
784  // ZV | ..
785  r = 0;
786  for (ite = ptrlistiterator<circuit> (excitations); *ite; ++ite, r++) {
787  // lower part entries
788  for (f = 0; f < lnfreqs; f++) {
789  ZVL_(r, c) = excitationZ (V, *ite, f);
790  }
791  }
792  }
793 
794  // create constant transimpedance matrix entries relating the
795  // source voltages to the interconnection currents
796  int vsrc = 0;
797  // aquire constant transadmittance matrix entries
798  for (ptrlistiterator<circuit> it (excitations); *it; ++it, vsrc++) {
799  circuit * vs = it.current ();
800  // get positive and negative node
801  int pnode = vs->getNode(NODE_1)->getNode ();
802  int nnode = vs->getNode(NODE_2)->getNode ();
803  for (f = 0; f < lnfreqs; f++) { // for each frequency
804  int pn = (pnode - 1) * lnfreqs + f;
805  int nn = (nnode - 1) * lnfreqs + f;
806  I->set (0.0);
807  if (pnode) I_(pn) = +1.0;
808  if (nnode) I_(nn) = -1.0;
809  eqns.passEquationSys (A, V, I);
810  eqns.solve ();
811  // .. | ZC
812  // ---+---
813  // .. | ..
814  for (r = 0; r < sn; r++) {
815  // upper part of the entries
816  ZCU_(r, vsrc) = V_(r);
817  }
818  // .. | ..
819  // ---+---
820  // .. | ZC
821  r = 0;
822  for (ite = ptrlistiterator<circuit> (excitations); *ite; ++ite, r++) {
823  // lower part entries
824  ZCL_(r, vsrc) = excitationZ (V, *ite, f);
825  }
826  }
827  }
828  delete I;
829  delete V;
830 
831  // allocate new transadmittance matrix
832  Y = new tmatrix<nr_complex_t> (sy * lnfreqs);
833 
834  // invert the Z matrix to a Y matrix
835  invertMatrix (Z, Y);
836 
837  // substract the 100 Ohm resistor
838  for (c = 0; c < sy * lnfreqs; c++) Y_(c, c) -= 0.01;
839 
840  // extract the variable transadmittance matrix
841  YV = new tmatrix<nr_complex_t> (sv * nlfreqs);
842 
843  // variable transadmittance matrix must be continued conjugately
844  *YV = expandMatrix (*Y, sv);
845 
846  // delete overall temporary MNA matrix
847  delete A; A = NULL;
848  // delete transimpedance matrix
849  delete Z; Z = NULL;
850 }
851 
852 /* Little helper function obtaining a transimpedance value for the
853  given voltage source (excitation) and for a given frequency
854  index. */
856  int f) {
857  // get positive and negative node
858  int pnode = vs->getNode(NODE_1)->getNode ();
859  int nnode = vs->getNode(NODE_2)->getNode ();
860  nr_complex_t z = 0.0;
861  if (pnode) z += V_((pnode - 1) * lnfreqs + f);
862  if (nnode) z -= V_((nnode - 1) * lnfreqs + f);
863  return z;
864 }
865 
866 /* This function computes the constant current vectors using the
867  voltage of the excitations and the transadmittance matrix
868  entries. */
870  int se = nnlvsrcs * lnfreqs;
871  int sn = nbanodes * lnfreqs;
872  int r, c, vsrc = 0;
873 
874  // collect excitation voltages
875  tvector<nr_complex_t> VC (se);
876  for (ptrlistiterator<circuit> it (excitations); *it; ++it, vsrc++) {
877  circuit * vs = it.current ();
878  vs->initHB ();
879  vs->setVoltageSource (0);
880  for (int f = 0; f < rfreqs.getSize (); f++) { // for each frequency
881  nr_double_t freq = rfreqs (f);
882  vs->calcHB (freq);
883  VC (vsrc * lnfreqs + f) = vs->getE (VSRC_1);
884  }
885  }
886 
887  // compute constant current vector for balanced nodes
888  IC = new tvector<nr_complex_t> (sn);
889  // .. | YC * VC
890  // ---+---
891  // .. | ..
892  for (r = 0; r < sn; r++) {
893  nr_complex_t i = 0.0;
894  for (c = 0; c < se; c++) {
895  i += Y_(r, c + sn) * VC (c);
896  }
897  int f = r % lnfreqs;
898  if (f != 0 && f != lnfreqs - 1) i /= 2;
899  IC->set (r, i);
900  }
901  // expand the constant current conjugate
902  *IC = expandVector (*IC, nbanodes);
903 
904  // compute constant current vector for sources itself
905  IS = new tvector<nr_complex_t> (se);
906  // .. | ..
907  // ---+---
908  // .. | YC * VC
909  for (r = 0; r < se; r++) {
910  nr_complex_t i = 0.0;
911  for (c = 0; c < se; c++) {
912  i += Y_(r + sn, c + sn) * VC (c);
913  }
914  IS->set (r, i);
915  }
916 
917  // delete overall transadmittance matrix
918  delete Y; Y = NULL;
919 }
920 
921 /* Checks whether currents through the interconnects of the linear and
922  non-linear subcircuit (in the frequency domain) are equal. */
924  nr_double_t iabstol = getPropertyDouble ("iabstol");
925  nr_double_t vabstol = getPropertyDouble ("vabstol");
926  nr_double_t reltol = getPropertyDouble ("reltol");
927  int n, len = FV->getSize ();
928  for (n = 0; n < len; n++) {
929  // check iteration voltages
930  nr_double_t v_abs = abs (VS->get (n) - VP->get (n));
931  nr_double_t v_rel = abs (VS->get (n));
932  if (v_abs >= vabstol + reltol * v_rel) return 0;
933  // check balanced currents
934  nr_complex_t il = IL->get (n);
935  nr_complex_t in = IN->get (n);
936  if (il != in) {
937  nr_double_t i_abs = abs (il + in);
938  nr_double_t i_rel = abs ((il + in) / (il - in));
939  if (i_abs >= iabstol && 2.0 * i_rel >= reltol) return 0;
940  }
941  }
942  return 1;
943 }
944 
945 // some definitions for the non-linear matrix filler
946 #undef G_
947 #undef C_
948 #define G_(r,c) (*jg) ((r)*nlfreqs+f,(c)*nlfreqs+f)
949 #define C_(r,c) (*jq) ((r)*nlfreqs+f,(c)*nlfreqs+f)
950 #undef FI_
951 #undef FQ_
952 #define FI_(r) (*ig) ((r)*nlfreqs+f)
953 #define FQ_(r) (*fq) ((r)*nlfreqs+f)
954 #define IR_(r) (*ir) ((r)*nlfreqs+f)
955 #define QR_(r) (*qr) ((r)*nlfreqs+f)
956 
957 /* This function fills in the matrix and vector entries for the
958  non-linear HB equations for a given frequency index. */
960  tmatrix<nr_complex_t> * jq,
961  tvector<nr_complex_t> * ig,
965  int f) {
966  // through each linear circuit
967  for (ptrlistiterator<circuit> it (nolcircuits); *it; ++it) {
968  circuit * cir = it.current ();
969  int s = cir->getSize ();
970  int nr, nc, r, c;
971 
972  for (r = 0; r < s; r++) {
973  if ((nr = cir->getNode(r)->getNode () - 1) < 0) continue;
974  // apply G- and C-matrix entries
975  for (c = 0; c < s; c++) {
976  if ((nc = cir->getNode(c)->getNode () - 1) < 0) continue;
977  G_(nr, nc) += cir->getY (r, c);
978  C_(nr, nc) += cir->getQV (r, c);
979  }
980  // apply I- and Q-vector entries
981  FI_(nr) -= cir->getI (r);
982  FQ_(nr) -= cir->getQ (r);
983  // ThinkME: positive or negative?
984  IR_(nr) += cir->getGV (r) + cir->getI (r);
985  QR_(nr) += cir->getCV (r) + cir->getQ (r);
986  }
987  }
988 }
989 
990 /* The function initializes the non-linear part of the HB. */
992  int N = nbanodes;
993 
994  // allocate matrices and vectors
995  if (FQ == NULL) {
996  FQ = new tvector<nr_complex_t> (N * nlfreqs);
997  }
998  if (IG == NULL) {
999  IG = new tvector<nr_complex_t> (N * nlfreqs);
1000  }
1001  if (IR == NULL) {
1002  IR = new tvector<nr_complex_t> (N * nlfreqs);
1003  }
1004  if (QR == NULL) {
1005  QR = new tvector<nr_complex_t> (N * nlfreqs);
1006  }
1007  if (JG == NULL) {
1008  JG = new tmatrix<nr_complex_t> (N * nlfreqs);
1009  }
1010  if (JQ == NULL) {
1011  JQ = new tmatrix<nr_complex_t> (N * nlfreqs);
1012  }
1013  if (JF == NULL) {
1014  JF = new tmatrix<nr_complex_t> (N * nlfreqs);
1015  }
1016 
1017  // voltage vector in frequency and time domain
1018  if (VS == NULL) {
1019  VS = new tvector<nr_complex_t> (N * nlfreqs);
1020  }
1021  if (vs == NULL) {
1022  vs = new tvector<nr_complex_t> (N * nlfreqs);
1023  }
1024  if (VP == NULL) {
1025  VP = new tvector<nr_complex_t> (N * nlfreqs);
1026  }
1027 
1028  // error vector
1029  if (FV == NULL) {
1030  FV = new tvector<nr_complex_t> (N * nlfreqs);
1031  }
1032  // right hand side vector
1033  if (RH == NULL) {
1034  RH = new tvector<nr_complex_t> (N * nlfreqs);
1035  }
1036 
1037  // linear and non-linear current vector
1038  if (IL == NULL) {
1039  IL = new tvector<nr_complex_t> (N * nlfreqs);
1040  }
1041  if (IN == NULL) {
1042  IN = new tvector<nr_complex_t> (N * nlfreqs);
1043  }
1044 
1045  // assign nodes
1046  assignNodes (nolcircuits, nanodes);
1047 
1048  // initialize circuits
1049  for (ptrlistiterator<circuit> it (nolcircuits); *it; ++it) {
1050  (*it)->initHB (nlfreqs);
1051  }
1052 }
1053 
1054 /* Saves the node voltages of the given circuit and for the given
1055  frequency entry into the circuit voltage vector. */
1057  int r, nr, s = cir->getSize ();
1058  for (r = 0; r < s; r++) {
1059  if ((nr = cir->getNode(r)->getNode () - 1) < 0) continue;
1060  // apply V-vector entries
1061  cir->setV (r, real (vs->get (nr * nlfreqs + f)));
1062  }
1063 }
1064 
1065 /* The function saves voltages into non-linear circuits, runs each
1066  non-linear components' HB calculator for each frequency and applies
1067  the matrix and vector entries appropriately. */
1069  // clear matrices and vectors before
1070  IG->set (0.0);
1071  FQ->set (0.0);
1072  IR->set (0.0);
1073  QR->set (0.0);
1074  JG->set (0.0);
1075  JQ->set (0.0);
1076  // through each frequency
1077  for (int f = 0; f < nlfreqs; f++) {
1078  // calculate components' HB matrices and vector for the given frequency
1079  for (ptrlistiterator<circuit> it (nolcircuits); *it; ++it) {
1080  saveNodeVoltages (*it, f); // node voltages
1081  (*it)->calcHB (f); // HB calculator
1082  }
1083  // fill in all matrix entries for the given frequency
1084  fillMatrixNonLinear (JG, JQ, IG, FQ, IR, QR, f);
1085  }
1086 }
1087 
1088 /* The following function transforms a vector using a Fast Fourier
1089  Transformation from the time domain to the frequency domain. */
1091  int i, k, r;
1092  int n = nlfreqs;
1093  int nd = dfreqs.getSize ();
1094  int nodes = V->getSize () / n;
1095  nr_double_t * d = (nr_double_t *) V->getData ();
1096 
1097  if (nd == 1) {
1098  // for each node a single 1d-FFT
1099  for (k = i = 0; i < nodes; i++, k += 2 * n) {
1100  nr_double_t * dst = &d[k];
1101  _fft_1d (dst, n, isign);
1102  if (isign > 0) for (r = 0; r < 2 * n; r++) *dst++ /= n;
1103  }
1104  }
1105  else {
1106  // for each node a single nd-FFT
1107  for (k = i = 0; i < nodes; i++, k += 2 * n) {
1108  nr_double_t * dst = &d[k];
1109  _fft_nd (dst, ndfreqs, nd, isign);
1110  if (isign > 0) for (r = 0; r < 2 * n; r++) *dst++ /= ndfreqs[0];
1111  }
1112  }
1113 }
1114 
1115 /* The following function transforms a vector using an Inverse Fast
1116  Fourier Transformation from the frequency domain to the domain
1117  time. */
1119  VectorFFT (V, -isign);
1120 }
1121 
1122 /* The following function transforms a matrix using a Fast Fourier
1123  Transformation from the time domain to the frequency domain. */
1125 
1126 #if THE_SLO_ALGO
1127  // each column FFT
1128  for (int c = 0; c < M->getCols (); c++) {
1130  VectorFFT (&V);
1131  M->setCol (c, V);
1132  }
1133 
1134  // each row IFFT
1135  for (int r = 0; r < M->getRows (); r++) {
1136  tvector<nr_complex_t> V = M->getRow (r);
1137  VectorIFFT (&V);
1138  M->setRow (r, V);
1139  }
1140 #else
1141  int c, r, nc, nr;
1142  // for each non-linear node block
1143  for (nc = c = 0; c < nbanodes; c++, nc += nlfreqs) {
1144  for (nr = r = 0; r < nbanodes; r++, nr += nlfreqs) {
1145  tvector<nr_complex_t> V (nlfreqs);
1146  int fr, fc, fi;
1147  // transform the sub-diagonal only
1148  for (fc = 0; fc < nlfreqs; fc++) V (fc) = M->get (nr + fc, nc + fc);
1149  VectorFFT (&V);
1150  // fill in resulting sub-matrix for the node
1151  for (fc = 0; fc < nlfreqs; fc++) {
1152  for (fi = nlfreqs - 1 - fc, fr = 0; fr < nlfreqs; fr++) {
1153  if (++fi >= nlfreqs) fi = 0;
1154  M->set (nr + fr, nc + fc, V (fi));
1155  }
1156  }
1157  }
1158  }
1159 #endif
1160 }
1161 
1162 /* This function solves the actual HB equation in the frequency domain.
1163  F(V) = IC + [YV] * VS + j[O] * FQ + IG -> 0
1164  Care must be taken with indexing here: In the frequency domain only
1165  real positive frequencies are used and computed, but in the time
1166  domain we have more values because of the periodic continuation in
1167  the frequency domain.
1168  RHS = j[O] * CV + GV - (IC + j[O] * FQ + IG)
1169  Also the right hand side of the equation system for the new voltage
1170  vector is computed here. */
1171 void hbsolver::solveHB (void) {
1172  // for each non-linear node
1173  for (int r = 0; r < nbanodes * nlfreqs; ) {
1174  // for each frequency
1175  for (int f = 0; f < nlfreqs; f++, r++) {
1176  nr_complex_t il = 0.0, in = 0.0, ir = 0.0;
1177  // constant current vector due to sources
1178  il += IC->get (r);
1179  // part 1 of right hand side vector
1180  ir -= il;
1181  // transadmittance matrix multiplied by voltage vector
1182  for (int c = 0; c < nbanodes * nlfreqs; c++) {
1183  il += YV_(r, c) * VS_(c);
1184  }
1185  // charge vector
1186  in += OM_(f) * FQ->get (r);
1187  // current vector
1188  in += IG->get (r);
1189  // part 2, 3 and 4 of right hand side vector
1190  ir += IR->get (r);
1191  ir += OM_(f) * QR->get (r);
1192  // put values into result vectors
1193  RH->set (r, ir);
1194  FV->set (r, il + in);
1195  IL->set (r, il);
1196  IN->set (r, in);
1197  }
1198  }
1199 }
1200 
1201 /* The function calculates the full Jacobian JF = [YV] + j[O] * JQ + JG */
1203  int c, r, fc, fr, rt, ct;
1204  /* add admittances of capacitance matrix JQ and non-linear
1205  admittances matrix JG into complete Jacobian JF */
1206  for (c = 0; c < nbanodes; c++) {
1207  ct = c * nlfreqs;
1208  for (fc = 0; fc < nlfreqs; fc++, ct++) {
1209  for (r = 0; r < nbanodes; r++) {
1210  rt = r * nlfreqs;
1211  for (fr = 0; fr < nlfreqs; fr++, rt++) {
1212  JF_(rt, ct) = JG->get (rt, ct) + JQ->get (rt, ct) * OM_(fr);
1213  }
1214  }
1215  }
1216  }
1217  *JF += *YV; // add linear admittance matrix
1218 }
1219 
1220 /* The function expands the given vector in the frequency domain to
1221  make it a real valued signal in the time domain. */
1223  int nodes) {
1224  tvector<nr_complex_t> res (nodes * nlfreqs);
1225  int r, ff, rf, rt;
1226  for (r = 0; r < nodes; r++) {
1227  rt = r * nlfreqs;
1228  rf = r * lnfreqs;
1229  // copy first part of vector
1230  for (ff = 0; ff < lnfreqs; ff++, rf++, rt++) {
1231  res (rt) = V (rf);
1232  }
1233  // continue vector conjugated
1234  for (rf -= 2; ff < nlfreqs; ff++, rf--, rt++) {
1235  res (rt) = conj (V (rf));
1236  }
1237  }
1238  return res;
1239 }
1240 
1241 /* The function expands the given matrix in the frequency domain to
1242  make it a real valued signal in the time domain. */
1244  int nodes) {
1245  tmatrix<nr_complex_t> res (nodes * nlfreqs);
1246  int r, c, rf, rt, cf, ct, ff;
1247  for (r = 0; r < nodes; r++) {
1248  for (c = 0; c < nodes; c++) {
1249  rf = r * lnfreqs;
1250  rt = r * nlfreqs;
1251  cf = c * lnfreqs;
1252  ct = c * nlfreqs;
1253  // copy first part of diagonal
1254  for (ff = 0; ff < lnfreqs; ff++, cf++, ct++, rf++, rt++) {
1255  res (rt, ct) = M (rf, cf);
1256  }
1257  // continue diagonal conjugated
1258  for (cf -= 2, rf -= 2; ff < nlfreqs; ff++, cf--, ct++, rf--, rt++) {
1259  res (rt, ct) = conj (M (rf, cf));
1260  }
1261  }
1262  }
1263  return res;
1264 }
1265 
1266 /* This function solves the equation system
1267  JF * VS(n+1) = JF * VS(n) - FV
1268  in order to obtains a new voltage vector in the frequency domain. */
1270  // save previous iteration voltage
1271  *VP = *VS;
1272 
1273  // setup equation system
1274  eqnsys<nr_complex_t> eqns;
1275  try_running () {
1276  // use LU decomposition for solving
1278  eqns.passEquationSys (JF, VS, RH);
1279  eqns.solve ();
1280  }
1281  // appropriate exception handling
1282  catch_exception () {
1283  case EXCEPTION_PIVOT:
1284  default:
1285  logprint (LOG_ERROR, "WARNING: %s: during NR iteration\n", getName ());
1286  estack.print ();
1287  }
1288 
1289  // save new voltages in time domain vector
1290  *vs = *VS;
1291 }
1292 
1293 /* The following function extends the existing linear MNA matrix to
1294  contain the additional rows and columns for the excitation voltage
1295  sources. */
1297  int nodes) {
1298  int no = M.getCols ();
1299  tmatrix<nr_complex_t> res (no + nodes * lnfreqs);
1300  // copy the existing part
1301  for (int r = 0; r < no; r++) {
1302  for (int c = 0; c < no; c++) {
1303  res (r, c) = M (r, c);
1304  }
1305  }
1306  return res;
1307 }
1308 
1309 /* The function fills in the missing MNA entries for the excitation
1310  voltage sources into the extended rows and columns as well as the
1311  actual voltage values into the right hand side vector. */
1313  tvector<nr_complex_t> * I) {
1314  // through each excitation source
1315  int of = lnfreqs * (nlnvsrcs + nnanodes);
1316  int sc = of;
1317 
1318  for (ptrlistiterator<circuit> it (excitations); *it; ++it) {
1319  circuit * vs = it.current ();
1320  // get positive and negative node
1321  int pnode = vs->getNode(NODE_1)->getNode ();
1322  int nnode = vs->getNode(NODE_2)->getNode ();
1323  for (int f = 0; f < lnfreqs; f++, sc++) { // for each frequency
1324  // fill right hand side vector
1325  nr_double_t freq = rfreqs (f);
1326  vs->calcHB (freq);
1327  I_(sc) = vs->getE (VSRC_1);
1328  // fill MNA entries
1329  int pn = (pnode - 1) * lnfreqs + f;
1330  int nn = (nnode - 1) * lnfreqs + f;
1331  if (pnode) {
1332  Y_(pn, sc) = +1.0;
1333  Y_(sc, pn) = +1.0;
1334  }
1335  if (nnode) {
1336  Y_(nn, sc) = -1.0;
1337  Y_(sc, nn) = -1.0;
1338  }
1339  }
1340  }
1341 }
1342 
1343 /* The function calculates and saves the final solution. */
1345 
1346  // extend the linear MNA matrix
1347  *NA = extendMatrixLinear (*NA, nnlvsrcs);
1348 
1349  int S = NA->getCols ();
1350  int N = nnanodes * lnfreqs;
1351 
1352  // right hand side vector
1354  // temporary solution
1356  // final solution
1357  x = new tvector<nr_complex_t> (N);
1358 
1359  // fill in missing MNA entries
1360  fillMatrixLinearExtended (NA, I);
1361 
1362  // put currents through balanced nodes into right hand side
1363  for (int n = 0; n < nbanodes; n++) {
1364  for (int f = 0; f < lnfreqs; f++) {
1365  nr_complex_t i = IL->get (n * nlfreqs + f);
1366  if (f != 0 && f != lnfreqs - 1) i *= 2;
1367  I_(n * lnfreqs + f) = i;
1368  }
1369  }
1370 
1371  // use QR decomposition for the final solution
1372  try_running () {
1373  eqnsys<nr_complex_t> eqns;
1375  eqns.passEquationSys (NA, V, I);
1376  eqns.solve ();
1377  }
1378  // appropriate exception handling
1379  catch_exception () {
1380  case EXCEPTION_PIVOT:
1381  default:
1382  logprint (LOG_ERROR, "WARNING: %s: during final AC analysis\n",
1383  getName ());
1384  estack.print ();
1385  }
1386  for (int i = 0; i < N; i++) x->set (i, V_(i));
1387 }
1388 
1389 // Saves simulation results.
1391  vector * f;
1392  // add current frequency to the dependency of the output dataset
1393  if ((f = data->findDependency ("hbfrequency")) == NULL) {
1394  f = new vector ("hbfrequency");
1395  data->addDependency (f);
1396  }
1397  // save frequency vector
1398  if (runs == 1) {
1399  for (int i = 0; i < lnfreqs; i++) f->add (rfreqs (i));
1400  }
1401  // save node voltage vectors
1402  int nanode = 0;
1403  for (strlistiterator it (nanodes); *it; ++it, nanode++) {
1404  int l = strlen (*it);
1405  char * n = (char *) malloc (l + 4);
1406  sprintf (n, "%s.Vb", *it);
1407  for (int i = 0; i < lnfreqs; i++) {
1408  saveVariable (n, x->get (i + nanode * lnfreqs), f);
1409  }
1410  }
1411 }
1412 
1413 // properties
1414 PROP_REQ [] = {
1415  { "n", PROP_INT, { 1, PROP_NO_STR }, PROP_MIN_VAL (1) },
1416  PROP_NO_PROP };
1417 PROP_OPT [] = {
1418  { "f", PROP_REAL, { 1e9, PROP_NO_STR }, PROP_POS_RANGEX },
1419  { "iabstol", PROP_REAL, { 1e-12, PROP_NO_STR }, PROP_RNG_X01I },
1420  { "vabstol", PROP_REAL, { 1e-6, PROP_NO_STR }, PROP_RNG_X01I },
1421  { "reltol", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_RNG_X01I },
1422  { "MaxIter", PROP_INT, { 150, PROP_NO_STR }, PROP_RNGII (2, 10000) },
1423  PROP_NO_PROP };
1424 struct define_t hbsolver::anadef =
1426 
1427 /* TODO list for HB Solver:
1428  - Take care about nodes with non-linear components only.
1429  - AC Power Sources (extra Z and open loop voltage).
1430  - Current sources.
1431  - Balancing of multi-dimensional non-linear networks.
1432  - Sources directly connected to non-linear components and no other
1433  linear component (insert short).
1434  - Bug: With capacitors at hand there is voltage convergence but no
1435  current balancing.
1436  - Output currents through voltage sources.
1437  */