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