My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
check_touchstone.cpp
Go to the documentation of this file.
1 /*
2  * check_touchstone.cpp - checker for Touchstone files
3  *
4  * Copyright (C) 2003, 2004, 2005, 2006 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: check_touchstone.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 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <math.h>
34 
35 #include "logging.h"
36 #include "complex.h"
37 #include "object.h"
38 #include "vector.h"
39 #include "matrix.h"
40 #include "matvec.h"
41 #include "dataset.h"
42 #include "strlist.h"
43 #include "constants.h"
44 #include "check_touchstone.h"
45 
46 #define ZREF 50.0 /* reference impedance */
47 
51 
52 /* default touchstone options */
54  "GHz", 'S', "MA", 50.0, 1e9, 0, 0, 0 };
55 
56 /* available touchstone options */
57 static const char * touchstone_valid_options[] = {
58  "hz", "khz", "mhz", "ghz", "s", "y", "z", "g", "h", "ma", "db", "ri", NULL };
59 
60 /* This subroutine is going to join vectors on multiple lines. The
61  input and output list of vectors of this function is the
62  touchstone_vector variable. */
63 static void touchstone_join (void) {
64  vector * yroot, * xroot, * next = NULL;
65  /* go through each vector */
66  for (yroot = touchstone_vector; yroot != NULL; yroot = next) {
67  /* go through each trailing vector */
68  next = (vector *) yroot->getNext ();
69  for (xroot = next; xroot != NULL; xroot = next) {
70  next = (vector *) xroot->getNext ();
71  /* append xroot vector to yroot vector (even no. of values) ? */
72  if ((xroot->getSize () & 1) == 0) {
73  /* yes, delete the xroot vector and adjust list */
74  yroot->add (xroot);
75  yroot->setNext (next);
76  delete xroot;
77  }
78  else {
79  /* no, handle next vectors */
80  next = xroot;
81  break;
82  }
83  }
84  }
85 }
86 
87 /* This subroutine checks the size and overall conformance of each
88  touchstone matrix at a given frequency derived from the first
89  matrix. The function return zero on success and non-zero
90  otherwise. */
91 static int touchstone_vector_check (void) {
92  vector * root = touchstone_vector, * next;
93  int even = 0, errors = 0, size = root->getSize (), noise = 0, lines = 1;
94  nr_double_t f = real (root->get (0));
95 
96  /* check size of first line */
97  if ((size & 1) == 0) {
98  logprint (LOG_ERROR, "checker error, first data line has %d (even) "
99  "values\n", size);
100  errors++;
101  even = 1;
102  }
103  /* first line determines the number of expected ports */
104  touchstone_options.ports = (int) sqrt ((size - 1) / 2.0);
105 
106  /* check first frequency value */
107  if (f < 0.0) {
108  logprint (LOG_ERROR, "checker error, negative data frequency "
109  "value %g\n", f);
110  errors++;
111  }
112 
113  /* go through each vector */
114  for (root = (vector *) root->getNext (); root != NULL; root = next) {
115  next = (vector *) root->getNext ();
116  nr_double_t freq = real (root->get (0));
117 
118  /* check increasing frequency value */
119  if (f >= freq) {
120  if (!noise) {
121  /* determined start of noise parameters */
122  noise++;
123  size = 5;
124  if (freq < 0.0) {
125  logprint (LOG_ERROR, "checker error, negative noise frequency "
126  "value %g\n", freq);
127  errors++;
128  }
129  }
130  else {
131  logprint (LOG_ERROR, "checker error, %s line (f = %g) has "
132  "decreasing frequency value\n", noise ? "noise" : "data",
133  freq);
134  errors++;
135  }
136  }
137  f = freq;
138 
139  /* check size of vector */
140  if (!even && root->getSize () != size) {
141  logprint (LOG_ERROR, "checker error, %s line (f = %g) has %d values, "
142  "%d required\n", noise ? "noise" : "data",
143  real (root->get (0)), root->getSize (), size);
144  errors++;
145  }
146 
147  /* count number of data lines without noise entries */
148  if (!noise) lines++;
149  }
150  touchstone_options.noise = noise;
151  touchstone_options.lines = lines;
152  return errors;
153 }
154 
155 /* The function evaluates the identifiers in the option line and fills
156  the touchstone_options structure with appropriate values. */
157 static void touchstone_options_eval (void) {
158  /* go through all identifiers */
159  for (int i = 0; i < touchstone_idents->length (); i++) {
160  char * str = touchstone_idents->get (i);
161  /* frequency unit */
162  if (!strcmp (str, "hz")) {
163  touchstone_options.factor = 1.0;
164  touchstone_options.unit = "Hz";
165  }
166  else if (!strcmp (str, "khz")) {
167  touchstone_options.factor = 1e3;
168  touchstone_options.unit = "kHz";
169  }
170  else if (!strcmp (str, "mhz")) {
171  touchstone_options.factor = 1e6;
172  touchstone_options.unit = "MHz";
173  }
174  else if (!strcmp (str, "ghz")) {
175  touchstone_options.factor = 1e9;
176  touchstone_options.unit = "GHz";
177  }
178  /* parameter type */
179  else if (!strcmp (str, "s")) {
180  touchstone_options.parameter = 'S';
181  }
182  else if (!strcmp (str, "y")) {
183  touchstone_options.parameter = 'Y';
184  }
185  else if (!strcmp (str, "z")) {
186  touchstone_options.parameter = 'Z';
187  }
188  else if (!strcmp (str, "g")) {
189  touchstone_options.parameter = 'G';
190  }
191  else if (!strcmp (str, "h")) {
192  touchstone_options.parameter = 'H';
193  }
194  /* value formats */
195  else if (!strcmp (str, "ma")) {
196  touchstone_options.format = "MA";
197  }
198  else if (!strcmp (str, "db")) {
199  touchstone_options.format = "dB";
200  }
201  else if (!strcmp (str, "ri")) {
202  touchstone_options.format = "RI";
203  }
204  }
205 }
206 
207 /* This little function returns a static string containing an
208  appropriate variable name. */
209 static char * touchstone_create_set (int r, int c) {
210  char * text;
211  text = matvec::createMatrixString (touchstone_options.parameter, r, c);
212  return text;
213 }
214 
215 /* The function actually creates the resulting dataset. */
216 static void touchstone_create (void) {
217  vector * f, * v, * root, * next, * nf = NULL;
218  int ports = touchstone_options.ports, n;
219  nr_complex_t val;
220  strlist * s;
221 
222  /* create dataset and frequency vector */
223  touchstone_result = new dataset ();
224  f = new vector ("frequency");
225  touchstone_result->appendDependency (f);
226  s = new strlist ();
227  s->add (f->getName ());
228  /* create variable vectors for the resulting dataset */
229  for (int r = 0; r < ports; r++) {
230  for (int c = 0; c < ports; c++) {
231  v = new vector ();
232  v->setName (touchstone_create_set (r, c));
233  v->setDependencies (new strlist (*s));
234  touchstone_result->appendVariable (v);
235  }
236  }
237  delete s;
238 
239  /* create noise vectors if necessary */
240  if (touchstone_options.noise) {
241  nf = new vector ("nfreq");
242  touchstone_result->appendDependency (nf);
243  s = new strlist ();
244  s->add (nf->getName ());
245  /* append noise parameters to dataset */
246  v = new vector ("Fmin");
247  v->setDependencies (new strlist (*s));
248  touchstone_result->appendVariable (v);
249  v = new vector ("Sopt");
250  v->setDependencies (new strlist (*s));
251  touchstone_result->appendVariable (v);
252  v = new vector ("Rn");
253  v->setDependencies (new strlist (*s));
254  touchstone_result->appendVariable (v);
255  delete s;
256  }
257 
258  /* go through each vector */
259  for (n = 0, root = touchstone_vector; root != NULL; root = next, n++) {
260  next = (vector *) root->getNext ();
261  // handle data lines
262  if (n < touchstone_options.lines) {
263  /* fill frequency vector */
264  f->add (real (root->get (0)) * touchstone_options.factor);
265  /* go through each variable vector */
266  v = touchstone_result->getVariables ();
267  for (int i = 0; i < ports; i++) {
268  for (int j = 0; j < ports; j++) {
269  int pos = 1 + j * 2 + i * 2 * ports;
270  /* handle special case for 2-port touchstone data, '21' data
271  precedes the '12' data */
272  if (ports == 2 && i != j) {
273  pos = 1 + i * 2 + j * 2 * ports;
274  }
275  /* depending on the touchstone data format */
276  if (!strcmp (touchstone_options.format, "RI")) {
277  val = rect (real (root->get (pos + 0)),
278  real (root->get (pos + 1)));
279  }
280  else if (!strcmp (touchstone_options.format, "MA")) {
281  val = polar (real (root->get (pos + 0)),
282  rad (real (root->get (pos + 1))));
283  }
284  else if (!strcmp (touchstone_options.format, "dB")) {
285  val = polar (pow (10.0, real (root->get (pos + 0)) / 20.0),
286  rad (real (root->get (pos + 1))));
287  }
288  v->add (val);
289  v = (vector *) v->getNext ();
290  }
291  }
292  }
293  // handle noise lines
294  else if (touchstone_options.noise) {
295  /* fill frequency vector */
296  nf->add (real (root->get (0)) * touchstone_options.factor);
297  /* fill minimum noise figure vector */
298  v = touchstone_result->findVariable ("Fmin");
299  val = pow (10.0, real (root->get (1)) / 10.0);
300  v->add (val);
301  /* fill optimal noise reflexion coefficient vector */
302  v = touchstone_result->findVariable ("Sopt");
303  val = polar (real (root->get (2)), rad (real (root->get (3))));
304  if (ZREF != touchstone_options.resistance) {
305  // re-normalize reflexion coefficient if necessary
306  nr_double_t r = (ZREF - touchstone_options.resistance) /
307  (ZREF + touchstone_options.resistance);
308  val = (val - r) / (1.0 - r * val);
309  }
310  v->add (val);
311  /* fill equivalent noise resistance vector */
312  v = touchstone_result->findVariable ("Rn");
313  val = real (root->get (4)) * touchstone_options.resistance;
314  v->add (val);
315  }
316  }
317 }
318 
319 /* The function re-normalizes S-parameters to the internal reference
320  impedance 50 Ohms. */
321 static void touchstone_normalize_sp (void) {
322  int ports = touchstone_options.ports;
323  vector * v = touchstone_result->getVariables ();
324  int i, j, n, len = v->getSize ();
325  matrix s = matrix (ports);
326 
327  // go through each matrix entry
328  for (n = 0; n < len; n++) {
329  v = touchstone_result->getVariables ();
330  // save entries in a temporary matrix
331  for (i = 0; i < ports; i++) {
332  for (j = 0; j < ports; j++) {
333  s.set (i, j, v->get (n));
334  v = (vector *) v->getNext ();
335  }
336  }
337  // convert the temporary matrix
338  s = stos (s, touchstone_options.resistance, ZREF);
339  v = touchstone_result->getVariables ();
340  // restore the results in the entries
341  for (i = 0; i < ports; i++) {
342  for (j = 0; j < ports; j++) {
343  v->set (s.get (i, j), n);
344  v = (vector *) v->getNext ();
345  }
346  }
347  }
348 }
349 
350 /* The function transforms the reference impedance given in the
351  touchstone file to the internal reference impedance 50 Ohms. */
352 static void touchstone_normalize (void) {
353  vector * v = touchstone_result->getVariables ();
354  int ports = touchstone_options.ports;
355 
356  // transform S-parameters if necessary
357  if (touchstone_options.parameter == 'S') {
358  if (touchstone_options.resistance != ZREF)
359  touchstone_normalize_sp ();
360  return;
361  }
362  // transform any other X-parameters
363  for (int i = 1; i <= ports; i++) {
364  for (int j = 1; j <= ports; j++) {
365  switch (touchstone_options.parameter) {
366  case 'Y': // Y-parameters
367  *v /= touchstone_options.resistance;
368  break;
369  case 'Z': // Z-parameters
370  *v *= touchstone_options.resistance;
371  break;
372  case 'G': // hybrid G-parameters
373  if (i == 1 && j == 1)
374  *v /= touchstone_options.resistance;
375  else if (i == 2 && j == 2)
376  *v *= touchstone_options.resistance;
377  break;
378  case 'H': // hybrid H-parameters
379  if (i == 1 && j == 1)
380  *v *= touchstone_options.resistance;
381  else if (i == 2 && j == 2)
382  *v /= touchstone_options.resistance;
383  break;
384  }
385  v = (vector *) v->getNext ();
386  }
387  }
388 }
389 
390 /* Removes temporary data items from memory if necessary. */
391 static void touchstone_finalize (void) {
392  vector * root, * next;
393  for (root = touchstone_vector; root != NULL; root = next) {
394  next = (vector *) root->getNext ();
395  delete root;
396  }
397  touchstone_vector = NULL;
398  if (touchstone_idents != NULL) {
399  delete touchstone_idents;
400  touchstone_idents = NULL;
401  }
403  /* apply default values again */
404  touchstone_options.unit = "GHz";
405  touchstone_options.parameter = 'S';
406  touchstone_options.format = "MA";
407  touchstone_options.resistance = 50.0;
408  touchstone_options.factor = 1e9;
409  touchstone_options.ports = 0;
410  touchstone_options.noise = 0;
411  touchstone_options.lines = 0;
412 }
413 
414 
415 /* This function is the checker routine for a parsed touchstone. It
416  returns zero on success or non-zero if the parsed touchstone
417  contained errors. */
418 int touchstone_check (void) {
419 
420  int i, n, errors = 0;
421 
422  /* first checking the options */
423  if (touchstone_idents->length () > 3) {
424  logprint (LOG_ERROR, "checker error, found %d options\n",
425  touchstone_idents->length ());
426  errors++;
427  }
428  /* touchstone is case insensitive */
429  for (i = 0; i < touchstone_idents->length (); i++) {
430  for (char * p = touchstone_idents->get (i); *p != '\0'; p++)
431  *p = tolower (*p);
432  }
433  /* check duplicate options */
434  for (i = 0; i < touchstone_idents->length (); i++) {
435  char * str = touchstone_idents->get (i);
436  if ((n = touchstone_idents->contains (str)) != 1) {
437  logprint (LOG_ERROR, "checker error, option `%s' occurred %dx\n",
438  str, n);
439  errors++;
440  }
441  }
442  /* check valid options */
443  for (i = 0; i < touchstone_idents->length (); i++) {
444  char * str = touchstone_idents->get (i);
445  int valid = 0;
446  for (int v = 0; touchstone_valid_options[v] != NULL; v++) {
447  if (!strcmp (touchstone_valid_options[v], str))
448  valid = 1;
449  }
450  if (!valid) {
451  logprint (LOG_ERROR, "checker error, invalid option `%s'\n", str);
452  errors++;
453  }
454  }
455 
456  /* evaluate the option line and put values into touchstone_options
457  structure */
458  touchstone_options_eval ();
459 
460  if (touchstone_vector == NULL) {
461  logprint (LOG_ERROR, "checker error, no data in touchstone file\n");
462  errors++;
463  }
464  else {
465  /* join vectors on multiple lines */
466  touchstone_join ();
467 
468  /* check each vector */
469  errors += touchstone_vector_check ();
470 
471  /* check validity of ports and parameters */
472  if ((touchstone_options.parameter == 'G' ||
473  touchstone_options.parameter == 'H') &&
474  touchstone_options.ports != 2) {
475  logprint (LOG_ERROR, "checker error, %c-parameters for %d-ports not "
476  "defined\n", touchstone_options.parameter,
477  touchstone_options.ports);
478  errors++;
479  }
480 
481  /* check noise parameter compatibility */
482  if (touchstone_options.noise && touchstone_options.ports != 2) {
483  logprint (LOG_ERROR, "checker error, noise parameters for %d-ports not "
484  "defined\n", touchstone_options.ports);
485  errors++;
486  }
487  }
488 
489  /* finally create a dataset */
490  if (!errors) {
491  touchstone_create ();
492  touchstone_normalize ();
493  }
494 
495 #if DEBUG
496  /* emit little notify message on successful loading */
497  if (!errors) {
498  logprint (LOG_STATUS, "NOTIFY: touchstone %d-port %c-data%s loaded\n",
499  touchstone_options.ports, touchstone_options.parameter,
500  touchstone_options.noise ? " including noise" : "");
501  }
502 #endif
503 
504  /* free temporary memory */
505  touchstone_finalize ();
506 
507  return errors ? -1 : 0;
508 }
509 
510 // Destroys data used by the Touchstone file lexer, parser and checker.
511 void touchstone_destroy (void) {
512  if (touchstone_result != NULL) {
513  // delete associated dataset
514  delete touchstone_result;
515  touchstone_result = NULL;
516  }
517  if (touchstone_vector != NULL) {
518  touchstone_finalize ();
519  touchstone_vector = NULL;
520  }
521 }
522 
523 // Initializes the Touchstone file checker.
524 void touchstone_init (void) {
525  touchstone_result = NULL;
526  touchstone_vector = NULL;
527  touchstone_idents = NULL;
528 }