My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
eqndefined.cpp
Go to the documentation of this file.
1 /*
2  * eqndefined.cpp - equation defined device class implementation
3  *
4  * Copyright (C) 2007 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: eqndefined.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 "component.h"
30 #include "equation.h"
31 #include "environment.h"
32 #include "device.h"
33 #include "eqndefined.h"
34 
35 using namespace eqn;
36 
37 // Constructor for the equation defined device.
38 eqndefined::eqndefined () : circuit () {
39  type = CIR_EQNDEFINED;
40  setVariableSized (true);
41  veqn = NULL;
42  ieqn = NULL;
43  qeqn = NULL;
44  geqn = NULL;
45  ceqn = NULL;
46  _jstat = NULL;
47  _jdyna = NULL;
48  _charges = NULL;
49 }
50 
51 // Destructor deletes equation defined device object from memory.
53  if (veqn) free (veqn);
54  if (ieqn) free (ieqn);
55  if (geqn) free (geqn);
56  if (qeqn) free (qeqn);
57  if (ceqn) free (ceqn);
58  if (_jstat) free (_jstat);
59  if (_jdyna) free (_jdyna);
60  if (_charges) free (_charges);
61 }
62 
63 // Callback for initializing the DC analysis.
64 void eqndefined::initDC (void) {
65  allocMatrixMNA ();
66  if (ieqn == NULL) initModel ();
67  doHB = false;
68 }
69 
70 // Some help macros.
71 #define A(a) ((assignment *) (a))
72 #define C(c) ((constant *) (c))
73 #define BP(n) real (getV (n * 2 + 0) - getV (n * 2 + 1))
74 
75 // Creates a variable name from the given arguments.
76 char * eqndefined::createVariable (const char * base, int n, bool pfx) {
77  char * str = strchr (getName (), '.');
78  if (str != NULL)
79  str = strrchr (str, '.') + 1;
80  else
81  str = getName ();
82  char * txt = (char *) malloc (strlen (str) + strlen (base) + 3);
83  if (pfx)
84  sprintf (txt, "%s.%s%d", str, base, n);
85  else
86  sprintf (txt, "%s%d", base, n);
87  return txt;
88 }
89 
90 // Creates also a variable name from the given arguments.
91 char * eqndefined::createVariable (const char * base, int r, int c, bool pfx) {
92  char * str = strchr (getName (), '.');
93  if (str != NULL)
94  str = strrchr (str, '.') + 1;
95  else
96  str = getName ();
97  char * txt = (char *) malloc (strlen (str) + strlen (base) + 4);
98  if (pfx)
99  sprintf (txt, "%s.%s%d%d", str, base, r, c);
100  else
101  sprintf (txt, "%s%d%d", base, r, c);
102  return txt;
103 }
104 
105 // Saves the given value into the equation result.
106 void eqndefined::setResult (void * eqn, nr_double_t val) {
107  A(eqn)->evaluate ();
108  constant * c = A(eqn)->getResult ();
109  c->d = val;
110 }
111 
112 // Returns the result of the equation.
113 nr_double_t eqndefined::getResult (void * eqn) {
114  A(eqn)->evaluate ();
115  return A(eqn)->getResultDouble ();
116 }
117 
118 // Initializes the equation defined device.
119 void eqndefined::initModel (void) {
120  int i, j, k, branches = getSize () / 2;
121  char * in, * qn, * vn, * gn, * cn, * vnold, * inold;
122  eqn::node * ivalue, * qvalue, * diff;
123 
124  // allocate space for equation pointers
125  veqn = (void **) malloc (sizeof (assignment *) * branches);
126  ieqn = (void **) malloc (sizeof (assignment *) * branches);
127  geqn = (void **) malloc (sizeof (assignment *) * branches * branches);
128  qeqn = (void **) malloc (sizeof (assignment *) * branches);
129  ceqn = (void **) malloc (sizeof (assignment *) * branches * branches);
130 
131  // allocate space for Jacobians and charges
132  _jstat = (nr_double_t *) malloc (sizeof (nr_double_t) * branches * branches);
133  _jdyna = (nr_double_t *) malloc (sizeof (nr_double_t) * branches * branches);
134  _charges = (nr_double_t *) malloc (sizeof (nr_double_t) * branches);
135 
136  // first create voltage variables
137  for (i = 0; i < branches; i++) {
138  vn = createVariable ("V", i + 1);
139  if ((veqn[i] = getEnv()->getChecker()->findEquation (vn)) == NULL) {
140  veqn[i] = getEnv()->getChecker()->addDouble ("#voltage", vn, 0);
141  A(veqn[i])->evalType ();
142  A(veqn[i])->skip = 1;
143  }
144  free (vn);
145  }
146 
147  // prepare current and charge equations
148  for (i = 0; i < branches; i++) {
149 
150  // fetch current and charge equations
151  in = createVariable ("I", i + 1);
152  ivalue = getEnv()->getChecker()->findEquation (in);
153  if (!ivalue) {
154  logprint (LOG_ERROR, "ERROR: current equation `%s' not found for "
155  "EDD `%s'\n", in, getName ());
156  }
157  qn = createVariable ("Q", i + 1);
158  qvalue = getEnv()->getChecker()->findEquation (qn);
159  if (!qvalue) {
160  logprint (LOG_ERROR, "ERROR: charge equation `%s' not found for "
161  "EDD `%s'\n", qn, getName ());
162  }
163  free (in);
164  free (qn);
165 
166  // replace voltage and current references
167  for (j = 0; j < branches; j++) {
168  in = createVariable ("I", j + 1);
169  inold = createVariable ("I", j + 1, false);
170  vn = createVariable ("V", j + 1);
171  vnold = createVariable ("V", j + 1, false);
172  if (ivalue) {
173  ivalue->replace (vnold, vn);
174  ivalue->replace (inold, in);
175  }
176  if (qvalue) {
177  qvalue->replace (vnold, vn);
178  qvalue->replace (inold, in);
179  }
180  free (vnold); free (vn);
181  free (inold); free (in);
182  }
183 
184  // setup and save equations for currents and charges
185  ieqn[i] = ivalue;
186  qeqn[i] = qvalue;
187  }
188 
189  // evaluate types of currents and charges
190  for (i = 0; i < branches; i++) {
191  if (ieqn[i]) { A(ieqn[i])->evalType (); A(ieqn[i])->skip = 1; }
192  if (qeqn[i]) { A(qeqn[i])->evalType (); A(qeqn[i])->skip = 1; }
193  }
194 
195  // create derivatives of currents
196  for (k = 0, i = 0; i < branches; i++) {
197  ivalue = A(ieqn[i]);
198 
199  // create "static" differentiations
200  for (j = 0; j < branches; j++, k++) {
201  vn = createVariable ("V", j + 1);
202 
203  // create conductance equations
204  if (ivalue) {
205  gn = createVariable ("G", i + 1, j + 1);
206  if ((geqn[k] = getEnv()->getChecker()->findEquation (gn)) == NULL) {
207  diff = ivalue->differentiate (vn);
208  getEnv()->getChecker()->addEquation (diff);
209  diff->evalType ();
210  diff->skip = 1;
211  geqn[k] = diff;
212  A(diff)->rename (gn);
213  }
214  free (gn);
215 #if DEBUG
216  logprint (LOG_STATUS, "DEBUG: %s\n", A(geqn[k])->toString ());
217 #endif
218  }
219  else geqn[k] = NULL;
220 
221  free (vn);
222  }
223  }
224 
225  // create derivatives of charges
226  for (k = 0, i = 0; i < branches; i++) {
227  qvalue = A(qeqn[i]);
228 
229  // create "dynamic" differentiations
230  for (j = 0; j < branches; j++, k++) {
231  vn = createVariable ("V", j + 1);
232 
233  // create capacitance equations
234  if (qvalue) {
235  cn = createVariable ("C", i + 1, j + 1);
236  if ((ceqn[k] = getEnv()->getChecker()->findEquation (cn)) == NULL) {
237  diff = qvalue->differentiate (vn);
238  getEnv()->getChecker()->addEquation (diff);
239  diff->evalType ();
240  ceqn[k] = diff;
241  A(diff)->rename (cn);
242 
243  // apply dQ/dI * dI/dV => dQ/dV derivatives
244  for (int l = 0; l < branches; l++) {
245  in = createVariable ("I", l + 1);
246  diff = qvalue->differentiate (in);
247  A(diff)->mul (A(geqn[l * branches + j]));
248  A(ceqn[k])->add (A(diff));
249  delete diff;
250  free (in);
251  }
252  A(ceqn[k])->evalType ();
253  A(ceqn[k])->skip = 1;
254  }
255  free (cn);
256 #if DEBUG
257  logprint (LOG_STATUS, "DEBUG: %s\n", A(ceqn[k])->toString ());
258 #endif
259  }
260  else ceqn[k] = NULL;
261 
262  free (vn);
263  }
264  }
265 }
266 
267 // Update local variable equations.
268 void eqndefined::updateLocals (void) {
269  int i, branches = getSize () / 2;
270 
271  // update voltages for equations
272  for (i = 0; i < branches; i++) {
273  setResult (veqn[i], BP (i));
274  }
275  // get local subcircuit values
276  getEnv()->passConstants ();
277  getEnv()->equationSolver ();
278 }
279 
280 // Callback for DC analysis.
281 void eqndefined::calcDC (void) {
282  int i, j, k, branches = getSize () / 2;
283 
284  // update local equations
285  updateLocals ();
286 
287  // calculate currents and put into right-hand side
288  for (i = 0; i < branches; i++) {
289  nr_double_t c = getResult (ieqn[i]);
290  setI (i * 2 + 0, -c);
291  setI (i * 2 + 1, +c);
292  }
293 
294  // calculate derivatives and put into Jacobian and right-hand side
295  for (k = 0, i = 0; i < branches; i++) {
296  nr_double_t gv = 0;
297  // usual G (dI/dV) entries
298  for (j = 0; j < branches; j++, k++) {
299  nr_double_t g = getResult (geqn[k]);
300  setY (i * 2 + 0, j * 2 + 0, +g);
301  setY (i * 2 + 1, j * 2 + 1, +g);
302  setY (i * 2 + 0, j * 2 + 1, -g);
303  setY (i * 2 + 1, j * 2 + 0, -g);
304  gv += g * BP (j);
305  }
306  // during HB
307  if (doHB) {
308  setGV (i * 2 + 0, +gv);
309  setGV (i * 2 + 1, -gv);
310  }
311  // DC and transient analysis
312  else {
313  addI (i * 2 + 0, +gv);
314  addI (i * 2 + 1, -gv);
315  }
316  }
317 }
318 
319 // Evaluate operating points.
320 void eqndefined::evalOperatingPoints (void) {
321  int i, j, k, branches = getSize () / 2;
322 
323  // save values for charges, conductances and capacitances
324  for (k = 0, i = 0; i < branches; i++) {
325  nr_double_t q = getResult (qeqn[i]);
326  _charges[i] = q;
327  for (j = 0; j < branches; j++, k++) {
328  nr_double_t g = getResult (geqn[k]);
329  _jstat[k] = g;
330  nr_double_t c = getResult (ceqn[k]);
331  _jdyna[k] = c;
332  }
333  }
334 }
335 
336 // Saves operating points.
338 
339  // update local equations
340  updateLocals ();
341 
342  // save values for charges, conductances and capacitances
343  evalOperatingPoints ();
344 }
345 
346 // Callback for initializing the AC analysis.
347 void eqndefined::initAC (void) {
348  allocMatrixMNA ();
349  doHB = false;
350 }
351 
352 // Callback for AC analysis.
353 void eqndefined::calcAC (nr_double_t frequency) {
354  setMatrixY (calcMatrixY (frequency));
355 }
356 
357 // Computes Y-matrix for AC analysis.
358 matrix eqndefined::calcMatrixY (nr_double_t frequency) {
359  int i, j, k, branches = getSize () / 2;
360  matrix y (2 * branches);
361  nr_double_t o = 2 * M_PI * frequency;
362 
363  // merge conductances and capacitances
364  for (k = 0, i = 0; i < branches; i++) {
365  for (j = 0; j < branches; j++, k++) {
366  int r = i * 2;
367  int c = j * 2;
368  nr_complex_t val = rect (_jstat[k], o * _jdyna[k]);
369  y (r + 0, c + 0) = +val;
370  y (r + 1, c + 1) = +val;
371  y (r + 0, c + 1) = -val;
372  y (r + 1, c + 0) = -val;
373  }
374  }
375 
376  return y;
377 }
378 
379 // Callback for initializing the TR analysis.
380 void eqndefined::initTR (void) {
381  int branches = getSize () / 2;
382  setStates (2 * branches);
383  initDC ();
384 }
385 
386 // Callback for the TR analysis.
387 void eqndefined::calcTR (nr_double_t) {
388  int state, i, j, k, branches = getSize () / 2;
389 
390  // run usual DC iteration, then save operating points
391  calcDC ();
392 
393  // calculate Q and C
394  evalOperatingPoints ();
395 
396  // charge integrations
397  for (i = 0; i < branches; i++) {
398  int r = i * 2;
399  state = 2 * i;
400  transientCapacitanceQ (state, r + 0, r + 1, _charges[i]);
401  }
402 
403  // charge: 2-node, voltage: 2-node
404  for (k = 0, i = 0; i < branches; i++) {
405  for (j = 0; j < branches; j++, k++) {
406  int r = i * 2;
407  int c = j * 2;
408  nr_double_t v = BP (j);
409  transientCapacitanceC (r + 0, r + 1, c + 0, c + 1, _jdyna[k], v);
410  }
411  }
412 }
413 
414 // Callback for initializing the S-parameter analysis.
415 void eqndefined::initSP (void) {
416  allocMatrixS ();
417  doHB = false;
418 }
419 
420 // Callback for S-parameter analysis.
421 void eqndefined::calcSP (nr_double_t frequency) {
422  setMatrixS (ytos (calcMatrixY (frequency)));
423 }
424 
425 // Callback for initializing the HB analysis.
426 void eqndefined::initHB (int) {
427  allocMatrixHB ();
428  if (ieqn == NULL) initModel ();
429  doHB = true;
430 }
431 
432 // Callback for HB analysis.
433 void eqndefined::calcHB (int) {
434  int i, j, k, branches = getSize () / 2;
435 
436  // G's (dI/dV) into Y-Matrix and I's into I-Vector
437  calcDC ();
438 
439  // calculate Q and C
440  evalOperatingPoints ();
441 
442  // setup additional charge right-hand side
443  for (i = 0; i < branches; i++) {
444  setQ (i * 2 + 0, -_charges[i]);
445  setQ (i * 2 + 1, +_charges[i]);
446  }
447 
448  // fill in C's (dQ/dV) in QV-Matrix and CV into right hand side
449  for (k = 0, i = 0; i < branches; i++) {
450  nr_double_t cv = 0;
451  for (j = 0; j < branches; j++, k++) {
452  int r = i * 2;
453  int c = j * 2;
454  nr_double_t val = _jdyna[k];
455  setQV (r + 0, c + 0, +val);
456  setQV (r + 1, c + 1, +val);
457  setQV (r + 0, c + 1, -val);
458  setQV (r + 1, c + 0, -val);
459  cv += val * BP (j);
460  }
461  setCV (i * 2 + 0, +cv);
462  setCV (i * 2 + 1, -cv);
463  }
464 }
465 
466 // properties
467 PROP_REQ [] = {
468  { "I1", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
469  { "Q1", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
470  PROP_NO_PROP };
471 PROP_OPT [] = {
472  { "I2", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
473  { "Q2", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
474  { "I3", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
475  { "Q3", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
476  { "I4", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
477  { "Q4", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
478  { "I5", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
479  { "Q5", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
480  { "I6", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
481  { "Q6", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
482  { "I7", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
483  { "Q7", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
484  { "I8", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
485  { "Q8", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
486  PROP_NO_PROP };
487 struct define_t eqndefined::cirdef =
488  { "EDD",