/* c_microstrip.c
 * 
 * Copyright (C) 2002 Claudio Girardi <claudio.girardi@ieee.org>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA
 */

/* c_microstrip.c - Puts up window for coupled microstrips and 
 * performs the associated calculations
 * Based on the original microstrip.c by Gopal Narayanan 
 */


#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include <string.h>
#include <math.h>

#include "unitscombo.h"
#include "microstrip.h"
#include "c_microstrip.h"


/* the following definitions are just a quick hack for mingw32 */
#ifndef HAVE_ATANH
static double atanh(double x)
{
  return (0.5 * log((1.0 + x) / (1.0 - x)));
}
#endif

#ifndef HAVE_ASINH
static double asinh(double x)
{
  return log(x + sqrt(x * x + 1.0));
}
#endif

#ifndef HAVE_ACOSH
static double acosh(double x)
{
  return log(x + sqrt(x * x - 1.0));
}
#endif


static microstrip *aux_ms = NULL;

/*
 * skin_depth - calculate skin depth
 */

static gfloat skin_depth(c_microstrip * c_ms)
{
  gfloat mur, sigma, f;
  gfloat depth;

  mur = c_ms->mur;
  f = c_ms->f;
  sigma = c_ms->sigma;

  depth = 1.0 / (sqrt(M_PI * f * mur * MU0 * sigma));
  return depth;
}

/**
 * delta_u_thickness_single - compute the thickness effect on normalized width for a single microstrip line 
 * @u: normalized width
 * @t_h: normalized thickness
 *
 * delta_u_thickness_single() computes the thickness effect on normalized width for a single microstrip line
 *
 * References: 
 * H. A. Atwater, "Simplified Design Equations for Microstrip Line Parameters", Microwave Journal, pp. 109-115, November 1989.
 */
gfloat delta_u_thickness_single(gfloat u, gfloat t_h)
{
  gfloat delta_u;

  if (t_h > 0.0) {
    delta_u = (1.25 * t_h / M_PI) * (1.0 + log((2.0 + (4.0 * M_PI * u - 2.0) / (1.0 + exp(-100.0 * (u - 1.0 / (2.0 * M_PI))))) / t_h));
  } else {
    delta_u = 0.0;
  }

  /* fprintf(stderr, "delta_u_thickness_single = %e\n", delta_u); */

  return delta_u;
}

/**
 * delta_u_thickness - compute the thickness effect on normalized width
 * @c_ms: coupled microstrips structure pointer
 *
 * compute the thickness effect on normalized width for coupled microstrips
 *
 * References: Rolf Jansen, "High-Speed Cmputation of Single and Coupled Microstrip Parameters Including Dispersion, High-Order Modes, Loss and Finite Strip Thickness", IEEE Trans. MTT, vol. 26, no. 2, pp. 75-82, Feb. 1978
 *
 */
static void delta_u_thickness(c_microstrip * c_ms)
{
  gfloat e_r, s, h, w, t, u, g, t_h;
  gfloat delta_u, delta_t, delta_u_e, delta_u_o;

  e_r = c_ms->er;
  s = c_ms->s;
  h = c_ms->h;
  w = c_ms->w;
  t = c_ms->t;
  u = w / h;			/* normalized line width */
  g = s / h;			/* normalized line spacing */
  t_h = t / h;			/* normalized strip thickness */

  if (t_h > 0.0) {
    /* single microstrip correction for finite strip thickness */
    delta_u = delta_u_thickness_single(u, t_h);
    delta_t = t_h / (g * e_r);
    /* thickness correction for the even- and odd-mode */
    delta_u_e = delta_u * (1.0 - 0.5 * exp(-0.69 * delta_u / delta_t));
    delta_u_o = delta_u_e + delta_t;
  } else {
    delta_u_e = delta_u_o = 0.0;
  }

  c_ms->w_t_e = w + delta_u_e * h;
  c_ms->w_t_o = w + delta_u_o * h;

  /* fprintf(stderr, "w_t_e = %e\n", c_ms->w_t_e); */
  /* fprintf(stderr, "w_t_o = %e\n", c_ms->w_t_o); */
}


/**
 * compute_single_line() - compute various parameters for a single line
 * @c_ms: coupled microstrips structure pointer
 *
 * compute various parameters for a zero-thickness single microstrip line with geometrical dimensions taken from the coupled microstrips structure pointed by @c_ms.
 *
 * References: Manfred Kirschning and Rolf Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT, vol. 32, no. 1, Jan. 1984
 *
 * E. Hammerstad and O. Jensen, "Accurate Models for Microstrip Computer-Aided Design", IEEE MTT-S Symposium Digest, pp. 407-409, Jun. 1980
 */
static void compute_single_line(c_microstrip * c_ms)
{
  gfloat er, mur, h, w, s, ht, t;
  gfloat w_h, ht_h;
  gfloat Z0_single, er_eff_single;
//  microstrip *ms;

  er = c_ms->er;
  mur = c_ms->mur;
  h = c_ms->h;
  w = c_ms->w;
  s = c_ms->s;
  t = c_ms->t;
  ht = c_ms->ht;
  ht_h = ht / h;
  w_h = w / h;

  if (aux_ms == NULL)
    if ((aux_ms = g_malloc(sizeof *aux_ms)) == NULL)
      fprintf(stderr, "error allocating aux_ms!\n");

  /* prepare parameters for single microstrip computations */
  aux_ms->er = er;
  aux_ms->w = w;
  aux_ms->h = h;
  aux_ms->t = 0.0;
  //aux_ms->t = t;
  aux_ms->ht = 1e12;		/* arbitrarily high */
  aux_ms->f = c_ms->f;
  aux_ms->mur = mur;
  microstrip_Z0(aux_ms);
  microstrip_dispersion(aux_ms);

  er_eff_single = aux_ms->er_eff_0;
  Z0_single = aux_ms->Z0_0;

  //fprintf(stderr, "aux_ms->C = %e\n", sqrt(aux_ms->er_eff_0) / (C0 * aux_ms->Z0_0));
}


/**
 * filling_factor_even() - compute the filling factor for the coupled microstrips even-mode without cover and zero conductor thickness 
 * @u: normalized width
 * @g: normalized strips spacing
 * @e_r: relative dielectric constant
 */
gfloat filling_factor_even(gfloat u, gfloat g, gfloat e_r)
{
  gfloat v, v3, v4, a_e, b_e, q_inf;

  v = u * (20.0 + g * g) / (10.0 + g * g) + g * exp(-g);
  v3 = v * v * v;
  v4 = v3 * v;
  a_e = 1.0 + log((v4 + v * v / 2704.0) / (v4 + 0.432)) / 49.0 + log(1.0 + v3 / 5929.741)
    / 18.7;
  b_e = 0.564 * pow(((e_r - 0.9) / (e_r + 3.0)), 0.053);

  /* filling factor, with width corrected for thickness */
  q_inf = pow((1.0 + 10.0 / v), -a_e * b_e);

  return q_inf;
}

