My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
spfile.cpp
Go to the documentation of this file.
1 /*
2  * spfile.cpp - S-parameter file class implementation
3  *
4  * Copyright (C) 2004, 2005, 2006, 2008, 2009 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: spfile.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 "matvec.h"
31 #include "dataset.h"
32 #include "strlist.h"
33 #include "poly.h"
34 #include "spline.h"
35 #include "interpolator.h"
36 #include "spfile.h"
37 
38 // Constructor for S-parameter file vector.
40  v = f = 0;
41  isreal = 1;
42  inter = NULL;
43  r = c = 0;
44 }
45 
46 // Destructor for S-parameter file vector.
48  if (inter) delete inter;
49 }
50 
51 // Passes vectors and their data types to the S-parameter file vector.
53  bool _isreal, int it, int dt) {
54  v = _v;
55  f = _f;
56  isreal = _isreal;
57  inter = new interpolator ();
58  if (isreal) {
59  inter->rvectors (v, f);
60  inter->prepare (it, REPEAT_NO, dt | DATA_REAL);
61  }
62  else {
63  inter->cvectors (v, f);
64  inter->prepare (it, REPEAT_NO, dt | DATA_COMPLEX);
65  }
66 }
67 
68 // Returns interpolated data.
70  if (isreal)
71  return inter->rinterpolate (x);
72  else
73  return inter->cinterpolate (x);
74 }
75 
76 // Constructor creates an empty and unnamed instance of the spfile class.
77 spfile::spfile () : circuit () {
78  data = NULL;
79  sfreq = nfreq = NULL;
80  spara = FMIN = SOPT = RN = NULL;
81  interpolType = dataType = 0;
82  type = CIR_SPFILE;
83  setVariableSized (true);
84 }
85 
86 // Destructor deletes spfile object from memory.
88  if (spara) delete[] spara;
89  if (RN) delete RN;
90  if (FMIN) delete FMIN;
91  if (SOPT) delete SOPT;
92 #if DEBUG && 0
93  if (data) {
94  data->setFile ("spfile.dat");
95  data->print ();
96  }
97 #endif
98  if (data) delete data;
99 }
100 
101 void spfile::calcSP (nr_double_t frequency) {
102 
103  // nothing to do if the given file type had errors
104  if (spara == NULL || sfreq == NULL) return;
105 
106  // set interpolated S-parameters
108 }
109 
110 /* This function returns the S-parameter matrix of the circuit for the
111  given frequency. It uses interpolation for frequency points which
112  are not part of the original touchstone file. */
113 matrix spfile::getInterpolMatrixS (nr_double_t frequency) {
114 
115  // first interpolate the matrix values
116  matrix s (getSize () - 1);
117  for (int r = 0; r < getSize () - 1; r++) {
118  for (int c = 0; c < getSize () - 1; c++) {
119  int i = r * getSize () + c;
120  s.set (r, c, spara[i].interpolate (frequency));
121  }
122  }
123 
124  // then convert them to S-parameters if necessary
125  switch (paraType) {
126  case 'Y':
127  s = ytos (s);
128  break;
129  case 'Z':
130  s = ztos (s);
131  break;
132  case 'H':
133  s = htos (s);
134  break;
135  case 'G':
136  s = gtos (s);
137  break;
138  }
139  return s;
140 }
141 
142 void spfile::calcNoiseSP (nr_double_t frequency) {
143  // nothing to do if the given file type had errors
144  if (spara == NULL || nfreq == NULL) return;
145  setMatrixN (calcMatrixCs (frequency));
146 }
147 
148 matrix spfile::calcMatrixCs (nr_double_t frequency) {
149  // set interpolated noise correlation matrix
150  nr_double_t r = real (RN->interpolate (frequency));
151  nr_double_t f = real (FMIN->interpolate (frequency));
152  nr_complex_t g = SOPT->interpolate (frequency);
153  matrix s = getInterpolMatrixS (frequency);
154  matrix n = correlationMatrix (f, g, r, s);
156  return c;
157 }
158 
159 /* This function expands the actual S-parameter file data stored
160  within the touchstone file to have an additional reference one-port
161  whose S-parameter is -1 (i.e. ground). */
163  assert (s.getCols () == s.getRows ());
164  int r, c, ports = s.getCols () + 1;
165  nr_double_t g = -1;
166  nr_complex_t fr, ss, sr, sc, sa;
167  matrix res (ports);
168 
169  // compute S'mm
170  for (sa = 0, r = 0; r < ports - 1; r++)
171  for (c = 0; c < ports - 1; c++) sa += s.get (r, c);
172  ss = (2 - g - ports + sa) / (1 - ports * g - sa);
173  res.set (ports - 1, ports - 1, ss);
174  fr = (1.0 - g * ss) / (1.0 - g);
175 
176  // compute S'im
177  for (r = 0; r < ports - 1; r++) {
178  for (sc = 0, c = 0; c < ports - 1; c++) sc += s.get (r, c);
179  res.set (r, ports - 1, fr * (1.0 - sc));
180  }
181 
182  // compute S'mj
183  for (c = 0; c < ports - 1; c++) {
184  for (sr = 0, r = 0; r < ports - 1; r++) sr += s.get (r, c);
185  res.set (ports - 1, c, fr * (1.0 - sr));
186  }
187 
188  // compute S'ij
189  for (r = 0; r < ports - 1; r++) {
190  for (c = 0; c < ports - 1; c++) {
191  fr = g * res (r, ports - 1) * res (ports - 1, c) / (1.0 - g * ss);
192  res.set (r, c, s.get (r, c) - fr);
193  }
194  }
195 
196  return res;
197 }
198 
199 /* The function is the counterpart of the above expandSParaMatrix()
200  function. It shrinks the S-parameter matrix by removing the
201  reference port. */
203  assert (s.getCols () == s.getRows () && s.getCols () > 0);
204  int r, c, ports = s.getCols ();
205  nr_double_t g = -1;
206  matrix res (ports - 1);
207 
208  // compute S'ij
209  for (r = 0; r < ports - 1; r++) {
210  for (c = 0; c < ports - 1; c++) {
211  res.set (r, c, s (r, c) + g * s (r, ports - 1) *
212  s (ports - 1, c) / (1.0 - g * s (ports - 1, ports - 1)));
213  }
214  }
215  return res;
216 }
217 
218 /* This function expands the actual noise correlation matrix to have an
219  additional reference one-port whose S-parameter is -1
220  (i.e. ground). The given S-parameter matrix is required to perform
221  this transformation and is obtained using the expandSParaMatrix()
222  function. */
224  assert (s.getCols () == s.getRows () && n.getCols () == n.getRows () &&
225  n.getCols () == s.getCols () - 1);
226  nr_double_t T = getPropertyDouble ("Temp");
227  int r, c, ports = n.getCols () + 1;
228  nr_double_t g = -1;
229 
230  // create K matrix
231  matrix k (ports, ports - 1);
232  for (r = 0; r < ports - 1; r++) {
233  for (c = 0; c < ports - 1; c++) {
234  if (r == c)
235  k.set (r, c, 1.0 + g * (s.get (r, ports - 1) - 1.0));
236  else
237  k.set (r, c, g * s.get (r, ports - 1));
238  }
239  }
240  for (c = 0; c < ports - 1; c++)
241  k.set (ports - 1, c, g * s.get (ports - 1, ports - 1) - 1.0);
242 
243  // create D vector
244  matrix d (ports, 1);
245  for (r = 0; r < ports - 1; r++) d.set (r, 0, s.get (r, ports - 1));
246  d.set (ports - 1, 0, s.get (ports - 1, ports - 1) - 1.0);
247 
248  // expand noise correlation matrix
249  matrix res (ports);
250  res = (k * n * adjoint (k) - kelvin (T) / T0 * fabs (1 - norm (g)) *
251  d * adjoint (d)) * norm (1 / (1 - g));
252  return res;
253 }
254 
255 /* The function is the counterpart of the above expandNoiseMatrix()
256  function. It shrinks the noise correlation matrix by removing the
257  reference port. The given S-parameter matrix is required to perform
258  this transformation and is obtained using the expandSParaMatrix()
259  function. */
261  assert (s.getCols () == s.getRows () && n.getCols () == n.getRows () &&
262  n.getCols () == s.getCols () && n.getCols () > 0);
263  int r, ports = n.getCols ();
264  nr_double_t g = -1;
265  nr_double_t T = getPropertyDouble ("Temp");
266 
267  // create K' matrix
268  matrix k (ports - 1, ports);
269  for (r = 0; r < ports - 1; r++) k.set (r, r, 1);
270  for (r = 0; r < ports - 1; r++)
271  k.set (r, ports - 1, g * s.get (r, ports - 1) /
272  (1.0 - g * s.get (ports - 1, ports - 1)));
273 
274  // create D' vector
275  matrix d (ports - 1, 1);
276  for (r = 0; r < ports - 1; r++) d.set (r, 0, s.get (r, ports - 1));
277 
278  // shrink noise correlation matrix
279  matrix res (ports - 1);
280  res = k * n * adjoint (k) + kelvin (T) / T0 * fabs (1.0 - norm (g)) /
281  norm (1.0 - g * s.get (ports - 1, ports - 1)) * d * adjoint (d);
282  return res;
283 }
284 
285 void spfile::prepare (void) {
286 
287  // check type of data
288  char * type = getPropertyString ("Data");
289  if (!strcmp (type, "rectangular")) {
290  // rectangular data
291  dataType = DATA_RECTANGULAR;
292  }
293  else if (!strcmp (type, "polar")) {
294  // polar data
295  dataType = DATA_POLAR;
296  }
297 
298  // check type of interpolator
299  type = getPropertyString ("Interpolator");
300  if (!strcmp (type, "linear")) {
301  interpolType = INTERPOL_LINEAR;
302  }
303  else if (!strcmp (type, "cubic")) {
304  interpolType = INTERPOL_CUBIC;
305  }
306 
307  // load S-parameter file
308  char * file = getPropertyString ("File");
309  if (data == NULL) data = dataset::load_touchstone (file);
310  if (data != NULL) {
311  // determine the number of ports defined by that file
312  int ports = (int) sqrt ((double) data->countVariables ());
313  if (ports == getSize () - 1) {
314  if (spara == NULL) {
315  // find matrix vector entries in touchstone dataset
316  createIndex ();
317  }
318  if (sfreq == NULL) {
319  logprint (LOG_ERROR, "ERROR: file `%s' contains no `frequency' "
320  "vector\n", file);
321  }
322  }
323  else {
324  logprint (LOG_ERROR, "ERROR: file `%s' specifies a %d-port, `%s' "
325  "requires a %d-port\n", file, ports, getName (),
326  getSize () - 1);
327  }
328  }
329 }
330 
331 void spfile::initSP (void) {
332  // allocate S-parameter matrix
333  allocMatrixS ();
334  // initialize data
335  prepare ();
336 }
337 
338 /* The function creates an additional data vector for the given matrix
339  entry and adds it to the dataset. */
340 void spfile::createVector (int r, int c) {
341  int i = r * getSize () + c;
342  spara[i].r = r;
343  spara[i].c = c;
344  vector * v = new vector (matvec::createMatrixString ("S", r, c),
345  sfreq->getSize ());
346  v->setDependencies (new strlist ());
347  v->getDependencies()->add (sfreq->getName ());
348  data->addVariable (v);
349  spara[i].v = v;
350 }
351 
352 /* This function goes through the dataset stored within the original
353  touchstone file and looks for the S-parameter matrices and
354  frequency vector. It also tries to find the noise parameter
355  data. */
356 void spfile::createIndex (void) {
357  vector * v; int s = getSize (); char * n;
358  int r, c, i;
359 
360  // go through list of dependency vectors and find frequency vectors
361  for (v = data->getDependencies (); v != NULL; v = (vector *) v->getNext ()) {
362  if ((n = v->getName ()) != NULL) {
363  if (!strcmp (n, "frequency")) sfreq = v;
364  else if (!strcmp (n, "nfreq")) nfreq = v;
365  }
366  }
367 
368  // create vector index
369  spara = new spfile_vector[s * s] ();
370 
371  // go through list of variable vectors and find matrix entries
372  for (v = data->getVariables (); v != NULL; v = (vector *) v->getNext ()) {
373  if ((n = matvec::isMatrixVector (v->getName (), r, c)) != NULL) {
374  // save matrix vector indices
375  i = r * s + c;
376  spara[i].r = r;
377  spara[i].c = c;
378  spara[i].prepare (v, sfreq, false, interpolType, dataType);
379  paraType = n[0]; // save type of touchstone data
380  free (n);
381  }
382  if ((n = v->getName ()) != NULL) {
383  // find noise parameter vectors
384  if (!strcmp (n, "Rn")) {
385  RN = new spfile_vector ();
386  RN->prepare (v, nfreq, true, interpolType, dataType);
387  }
388  else if (!strcmp (n, "Fmin")) {
389  FMIN = new spfile_vector ();
390  FMIN->prepare (v, nfreq, true, interpolType, dataType);
391  }
392  else if (!strcmp (n, "Sopt")) {
393  SOPT = new spfile_vector ();
394  SOPT->prepare (v, nfreq, false, interpolType, dataType);
395  }
396  }
397  }
398 }
399 
400 /* This function computes the noise correlation matrix of a twoport
401  based upon the noise parameters and the given S-parameter
402  matrix. */
404  nr_double_t Rn, matrix s) {
405  assert (s.getCols () == s.getRows () && s.getCols () == 2);
406  matrix c (2);
407  nr_complex_t Kx = 4 * Rn / z0 / norm (1.0 + Sopt);
408  c.set (0, 0, (Fmin - 1) * (norm (s.get (0, 0)) - 1) +
409  Kx * norm (1.0 - s.get (0, 0) * Sopt));
410  c.set (1, 1, norm (s.get (1, 0)) * ((Fmin - 1) + Kx * norm (Sopt)));
411  c.set (0, 1, s.get (0, 0) / s.get (1, 0) * c.get (1, 1) -
412  conj (s.get (1, 0)) * conj (Sopt) * Kx);
413  c.set (1, 0, conj (c.get (0, 1)));
414  return c;
415 }
416 
417 /* The function computes the noise figure and noise parameters for the
418  given S-parameter and noise correlation matrices of a twoport. */
419 nr_double_t spfile::noiseFigure (matrix s, matrix c, nr_double_t& Fmin,
420  nr_complex_t& Sopt, nr_double_t& Rn) {
421  assert (s.getCols () == s.getRows () && c.getCols () == c.getRows () &&
422  s.getCols () == 2 && c.getCols () == 2);
423  nr_complex_t n1, n2;
424  n1 = c.get (0, 0) * norm (s.get (1, 0)) -
425  2 * real (c.get (0, 1) * s.get (1, 0) * conj (s.get (0, 0))) +
426  c.get (1, 1) * norm (s.get (0, 0));
427  n2 = 2.0 * (c.get (1, 1) * s.get (0, 0) -
428  c.get (0, 1) * s.get (1, 0)) / (c.get (1, 1) + n1);
429 
430  // optimal source reflection coefficient
431  Sopt = 1 - norm (n2);
432  if (real (Sopt) < 0.0)
433  Sopt = (1.0 + sqrt (Sopt)) / n2; // avoid a negative radicant
434  else
435  Sopt = (1.0 - sqrt (Sopt)) / n2;
436 
437  // minimum noise figure
438  Fmin = real (1.0 + (c.get (1, 1) - n1 * norm (Sopt)) /
439  norm (s.get (1, 0)) / (1.0 + norm (Sopt)));
440 
441  // equivalent noise resistance
442  Rn = real ((c (0, 0) - 2.0 *
443  real (c (0, 1) * conj ((1.0 + s (0, 0)) / s (1, 0))) +
444  c (1, 1) * norm ((1.0 + s (0, 0)) / s (1, 0))) / 4.0);
445  Rn = Rn * z0;
446 
447  // noise figure itself
448  return real (1.0 + c.get (1, 1) / norm (s.get (1, 0)));
449 }
450 
451 void spfile::initDC (void) {
452  // get appropriate property value
453  char * dc = getPropertyString ("duringDC");
454 
455  // a short during DC including the reference node
456  if (!strcmp (dc, "shortall")) {
457  int v, n, lastnode = getSize () - 1;
458  setVoltageSources (lastnode);
459  allocMatrixMNA ();
460  // place zero voltage sources
461  for (v = VSRC_1, n = NODE_1; n < lastnode; n++, v++) {
462  voltageSource (v, n, lastnode);
463  }
464  return;
465  }
466  // a short during DC excluding the reference node
467  if (!strcmp (dc, "short")) {
468  int v, n, lastnode = getSize () - 2;
469  setVoltageSources (lastnode);
470  allocMatrixMNA ();
471  // place zero voltage sources
472  for (v = VSRC_1, n = NODE_1; n < lastnode; n++, v++) {
473  voltageSource (v, n, lastnode);
474  }
475  return;
476  }
477  // an open during DC
478  else if (!strcmp (dc, "open")) {
479  setVoltageSources (0);
480  allocMatrixMNA ();
481  return;
482  }
483  // none specified, DC value of IDFT ?
484  else {
485  setVoltageSources (0);
486  allocMatrixMNA ();
487  }
488 }
489 
490 void spfile::initAC (void) {
491  setVoltageSources (0);
492  allocMatrixMNA ();
493  initSP ();
494 }
495 
496 void spfile::calcAC (nr_double_t frequency) {
497  // nothing to do if the given file type had errors
498  if (spara == NULL || sfreq == NULL) return;
499  // calculate interpolated S-parameters
500  calcSP (frequency);
501  // convert S-parameters to Y-parameters
502  setMatrixY (stoy (getMatrixS ()));
503 }
504 
505 void spfile::calcNoiseAC (nr_double_t frequency) {
506  // nothing to do if the given file type had errors
507  if (spara == NULL || nfreq == NULL) return;
508  setMatrixN (cstocy (calcMatrixCs (frequency), getMatrixY () * z0) / z0);
509 }
510 
511 void spfile::initTR (void) {
512  initDC ();
513 }
514 
515 // properties
516 PROP_REQ [] = {
517  { "File", PROP_STR, { PROP_NO_VAL, "spfile.snp" }, PROP_NO_RANGE },
518  PROP_NO_PROP };
519 PROP_OPT [] = {
520  { "Data", PROP_STR, { PROP_NO_VAL, "polar" },
521  PROP_RNG_STR2 ("rectangular", "polar") },
522  { "Interpolator", PROP_STR, { PROP_NO_VAL, "linear" },
523  PROP_RNG_STR2 ("linear", "cubic") },
524  { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
525  { "duringDC", PROP_STR, { PROP_NO_VAL, "open" },
526  PROP_RNG_STR4 ("open", "short", "shortall", "unspecified") },
527  PROP_NO_PROP };
528 struct define_t spfile::cirdef =
529  { "SPfile",