/**
 * filling_factor_odd() - compute the filling factor for the coupled microstrips odd-mode without cover and zero conductor thickness 
 * @u: normalized width
 * @g: normalized strips spacing
 * @e_r: relative dielectric constant
 */
gfloat filling_factor_odd(gfloat u, gfloat g, gfloat e_r)
{
  gfloat b_o, c_o, d_o, q_inf;

  b_o = 0.747 * e_r / (0.15 + e_r);
  c_o = b_o - (b_o - 0.207) * exp(-0.414 * u);
  d_o = 0.593 + 0.694 * exp(-0.562 * u);

  /* filling factor, with width corrected for thickness */
  q_inf = exp(-c_o * pow(g, d_o));

  return q_inf;
}


/**
 * delta_q_cover_even() - compute the cover effect on filling factor for the even-mode 
 * @h2h: normalized cover height
 */
gfloat delta_q_cover_even(gfloat h2h)
{
  gfloat q_c;

  if (h2h <= 39) {
    q_c = tanh(1.626 + 0.107 * h2h - 1.733 / sqrt(h2h));
  } else {
    q_c = 1.0;
  }

  return q_c;
}

/**
 * delta_q_cover_odd() - compute the cover effect on filling factor for the odd-mode 
 * @h2h: normalized cover height
 */
gfloat delta_q_cover_odd(gfloat h2h)
{
  gfloat q_c;

  if (h2h <= 7) {
    q_c = tanh(9.575 / (7.0 - h2h) - 2.965 + 1.68 * h2h - 0.311 * h2h * h2h);
  } else {
    q_c = 1.0;
  }

  return q_c;
}


/**
 * er_eff_static() - compute the static effective dielectric constants 
 * @c_ms: coupled microstrips structure pointer
 *
 * compute the static effective dielectric constants of the coupled microstrips structure pointed by @c_ms. 
 * References: Manfred Kirschning and Rolf Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT, vol. 32, no. 1, Jan. 1984
 */
static void er_eff_static(c_microstrip * c_ms)
{
  gfloat er, s, h, w_t_e, w_t_o, u_t_e, u_t_o, g, h2, h2h;
  gfloat a_o, t, t_h, q, q_c, q_t, q_inf;
  gfloat er_eff_single;

  /* compute zero-thickness single line parameters */
  compute_single_line(c_ms);
  er_eff_single = aux_ms->er_eff_0;

  er = c_ms->er;
  s = c_ms->s;
  h = c_ms->h;
  w_t_e = c_ms->w_t_e;
  w_t_o = c_ms->w_t_o;
  t = c_ms->t;
  h2 = c_ms->ht;
  u_t_e = w_t_e / h;		/* normalized even_mode line width */
  u_t_o = w_t_o / h;		/* normalized odd_mode line width */
  g = s / h;			/* normalized line spacing */
  h2h = h2 / h;			/* normalized cover height */
  t_h = t / h;			/* normalized strip thickness */

  /* filling factor, computed with thickness corrected width */
  q_inf = filling_factor_even(u_t_e, g, er);
  /* cover effect */
  q_c = delta_q_cover_even(h2h);
  /* thickness effect */
  q_t = delta_q_thickness(u_t_e, t_h);
  /* resultant filling factor */
  q = (q_inf - q_t) * q_c;
  /* static even-mode effective dielectric constant */
  c_ms->er_eff_e_0 = 0.5 * (er + 1.0) + 0.5 * (er - 1.0) * q;

  /* filling factor, with width corrected for thickness */
  q_inf = filling_factor_odd(u_t_o, g, er);
  /* cover effect */
  q_c = delta_q_cover_odd(h2h);
  /* thickness effect */
  q_t = delta_q_thickness(u_t_o, t_h);
  /* resultant filling factor */
  q = (q_inf - q_t) * q_c;

  a_o = 0.7287 * (er_eff_single - 0.5 * (er + 1.0)) * (1.0 - exp(-0.179 * u_t_o));

  /* static odd-mode effective dielectric constant */
  c_ms->er_eff_o_0 = (0.5 * (er + 1.0) + a_o - er_eff_single) * q + er_eff_single;
}


/**
 * delta_Z0_even_cover() - compute the even-mode impedance correction for a homogeneous microstrip due to the cover
 * @g: normalized strips spacing
 * @u: normalized width
 * @h2h: normalized cover height
 *
 * compute the even-mode impedance correction for a homogeneous microstrip due to the cover
 *
 * References:
 * S. March, "Microstrip Packaging: Watch the Last Step", Microwaves, vol. 20, no. 13, pp. 83.94, Dec. 1981.
 */
static gfloat delta_Z0_even_cover(gfloat g, gfloat u, gfloat h2h)
{
  gfloat f_e, g_e, delta_Z0_even;
  gfloat x, y, A, B, C, D, E, F;

  A = -4.351 / pow(1.0 + h2h, 1.842);
  B = 6.639 / pow(1.0 + h2h, 1.861);
  C = -2.291 / pow(1.0 + h2h, 1.90);
  f_e = 1.0 - atanh(A + (B + C * u) * u);

  x = pow(10.0, 0.103 * g - 0.159);
  y = pow(10.0, 0.0492 * g - 0.073);
  D = 0.747 / sin(0.5 * M_PI * x);
  E = 0.725 * sin(0.5 * M_PI * y);
  F = pow(10.0, 0.11 - 0.0947 * g);
  g_e = 270.0 * (1.0 - tanh(D + E * sqrt(1.0 + h2h) - F / (1.0 + h2h)));

  delta_Z0_even = f_e * g_e;

  return delta_Z0_even;
}


/**
 * delta_Z0_odd_cover() - compute the odd-mode impedance correction for a homogeneous microstrip due to the cover
 * @g: normalized strips spacing
 * @u: normalized width
 * @h2h: normalized cover height
 *
 * compute the odd-mode impedance correction for a homogeneous microstrip due to the cover
 *
 * References:
 * S. March, "Microstrip Packaging: Watch the Last Step", Microwaves, vol. 20, no. 13, pp. 83.94, Dec. 1981.
 */
static gfloat delta_Z0_odd_cover(gfloat g, gfloat u, gfloat h2h)
{
  gfloat f_o, g_o, delta_Z0_odd;
  gfloat G, J, K, L;

  J = tanh(pow(1.0 + h2h, 1.585) / 6.0);
  f_o = pow(u, J);

  G = 2.178 - 0.796 * g;
  if (g > 0.858) {
    K = log10(20.492 * pow(g, 0.174));
  } else {
    K = 1.30;
  }
  if (g > 0.873) {
    L = 2.51 * pow(g, -0.462);
  } else {
    L = 2.674;
  }
  g_o = 270.0 * (1.0 - tanh(G + K * sqrt(1.0 + h2h) - L / (1.0 + h2h)));

  delta_Z0_odd = f_o * g_o;

  return delta_Z0_odd;
}

/**
 * Z0_even_odd() - compute the static even- and odd-mode static impedances 
 * @c_ms: coupled microstrips structure pointer
 *
 * compute the static even- and odd-mode static impedances 
 *
 * References: Manfred Kirschning and Rolf Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT, vol. 32, no. 1, Jan. 1984
 *
 */
static void Z0_even_odd(c_microstrip * c_ms)
{
  gfloat er_eff, s, h, h2, w_t_e, w_t_o, u_t_e, u_t_o, g, h2h;
  gfloat Q_1, Q_2, Q_3, Q_4, Q_5, Q_6, Q_7, Q_8, Q_9, Q_10;
  gfloat Z0_e_0, delta_Z0_e_0, Z0_o_0, delta_Z0_o_0, Z0_single, er_eff_single;

  s = c_ms->s;
  h = c_ms->h;
  h2 = c_ms->ht;
  w_t_e = c_ms->w_t_e;
  w_t_o = c_ms->w_t_o;
  u_t_e = w_t_e / h;		/* normalized even-mode line width */
  u_t_o = w_t_o / h;		/* normalized odd-mode line width */
  g = s / h;			/* normalized line spacing */
  h2h = h2 / h;			/* normalized cover height */

  Z0_single = aux_ms->Z0_0;
  er_eff_single = aux_ms->er_eff_0;

  /* even-mode */
  er_eff = c_ms->er_eff_e_0;
  Q_1 = 0.8695 * pow(u_t_e, 0.194);
  Q_2 = 1.0 + 0.7519 * g + 0.189 * pow(g, 2.31);
  Q_3 = 0.1975 + pow((16.6 + pow((8.4 / g), 6.0)), -0.387) + log(pow(g, 10.0) / (1.0 + pow(g / 3.4, 10.0))) / 241.0;
  Q_4 = 2.0 * Q_1 / (Q_2 * (exp(-g) * pow(u_t_e, Q_3) + (2.0 - exp(-g)) * pow(u_t_e, -Q_3)));
  /* static even-mode impedance */
  Z0_e_0 = Z0_single * sqrt(er_eff_single / er_eff) / (1.0 - sqrt(er_eff_single) * Q_4 * Z0_single / 377.0);
  /* correction for cover */
  delta_Z0_e_0 = delta_Z0_even_cover(g, u_t_e, h2h) / sqrt(er_eff);

  c_ms->Z0_e_0 = Z0_e_0 - delta_Z0_e_0;

  /* odd-mode */
  er_eff = c_ms->er_eff_o_0;
  Q_5 = 1.794 + 1.14 * log(1.0 + 0.638 / (g + 0.517 * pow(g, 2.43)));
  Q_6 = 0.2305 + log(pow(g, 10.0) / (1.0 + pow(g / 5.8, 10.0))) / 281.3 + log(1.0 + 0.598 * pow(g, 1.154)) / 5.1;
  Q_7 = (10.0 + 190.0 * g * g) / (1.0 + 82.3 * g * g * g);
  Q_8 = exp(-6.5 - 0.95 * log(g) - pow(g / 0.15, 5.0));
  Q_9 = log(Q_7) * (Q_8 + 1.0 / 16.5);
  Q_10 = (Q_2 * Q_4 - Q_5 * exp(log(u_t_o) * Q_6 * pow(u_t_o, -Q_9))) / Q_2;

  /* static odd-mode impedance */
  Z0_o_0 = Z0_single * sqrt(er_eff_single / er_eff) / (1.0 - sqrt(er_eff_single) * Q_10 * Z0_single / 377.0);
  /* correction for cover */
  delta_Z0_o_0 = delta_Z0_odd_cover(g, u_t_o, h2h) / sqrt(er_eff);

  c_ms->Z0_o_0 = Z0_o_0 - delta_Z0_o_0;

  //fprintf(stderr, "Z0e = %e\n", c_ms->Z0e);
  //fprintf(stderr, "Z0o = %e\n", c_ms->Z0o);
}

/**
 * mur_eff() - returns effective magnetic permeability 
 * @c_ms: coupled microstrips structure pointer
 *
 * CURRENTLY NOT SUPPORTED !
 *
 **/
static gfloat mur_eff(c_microstrip * c_ms)
{
  gfloat mureff;

  mureff = c_ms->mur;		/* FIXME: ... */

  return mureff;
}


/**
 * er_eff_freq() - compute er_eff as a function of frequency 
 * @c_ms: coupled microstrips structure pointer
 *
 * compute the effective relative dielectric permettivity as a function of frequency 
 *
 * References: Manfred Kirschning and Rolf Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT, vol. 32, no. 1, Jan. 1984
 *
 */
static void er_eff_freq(c_microstrip * c_ms)
{
  gfloat P_1, P_2, P_3, P_4, P_5, P_6, P_7;
  gfloat P_8, P_9, P_10, P_11, P_12, P_13, P_14, P_15;
  gfloat F_e, F_o;
  gfloat er, er_eff, s, h, w, f, u, g, f_n;

  er = c_ms->er;
  s = c_ms->s;
  h = c_ms->h;
  w = c_ms->w;
  f = c_ms->f;
  u = w / h;			/* normalize line width */
  g = s / h;			/* normalize line spacing */

  /* normalized frequency [GHz * mm] */
  f_n = f * h / 1e06;

  er_eff = c_ms->er_eff_e_0;
  P_1 = 0.27488 + (0.6315 + 0.525 / pow(1.0 + 0.0157 * f_n, 20.0)) * u - 0.065683 * exp(-8.7513 * u);
  P_2 = 0.33622 * (1.0 - exp(-0.03442 * er));
  P_3 = 0.0363 * exp(-4.6 * u) * (1.0 - exp(-pow(f_n / 38.7, 4.97)));
  P_4 = 1.0 + 2.751 * (1.0 - exp(-pow(er / 15.916, 8.0)));
  P_5 = 0.334 * exp(-3.3 * pow(er / 15.0, 3.0)) + 0.746;
  P_6 = P_5 * exp(-pow(f_n / 18.0, 0.368));
  P_7 = 1.0 + 4.069 * P_6 * pow(g, 0.479) * exp(-1.347 * pow(g, 0.595) - 0.17 * pow(g, 2.5));

  F_e = P_1 * P_2 * pow((P_3 * P_4 + 0.1844 * P_7) * f_n, 1.5763);
  /* even-mode effective dielectric constant */
  c_ms->er_eff_e = er - (er - er_eff) / (1.0 + F_e);

  er_eff = c_ms->er_eff_o_0;
  P_8 = 0.7168 * (1.0 + 1.076 / (1.0 + 0.0576 * (er - 1.0)));
  P_9 = P_8 - 0.7193 * (1.0 - exp(-pow(f_n / 20.0, 1.424))) * atan(2.481 * pow(er / 8.0, 0.946));
  P_10 = 0.242 * pow(er - 1.0, 0.55);
  P_11 = 0.6366 * (exp(-0.3401 * f_n) - 1.0) * atan(1.263 * pow(u / 3.0, 1.629));
  P_12 = P_9 + (1.0 - P_9) / (1.0 + 1.183 * pow(u, 1.376));
  P_13 = 1.695 * P_10 / (0.414 + 1.605 * P_10);
  P_14 = 0.8928 + 0.1072 * (1.0 - exp(-0.42 * pow(f_n / 20.0, 3.215)));
  P_15 = fabs(1.0 - 0.8928 * (1.0 + P_11) * P_12 * exp(-P_13 * pow(g, 1.092)) / P_14);

  F_o = P_1 * P_2 * pow((P_3 * P_4 + 0.1844) * f_n * P_15, 1.5763);
  /* odd-mode effective dielectric constant */
  c_ms->er_eff_o = er - (er - er_eff) / (1.0 + F_o);
}


/**
 * conductor_losses() - compute microstrips conductor losses per unit length 
 * @c_ms: coupled microstrips structure pointer
 *
 * compute microstrips conductor losses per unit length 
 *
 * References: E. Hammerstad and O. Jensen, "Accurate Models for Microstrip Computer-Aided Design", IEEE MTT-S Symposium Digest, pp. 407-409, Jun. 1980
 *
 */
static void conductor_losses(c_microstrip * c_ms)
{
  gfloat f, w, e_r_eff_e_0, e_r_eff_o_0, Z0_h_e, Z0_h_o, delta, sigma, rough, tand;
  gfloat K, R_s, Q_c_e, Q_c_o, alpha_c_e, alpha_c_o;

  f = c_ms->f;
  w = c_ms->w;
  e_r_eff_e_0 = c_ms->er_eff_e_0;
  e_r_eff_o_0 = c_ms->er_eff_o_0;
  Z0_h_e = c_ms->Z0_e_0 * sqrt(e_r_eff_e_0);	/* homogeneous stripline impedance */
  Z0_h_o = c_ms->Z0_o_0 * sqrt(e_r_eff_o_0);	/* homogeneous stripline impedance */
  delta = c_ms->skindepth;
  sigma = c_ms->sigma;
  rough = c_ms->rough;
  tand = c_ms->tand;

  if (f > 0.0) {
    /* current distribution factor (same for the two modes) */
    K = exp(-1.2 * pow((Z0_h_e + Z0_h_o) / (2.0 * 377.0), 0.7));
    /* skin resistance */
    R_s = 1.0 / (sigma * delta);
    /* correction for surface roughness */
    R_s *= 1.0 + ((2.0 / M_PI) * atan(1.40 * pow((rough / delta), 2.0)));

    /* even-mode strip inductive quality factor */
    Q_c_e = (M_PI * Z0_h_e * w * f) / (R_s * C0 * K);
    /* even-mode losses per unith length */
    alpha_c_e = (20.0 * M_PI / log(10.0)) * f * sqrt(e_r_eff_e_0) / (C0 * Q_c_e);

    /* odd-mode strip inductive quality factor */
    Q_c_o = (M_PI * Z0_h_o * w * f) / (R_s * C0 * K);
    /* odd-mode losses per unith length */
    alpha_c_o = (20.0 * M_PI / log(10.0)) * f * sqrt(e_r_eff_o_0) / (C0 * Q_c_o);
  } else {
    alpha_c_e = alpha_c_o = 0.0;
  }

  c_ms->atten_cond_e = alpha_c_e * c_ms->l;
  c_ms->atten_cond_o = alpha_c_o * c_ms->l;
}


/** 
 * dielectric_losses() - compute microstrips dielectric losses per unit length
 * @c_ms: coupled microstrips structure pointer
 *
 * compute microstrips dielectric losses per unit length
 *
 * References: E. J. Denlinger, "Losses of microstrip lines", , IEEE Trans. MTT, vol. 28, no. 6, pp. 513-522, Jun. 1980
 *
 */
static void dielectric_losses(c_microstrip * c_ms)
{
  gfloat f, e_r, e_r_eff_e_0, e_r_eff_o_0, tand;
  gfloat alpha_d_e, alpha_d_o;

  f = c_ms->f;
  e_r = c_ms->er;
  e_r_eff_e_0 = c_ms->er_eff_e_0;
  e_r_eff_o_0 = c_ms->er_eff_o_0;
  tand = c_ms->tand;

  alpha_d_e = (20.0 * M_PI / log(10.0)) * (f / C0) * (e_r / sqrt(e_r_eff_e_0)) * ((e_r_eff_e_0 - 1.0) / (e_r - 1.0)) * tand;
  alpha_d_o = (20.0 * M_PI / log(10.0)) * (f / C0) * (e_r / sqrt(e_r_eff_o_0)) * ((e_r_eff_o_0 - 1.0) / (e_r - 1.0)) * tand;

  c_ms->atten_dielectric_e = alpha_d_e * c_ms->l;
  c_ms->atten_dielectric_o = alpha_d_o * c_ms->l;
}


/**
 * c_microstrip_attenuation() - compute attenuation of coupled microstrips 
 * @c_ms: coupled microstrips structure pointer
 *
 */
static void c_microstrip_attenuation(c_microstrip * c_ms)
{
  c_ms->skindepth = skin_depth(c_ms);

  conductor_losses(c_ms);
  dielectric_losses(c_ms);
}


/**
 * line_angle() - calculate strips electrical lengths in radians 
 * @c_ms: coupled microstrips structure pointer
 *
 */
static void line_angle(c_microstrip * c_ms)
{
  gfloat f, l, e_r_eff_e, e_r_eff_o;
  gfloat v_e, v_o, lambda_g_e, lambda_g_o, ang_l_e, ang_l_o;

  f = c_ms->f;
  l = c_ms->l;
  e_r_eff_e = c_ms->er_eff_e;
  e_r_eff_o = c_ms->er_eff_o;

  /* even-mode velocity */
  v_e = C0 / sqrt(e_r_eff_e);
  /* odd-mode velocity */
  v_o = C0 / sqrt(e_r_eff_o);
  /* even-mode wavelength */
  lambda_g_e = v_e / f;
  /* odd-mode wavelength */
  lambda_g_o = v_o / f;
  /* electrical angles */
  ang_l_e = 2.0 * M_PI * c_ms->l / lambda_g_e;	/* in radians */
  ang_l_o = 2.0 * M_PI * c_ms->l / lambda_g_o;	/* in radians */

  c_ms->ang_l_e = ang_l_e;
  c_ms->ang_l_o = ang_l_o;
}


void syn_err_fun(double *f1, double *f2, double s_h, double w_h, double e_r, double w_h_se, double w_h_so)
{

  double g, h;

  g = cosh(0.5 * M_PI * s_h);
  h = cosh(M_PI * w_h + 0.5 * M_PI * s_h);

  *f1 = (2.0 / M_PI) * acosh((2.0 * h - g + 1.0) / (g + 1.0));
  *f2 = (2.0 / M_PI) * acosh((2.0 * h - g - 1.0) / (g - 1.0));
  if (e_r <= 6.0) {
    *f2 += (4.0 / (M_PI * (1.0 + e_r / 2.0))) * acosh(1.0 + 2.0 * w_h / s_h);
  } else {
    *f2 += (1.0 / M_PI) * acosh(1.0 + 2.0 * w_h / s_h);
  }
  *f1 -= w_h_se;
  *f2 -= w_h_so;

  //g_print("syn_err_fun: f1 = %e\tf2 = %e\n", *f1, *f2);
}

/**
 * synth_width() - calculate widths given Z0 and e_r
 *
 * References: Akhtarzad S. et al., "The design of coupled microstrip lines", IEEE Trans. MTT-23, June 1975 
 *
 * Hinton, J.H., "On design of coupled microstrip lines", IEEE Trans. MTT-28, March 1980
 */
static void synth_width(c_microstrip * c_ms)
{
  gfloat Z0, Z0e, Z0o, e_r, h;
  gfloat w_h_se, w_h_so, w_h, a, ce, co, s_h;
  gdouble f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err;
  gdouble eps = 1e-04;

  e_r = c_ms->er;
  Z0e = c_ms->Z0e;
  Z0o = c_ms->Z0o;
  h = c_ms->h;

  Z0 = Z0e / 2.0;
  /* Wheeler formula for single microstrip synthesis */
  a = exp(Z0 * sqrt(e_r + 1.0) / 42.4) - 1.0;
  w_h_se = 8.0 * sqrt(a * ((7.0 + 4.0 / e_r) / 11.0) + ((1.0 + 1.0 / e_r) / 0.81)) / a;

  Z0 = Z0o / 2.0;
  /* Wheeler formula for single microstrip synthesis */
  a = exp(Z0 * sqrt(e_r + 1.0) / 42.4) - 1.0;
  w_h_so = 8.0 * sqrt(a * ((7.0 + 4.0 / e_r) / 11.0) + ((1.0 + 1.0 / e_r) / 0.81)) / a;

  ce = cosh(0.5 * M_PI * w_h_se);
  co = cosh(0.5 * M_PI * w_h_so);
  /* first guess at s/h */
  s_h = (2.0 / M_PI) * acosh((ce + co - 2.0) / (co - ce));
  /* first guess at w/h */
  w_h = acosh((ce * co - 1.0) / (co - ce)) / M_PI - s_h / 2.0;

  c_ms->s = s_h * h;
  c_ms->w = w_h * h;

  syn_err_fun(&f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so);

  /* rather crude Newton-Rhapson; we need this beacuse the estimate of */
  /* w_h is often quite far from the true value (see Akhtarzad S. et al.) */
  do {
    /* compute Jacobian */
    syn_err_fun(&ft1, &ft2, s_h + eps, w_h, e_r, w_h_se, w_h_so);
    j11 = (ft1 - f1) / eps;
    j21 = (ft2 - f2) / eps;
    syn_err_fun(&ft1, &ft2, s_h, w_h + eps, e_r, w_h_se, w_h_so);
    j12 = (ft1 - f1) / eps;
    j22 = (ft2 - f2) / eps;

    /* compute next step */
    d_s_h = (-f1 * j22 + f2 * j12) / (j11 * j22 - j21 * j12);
    d_w_h = (-f2 * j11 + f1 * j21) / (j11 * j22 - j21 * j12);
    //g_print("j11 = %e\tj12 = %e\tj21 = %e\tj22 = %e\n", j11, j12, j21, j22);
    //g_print("det = %e\n", j11*j22 - j21*j22);
    //g_print("d_s_h = %e\td_w_h = %e\n", d_s_h, d_w_h);

    s_h += d_s_h;
    w_h += d_w_h;

    /* chech the error */
    syn_err_fun(&f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so);

    err = sqrt(f1 * f1 + f2 * f2);
    /* converged ? */
  } while (err > 1e-04);


  c_ms->s = s_h * h;
  c_ms->w = w_h * h;
}


/**
 * Z0_dispersion() - calculate frequency dependency of characteristic impedances 
 * @c_ms: coupled microstrips structure pointer
 *
 */
static void Z0_dispersion(c_microstrip * c_ms)
{
  gfloat Q_0;
  gfloat Q_11, Q_12, Q_13, Q_14, Q_15, Q_16, Q_17, Q_18, Q_19, Q_20, Q_21;
  gfloat Q_22, Q_23, Q_24, Q_25, Q_26, Q_27, Q_28, Q_29;
  gfloat r_e, q_e, p_e, d_e, C_e;
  gfloat e_r_eff_o_f, e_r_eff_o_0;
  gfloat e_r_eff_single_f, e_r_eff_single_0, Z0_single_f;
  gfloat f_n, g, u, f, w, s, h, e_r;
  gfloat R_1, R_2, R_7, R_10, R_11, R_12, R_15, R_16, tmpf;

  f = c_ms->f;
  w = c_ms->w;
  s = c_ms->s;
  h = c_ms->h;
  e_r = c_ms->er;

  u = w / h;			/* normalize line width */
  g = s / h;			/* normalize line spacing */

  /* normalized frequency [GHz * mm] */
  f_n = f * h / 1e06;

  e_r_eff_single_f = aux_ms->er_eff;
  e_r_eff_single_0 = aux_ms->er_eff_0;
  Z0_single_f = aux_ms->Z0;

  e_r_eff_o_f = c_ms->er_eff_o;
  e_r_eff_o_0 = c_ms->er_eff_o_0;

  Q_11 = 0.893 * (1.0 - 0.3 / (1.0 + 0.7 * (e_r - 1.0)));
  Q_12 = 2.121 * (pow(f_n / 20.0, 4.91) / (1.0 + Q_11 * pow(f_n / 20.0, 4.91))) * exp(-2.87 * g) * pow(g, 0.902);
  Q_13 = 1.0 + 0.038 * pow(e_r / 8.0, 5.1);
  Q_14 = 1.0 + 1.203 * pow(e_r / 15.0, 4.0) / (1.0 + pow(e_r / 15.0, 4.0));
  Q_15 = 1.887 * exp(-1.5 * pow(g, 0.84)) * pow(g, Q_14) / (1.0 + 0.41 * pow(f_n / 15.0, 3.0) * pow(u, 2.0 / Q_13) / (0.125 + pow(u, 1.626 / Q_13)));
  Q_16 = (1.0 + 9.0 / (1.0 + 0.403 * pow(e_r - 1.0, 2))) * Q_15;
  Q_17 = 0.394 * (1.0 - exp(-1.47 * pow(u / 7.0, 0.672))) * (1.0 - exp(-4.25 * pow(f_n / 20.0, 1.87)));
  Q_18 = 0.61 * (1.0 - exp(-2.13 * pow(u / 8.0, 1.593))) / (1.0 + 6.544 * pow(g, 4.17));
  Q_19 = 0.21 * g * g * g * g / ((1.0 + 0.18 * pow(g, 4.19)) * (1.0 + 0.1 * u * u) * (1.0 + pow(f_n / 24.0, 3.0)));
  Q_20 = (0.09 + 1.0 / (1.0 + 0.1 * pow(e_r - 1, 2.7))) * Q_19;
  Q_21 = fabs(1.0 - 42.54 * pow(g, 0.133) * exp(-0.812 * g) * pow(u, 2.5) / (1.0 + 0.033 * pow(u, 2.5)));

  r_e = pow(f_n / 28.843, 12);
  q_e = 0.016 + pow(0.0514 * e_r * Q_21, 4.524);
  p_e = 4.766 * exp(-3.228 * pow(u, 0.641));
  d_e = 5.086 * q_e * (r_e / (0.3838 + 0.386 * q_e)) * (exp(-22.2 * pow(u, 1.92)) / (1.0 + 1.2992 * r_e)) * (pow(e_r - 1.0, 6.0) / (1.0 + 10 * pow(e_r - 1.0, 6.0)));
  C_e = 1.0 + 1.275 * (1.0 - exp(-0.004625 * p_e * pow(e_r, 1.674) * pow(f_n / 18.365, 2.745))) - Q_12 + Q_16 - Q_17 + Q_18 + Q_20;


  R_1 = 0.03891 * pow(e_r, 1.4);
  R_2 = 0.267 * pow(u, 7.0);
  R_7 = 1.206 - 0.3144 * exp(-R_1) * (1.0 - exp(-R_2));
  R_10 = 0.00044 * pow(e_r, 2.136) + 0.0184;
  tmpf = pow(f_n / 19.47, 6.0);
  R_11 = tmpf / (1.0 + 0.0962 * tmpf);
  R_12 = 1.0 / (1.0 + 0.00245 * u * u);
  R_15 = 0.707 * R_10 * pow(f_n / 12.3, 1.097);
  R_16 = 1.0 + 0.0503 * e_r * e_r * R_11 * (1.0 - exp(-pow(u / 15.0, 6.0)));
  Q_0 = R_7 * (1.0 - 1.1241 * (R_12 / R_16) * exp(-0.026 * pow(f_n, 1.15656) - R_15));

  /* even-mode frequency-dependent characteristic impedances */
  c_ms->Z0e = c_ms->Z0_e_0 * pow(0.9408 * pow(e_r_eff_single_f, C_e) - 0.9603, Q_0) / pow((0.9408 - d_e) * pow(e_r_eff_single_0, C_e) - 0.9603, Q_0);

  Q_29 = 15.16 / (1.0 + 0.196 * pow(e_r - 1.0, 2.0));
  tmpf = pow(e_r - 1.0, 3.0);
  Q_28 = 0.149 * tmpf / (94.5 + 0.038 * tmpf);
  tmpf = pow(e_r - 1.0, 1.5);
  Q_27 = 0.4 * pow(g, 0.84) * (1.0 + 2.5 * tmpf / (5.0 + tmpf));
  tmpf = pow((e_r - 1.0) / 13.0, 12.0);
  Q_26 = 30.0 - 22.2 * (tmpf / (1.0 + 3.0 * tmpf)) - Q_29;
  tmpf = (e_r - 1.0) * (e_r - 1.0);
  Q_25 = (0.3 * f_n * f_n / (10.0 + f_n * f_n)) * (1.0 + 2.333 * tmpf / (5.0 + tmpf));
  Q_24 = 2.506 * Q_28 * pow(u, 0.894) * pow((1.0 + 1.3 * u) * f_n / 99.25, 4.29) / (3.575 + pow(u, 0.894));
  Q_23 = 1.0 + 0.005 * f_n * Q_27 / ((1.0 + 0.812 * pow(f_n / 15.0, 1.9)) * (1.0 + 0.025 * u * u));
  Q_22 = 0.925 * pow(f_n / Q_26, 1.536) / (1.0 + 0.3 * pow(f_n / 30.0, 1.536));

  /* odd-mode frequency-dependent characteristic impedances */
  c_ms->Z0o = Z0_single_f + (c_ms->Z0_o_0 * pow(e_r_eff_o_f / e_r_eff_o_0, Q_22) - Z0_single_f * Q_23) / (1.0 + Q_24 + pow(0.46 * g, 2.2) * Q_25);
}


/**
 * calc_c_microstrip() - compute characteristics of a coupled microstrip lines structure
 * @c_ms: coupled microstrips structure pointer
 *
 * compute the characteristics of the coupled microstrips structure pointed by @c_ms. 
 * References: Manfred Kirschning and Rolf Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT, vol. 32, no. 1, Jan. 1984
 */
void calc_c_microstrip(c_microstrip * c_ms)
{
  /* compute thickness corrections */
  delta_u_thickness(c_ms);
  /* get effective dielectric constants */
  er_eff_static(c_ms);
  /* impedances for even- and odd-mode */
  Z0_even_odd(c_ms);
  /* calculate freq dependence of er_eff_e, er_eff_o */
  er_eff_freq(c_ms);
  /* FIXME: (not used) Get effective magnetic permeability */
  c_ms->mur_eff = mur_eff(c_ms);
  /* calculate frequency  dependence of Z0e, Z0o */
  Z0_dispersion(c_ms);
  /* calculate losses */
  c_microstrip_attenuation(c_ms);
  /* calculate electrical lengths */
  line_angle(c_ms);
}


/*
 * get_microstrip_sub
 * get and assign microstrip substrate parameters
 * into microstrip structure
 */

void get_c_microstrip_sub(trans_win * mwin, c_microstrip * c_ms)
{
  short curr_unit;

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->subparam_text[0])), "%g", &c_ms->er) != 1)
    error_mes("Error: c_ms->er");

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->subparam_text[1])), "%g", &c_ms->mur) != 1)
    error_mes("Error: c_ms->mur");

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->subparam_text[2])), "%g", &c_ms->h) != 1)
    error_mes("Error: c_ms->h");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->subparam_combo[2])->entry)));
  c_ms->h = c_ms->h * conv_length[curr_unit][LENGTH_M];

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->subparam_text[3])), "%g", &c_ms->ht) != 1)
    error_mes("Error: c_ms->ht");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->subparam_combo[3])->entry)));
  c_ms->ht = c_ms->ht * conv_length[curr_unit][LENGTH_M];

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->subparam_text[4])), "%g", &c_ms->t) != 1)
    error_mes("Error: c_ms->t");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->subparam_combo[4])->entry)));
  c_ms->t = c_ms->t * conv_length[curr_unit][LENGTH_M];

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->subparam_text[5])), "%g", &c_ms->sigma) != 1)
    error_mes("Error: c_ms->sigma");
  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->subparam_text[6])), "%g", &c_ms->tand) != 1)
    error_mes("Error: c_ms->tand");
  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->subparam_text[7])), "%g", &c_ms->rough) != 1)
    error_mes("Error: c_ms->rough");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->subparam_combo[7])->entry)));
  c_ms->rough = c_ms->rough * conv_length[curr_unit][LENGTH_M];
}

/*
 * get_c_microstrip_comp
 * get and assign microstrip component parameters
 * into microstrip structure
 */

void get_c_microstrip_comp(trans_win * mwin, c_microstrip * c_ms)
{
  short curr_unit;

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->component_param_text[0])), "%g", &c_ms->f) != 1)
    error_mes("Error: c_ms->f");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->component_param_combo[0])->entry)));
  c_ms->f = c_ms->f * conv_freq[curr_unit][FREQ_HZ];
}

/*
 * get_c_microstrip_elec
 * get and assign microstrip electrical parameters
 * into microstrip structure
 */

void get_c_microstrip_elec(trans_win * mwin, c_microstrip * c_ms)
{
  short curr_unit;

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->electrical_param_text[0])), "%g", &c_ms->Z0e) != 1)
    error_mes("Error: c_ms->Z0e");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->electrical_param_combo[0])->entry)));
  c_ms->Z0e = c_ms->Z0e * conv_res[curr_unit][RES_OHM];

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->electrical_param_text[1])), "%g", &c_ms->Z0o) != 1)
    error_mes("Error: c_ms->Z0o");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->electrical_param_combo[1])->entry)));
  c_ms->Z0o = c_ms->Z0o * conv_res[curr_unit][RES_OHM];

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->electrical_param_text[2])), "%g", &c_ms->ang_l_e) != 1)
    error_mes("Error: c_ms->ang_l_e");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->electrical_param_combo[2])->entry)));
  c_ms->ang_l_e = c_ms->ang_l_e * conv_ang[curr_unit][ANG_RAD];
}


/*
 * get_c_microstrip_phys
 * get and assign microstrip physical parameters
 * into microstrip structure
 */

void get_c_microstrip_phys(trans_win * mwin, c_microstrip * c_ms)
{
  short curr_unit;

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->physical_param_text[0])), "%g", &c_ms->w) != 1)
    error_mes("Error: c_ms->w");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->physical_param_combo[0])->entry)));
  c_ms->w = c_ms->w * conv_length[curr_unit][LENGTH_M];

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->physical_param_text[1])), "%g", &c_ms->s) != 1)
    error_mes("Error: c_ms->s");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->physical_param_combo[1])->entry)));
  c_ms->s = c_ms->s * conv_length[curr_unit][LENGTH_M];

  if (sscanf(gtk_entry_get_text(GTK_ENTRY(mwin->physical_param_text[2])), "%g", &c_ms->l) != 1)
    error_mes("Error: c_ms->l");
  curr_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->physical_param_combo[2])->entry)));
  c_ms->l = c_ms->l * conv_length[curr_unit][LENGTH_M];
}


static void show_results(trans_win * mwin, c_microstrip * c_ms)
{
  gchar *text, *results;
  short required_unit;

  /*allocate memory for text */
  if ((text = (char *) malloc(10 * sizeof(char))) == NULL) {
    perror("text error: malloc");
    exit(-1);
  }

  required_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->electrical_param_combo[0])->entry)));
  sprintf(text, "%g", (float) (c_ms->Z0e * conv_res[RES_OHM][required_unit]));
  gtk_entry_set_text(GTK_ENTRY(mwin->electrical_param_text[0]), text);

  required_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->electrical_param_combo[1])->entry)));
  sprintf(text, "%g", (float) (c_ms->Z0o * conv_res[RES_OHM][required_unit]));
  gtk_entry_set_text(GTK_ENTRY(mwin->electrical_param_text[1]), text);

  required_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->electrical_param_combo[1])->entry)));
  sprintf(text, "%g", (float) (c_ms->ang_l_e * conv_ang[ANG_RAD][required_unit]));
  gtk_entry_set_text(GTK_ENTRY(mwin->electrical_param_text[2]), text);

  free(text);

  if ((text = (char *) malloc(500 * sizeof(char))) == NULL) {
    perror("results text error: malloc");
    exit(-1);
  }
  if ((results = (char *) malloc(500 * sizeof(char))) == NULL) {
    perror("results text error: malloc");
    exit(-1);
  }

  required_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->physical_param_combo[1])->entry)));
  sprintf(results, "er_eff_e = %.4g\n", c_ms->er_eff_e);
  sprintf(text, "er_eff_o = %.4g\n", c_ms->er_eff_o);
  strcat(results, text);
  sprintf(text, "Conductor Losses Even = %.4g dB\n", c_ms->atten_cond_e);
  strcat(results, text);
  sprintf(text, "Conductor Losses Odd = %.4g dB\n", c_ms->atten_cond_o);
  strcat(results, text);
  sprintf(text, "Dielectric Losses Even = %.4g dB\n", c_ms->atten_dielectric_e);
  strcat(results, text);
  sprintf(text, "Dielectric Losses Odd = %.4g dB\n", c_ms->atten_dielectric_o);
  strcat(results, text);

  required_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->subparam_combo[4])->entry)));
  sprintf(text, "Skin Depth = %.4g %s\n", (c_ms->skindepth * conv_length[LENGTH_M][required_unit]), length_unit_text(getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->subparam_combo[4])->entry)))));
  strcat(results, text);
  gtk_label_set(GTK_LABEL(mwin->results_text), results);

  free(results);
  free(text);
}


/*
 * analysis function
 */

void analyze_c_microstrip(GtkWidget * widget, trans_win * mwin)
{
  /*  trans_win *mwin = (trans_win *) data; */
  c_microstrip *c_ms;

  /*allocate memory for pointer mw */
  if ((c_ms = g_malloc(sizeof(c_microstrip))) != NULL) {
    /* Get and assign substrate parameters */
    get_c_microstrip_sub(mwin, c_ms);
    /* Get and assign component parameters */
    get_c_microstrip_comp(mwin, c_ms);
    /* Get and assign physical parameters */
    get_c_microstrip_phys(mwin, c_ms);

    /* compute coupled microstrip parameters */
    calc_c_microstrip(c_ms);
    /* print results in the subwindow */
    show_results(mwin, c_ms);

    if (statusexists) {
      if (statusint != CONSISTENT) {
	gtk_label_set_text(GTK_LABEL(mwin->status), "Values are consistent");
      }
    }
    statusint = CONSISTENT;
  } else {
    perror("malloc c_ms");
    exit(-1);
  }
}


void syn_fun(double *f1, double *f2, double s_h, double w_h, double Z0_e, double Z0_o, c_microstrip * c_ms)
{
  gfloat h;

  h = c_ms->h;
  c_ms->s = s_h * h;
  c_ms->w = w_h * h;

  /* compute coupled microstrip parameters */
  calc_c_microstrip(c_ms);

  *f1 = c_ms->Z0e - Z0_e;
  *f2 = c_ms->Z0o - Z0_o;
  //g_print("syn_fun: f1 = %e\tf2 = %e\n", *f1, *f2);
}

/*
 * synthesis function
 */
void synthesize_c_microstrip(GtkWidget * widget, trans_win * mwin)
{
  gchar *text;
  short required_unit;
  c_microstrip *c_ms = NULL;
  gfloat Z0_e, Z0_o;
  gdouble f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err;
  gdouble eps = 1e-04;
  gfloat h, w_h, s_h;

  /* allocate memory for pointer c_ms */
  if ((c_ms = g_malloc(sizeof(c_microstrip))) != NULL) {

    /* Get and assign substrate parameters */
    get_c_microstrip_sub(mwin, c_ms);

    /* Get and assign component parameters */
    get_c_microstrip_comp(mwin, c_ms);

    /* Get and assign electrical parameters */
    get_c_microstrip_elec(mwin, c_ms);

    /* Get and assign physical parameters */
    /* at present it is required only for getting strips length */
    get_c_microstrip_phys(mwin, c_ms);


    /* required value of Z0_e and Z0_o */
    Z0_e = c_ms->Z0e;
    Z0_o = c_ms->Z0o;

    /* calculate width and use for initial value in Newton's method */
    synth_width(c_ms);
    h = c_ms->h;
    w_h = c_ms->w / h;
    s_h = c_ms->s / h;

    /* rather crude Newton-Rhapson */
    do {
      /* compute Jacobian */
      syn_fun(&ft1, &ft2, s_h + eps, w_h, Z0_e, Z0_o, c_ms);
      j11 = (ft1 - f1) / eps;
      j21 = (ft2 - f2) / eps;
      syn_fun(&ft1, &ft2, s_h, w_h + eps, Z0_e, Z0_o, c_ms);
      j12 = (ft1 - f1) / eps;
      j22 = (ft2 - f2) / eps;

      /* compute next step; increments of s_h and w_h */
      d_s_h = (-f1 * j22 + f2 * j12) / (j11 * j22 - j21 * j12);
      d_w_h = (-f2 * j11 + f1 * j21) / (j11 * j22 - j21 * j12);
      //g_print("j11 = %e\tj12 = %e\tj21 = %e\tj22 = %e\n", j11, j12, j21, j22);
      //g_print("det = %e\n", j11*j22 - j21*j22);
      //g_print("d_s_h = %e\td_w_h = %e\n", d_s_h, d_w_h);

      s_h += d_s_h;
      w_h += d_w_h;

      /* compute the error with the new values of s_h and w_h */
      syn_fun(&f1, &f2, s_h, w_h, Z0_e, Z0_o, c_ms);
      err = sqrt(f1 * f1 + f2 * f2);

      /* converged ? */
    } while (err > 1e-04);

    /* denormalize computed width and spacing */
    c_ms->s = s_h * h;
    c_ms->w = w_h * h;

    /*allocate memory for text */
    if ((text = (char *) malloc(10 * sizeof(char))) == NULL) {
      perror("text error: malloc");
      exit(-1);
    }

    required_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->physical_param_combo[0])->entry)));
    sprintf(text, "%g", (float) (c_ms->w * conv_length[LENGTH_M][required_unit]));
    gtk_entry_set_text(GTK_ENTRY(mwin->physical_param_text[0]), text);

    required_unit = getunit(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(mwin->physical_param_combo[1])->entry)));
    sprintf(text, "%g", (float) (c_ms->s * conv_length[LENGTH_M][required_unit]));
    gtk_entry_set_text(GTK_ENTRY(mwin->physical_param_text[1]), text);

    calc_c_microstrip(c_ms);
    /* print results in the subwindow */
    show_results(mwin, c_ms);

    if (statusexists) {
      if (statusint != CONSISTENT) {
	gtk_label_set_text(GTK_LABEL(mwin->status), "Values are consistent");
      }
    }
    statusint = CONSISTENT;
  } else {
    perror("malloc c_ms");
    exit(-1);
  }
}


/*
 * the window aspect 
 */

/*void c_microstrip_win (GtkWidget *parent) */
void c_microstrip_win(GtkWidget * parent)
/*c_microstrip_win (trans_gui *tg) */
{
  short row;

  /* if there is a window that already exists kill it first */
  if (main_body_window != NULL) {
    gtk_widget_destroy(main_body_window);
    g_free (twin);
    twin = g_malloc(sizeof(*twin));
  }
  setup_transgui(C_MICROSTRIP, parent, twin);

  for (row = 0; row <= 1; row++) {
    gtk_widget_set_sensitive(GTK_WIDGET(twin->physical_param_fix[row]), FALSE);
  }

  gtk_signal_connect(GTK_OBJECT(twin->Analbutton), "clicked", GTK_SIGNAL_FUNC(analyze_c_microstrip), twin);

  gtk_signal_connect(GTK_OBJECT(twin->Synbutton), "clicked", GTK_SIGNAL_FUNC(synthesize_c_microstrip), twin);
  /*                  GTK_SIGNAL_FUNC (synthesize_c_microstrip), twin); */
  if (statusint == INCONSISTENT) {
    analyze_c_microstrip(parent, (trans_win *) twin);
  }
  for (row = 0; row <= 1; row++) {
    gtk_signal_connect(GTK_OBJECT(twin->electrical_param_text[row]), "changed", GTK_SIGNAL_FUNC(setstatus), twin);
  }


  /*  return twin; */
  /*  free(twin); */
}
