/* microstrip.c
 * 
 * Copyright (C) 2001 Gopal Narayanan <gopal@astro.umass.edu>
 * 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
 */


/* microstrip.c - Puts up window for microstrip 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"

/* this is 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


/*
 * skin_depth - calculate skin depth
 */

gfloat skin_depth(microstrip * ms)
{
  gfloat mur, sigma, f;
  gfloat depth;

  mur = ms->mur;
  f = ms->f;
  sigma = ms->sigma;

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


/* Z0_homogeneous() - compute the impedance for a stripline in a homogeneous medium, without cover effects */
gfloat Z0_homogeneous(gfloat u)
{
  gfloat f, Z0;

  f = 6.0 + (2.0 * M_PI - 6.0) * exp(-pow(30.666 / u, 0.7528));
  Z0 = (377.0 / (2.0 * M_PI)) * log(f / u + sqrt(1.0 + 4.0 / (u * u)));

  return Z0;
}


/* delta_Z0_cover() - compute the cover effect on impedance for a stripline in a homogeneous medium */
gfloat delta_Z0_cover(gfloat u, gfloat h2h)
{
  gfloat P, Q;
  gfloat h2hp1;

  h2hp1 = 1.0 + h2h;

  P = 270.0 * (1.0 - tanh(1.192 + 0.706 * sqrt(h2hp1) - 1.389 / h2hp1));
  Q = 1.0109 - atanh((0.012 * u + 0.177 * u * u - 0.027 * u * u * u) / (h2hp1 * h2hp1));

  return (P * Q);
}


/* filling_factor() - compute the filling factor for a microstrip without cover and zero conductor thickness */
gfloat filling_factor(gfloat u, gfloat e_r)
{
  gfloat a, b, q_inf;
  gfloat u2, u3, u4;

  u2 = u * u;
  u3 = u2 * u;
  u4 = u3 * u;

  a = 1.0 + log((u4 + u2 / 2704) / (u4 + 0.432)) / 49.0 + log(1.0 + u3 / 5929.741) / 18.7;
  b = 0.564 * pow((e_r - 0.9) / (e_r + 3.0), 0.053);

  q_inf = pow(1.0 + 10.0 / u, -a * b);

  return q_inf;
}


/* delta_q_cover() - compute the cover effect on filling factor */
gfloat delta_q_cover(gfloat h2h)
{
  gfloat q_c;

  q_c = tanh(1.043 + 0.121 * h2h - 1.164 / h2h);

  return q_c;
}


/* delta_q_thickness() - compute the thickness effect on filling factor */
gfloat delta_q_thickness(gfloat u, gfloat t_h)
{
  gfloat q_t;

  q_t = (2.0 * log(2.0) / M_PI) * (t_h / sqrt(u));

  return q_t;
}


/* e_r_effective() - compute effective dielectric constant from material e_r and filling factor */
gfloat e_r_effective(gfloat e_r, gfloat q)
{
  gfloat e_r_eff;

  e_r_eff = 0.5 * (e_r + 1.0) + 0.5 * q * (e_r - 1.0);

  return e_r_eff;
}


/* delta_u_thickness - compute the thickness effect on normalized width */
gfloat delta_u_thickness(gfloat u, gfloat t_h, gfloat e_r)
{
  gfloat delta_u;

  if (t_h > 0.0) {
    /* correction for thickness for a homogeneous microstrip */
    delta_u = (t_h / M_PI) * log(1.0 + (4.0 * M_E) * pow(tanh(sqrt(6.517 * u)), 2.0) / t_h);
    /* correction for strip on a substrate with relative permettivity e_r */
    delta_u = 0.5 * delta_u * (1.0 + 1.0 / cosh(sqrt(e_r - 1.0)));
  } else {
    delta_u = 0.0;
  }

  return delta_u;
}


/* microstrip_Z0() - compute microstrip static impedance */
void microstrip_Z0(microstrip * ms)
{
  gfloat e_r, h, w, h2, h2h, u, t, t_h;
  gfloat Z0_h_1, Z0_h_r, Z0;
  gfloat delta_u_1, delta_u_r, q_inf, q_c, q_t, e_r_eff, e_r_eff_t, q;

  e_r = ms->er;
  h = ms->h;
  w = ms->w;
  t = ms->t;
  h2 = ms->ht;
  h2h = h2 / h;
  u = w / h;
  t_h = t / h;

  /* compute normalized width correction for e_r = 1.0 */
  delta_u_1 = delta_u_thickness(u, t_h, 1.0);
  /* compute homogeneous stripline impedance */
  Z0_h_1 = Z0_homogeneous(u + delta_u_1);
  /* compute normalized width corection */
  delta_u_r = delta_u_thickness(u, t_h, e_r);
  u += delta_u_r;
  /* compute homogeneous stripline impedance */
  Z0_h_r = Z0_homogeneous(u);

  /* filling factor, with width corrected for thickness */
  q_inf = filling_factor(u, e_r);
  /* cover effect */
  q_c = delta_q_cover(h2h);
  /* thickness effect */
  q_t = delta_q_thickness(u, t_h);
  /* resultant filling factor */
  q = (q_inf - q_t) * q_c;

  /* e_r corrected for thickness and non homogeneous material */
  e_r_eff_t = e_r_effective(e_r, q);

  /* effective dielectric constant */
  e_r_eff = e_r_eff_t * pow(Z0_h_1 / Z0_h_r, 2.0);

  /* characteristic impedance, corrected for thickness, cover */
  /*   and non homogeneous material */
  Z0 = Z0_h_r / sqrt(e_r_eff_t);

  ms->Z0_h_1 = Z0_h_1;		/* will be used in attenuation calculations */
  ms->w_eff = u * h;
  ms->er_eff_0 = e_r_eff;
  ms->Z0_0 = Z0;
}


/* e_r_dispersion() - computes the dispersion correction factor for the effective permeability */
gfloat e_r_dispersion(gfloat u, gfloat e_r, gfloat f_n)
{
  gfloat P_1, P_2, P_3, P_4, P;

  P_1 = 0.27488 + u * (0.6315 + 0.525 / pow(1.0 + 0.0157 * f_n, 20.0)) - 0.065683 * exp(-8.7513 * u);
  P_2 = 0.33622 * (1.0 - exp(-0.03442 * e_r));
  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(e_r / 15.916, 8.0)));

  P = P_1 * P_2 * pow((P_3 * P_4 + 0.1844) * f_n, 1.5763);

  return P;
}


/* Z0_dispersion() - computes the dispersion correction factor for the characteristic impedance */
gfloat Z0_dispersion(gfloat u, gfloat e_r, gfloat e_r_eff_0, gfloat e_r_eff_f, gfloat f_n)
{
  gfloat R_1, R_2, R_3, R_4, R_5, R_6, R_7, R_8, R_9, R_10, R_11, R_12, R_13, R_14, R_15, R_16, R_17, D, tmpf;

  R_1 = 0.03891 * pow(e_r, 1.4);
  R_2 = 0.267 * pow(u, 7.0);
  R_3 = 4.766 * exp(-3.228 * pow(u, 0.641));
  R_4 = 0.016 + pow(0.0514 * e_r, 4.524);
  R_5 = pow(f_n / 28.843, 12.0);
  R_6 = 22.2 * pow(u, 1.92);
  R_7 = 1.206 - 0.3144 * exp(-R_1) * (1.0 - exp(-R_2));
  R_8 = 1.0 + 1.275 * (1.0 - exp(-0.004625 * R_3 * pow(e_r, 1.674) * pow(f_n / 18.365, 2.745)));
  tmpf = pow(e_r - 1.0, 6.0);
  R_9 = 5.086 * R_4 * (R_5 / (0.3838 + 0.386 * R_4)) * (exp(-R_6) / (1.0 + 1.2992 * R_5)) * (tmpf / (1.0 + 10.0 * tmpf));
  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_13 = 0.9408 * pow(e_r_eff_f, R_8) - 0.9603;
  R_14 = (0.9408 - R_9) * pow(e_r_eff_0, R_8) - 0.9603;
  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)));
  R_17 = R_7 * (1.0 - 1.1241 * (R_12 / R_16) * exp(-0.026 * pow(f_n, 1.15656) - R_15));

  D = pow(R_13 / R_14, R_17);

  return D;
}


/* microstrip_dispersion() - compute frequency dependent parameters of microstrip */
void microstrip_dispersion(microstrip * ms)
{
  gfloat e_r, h, w, f, Z0_0, e_r_eff_0;
  gfloat u, f_n, P, e_r_eff_f, D, Z0_f;

  e_r = ms->er;
  h = ms->h;
  w = ms->w;
  f = ms->f;
  Z0_0 = ms->Z0_0;
  e_r_eff_0 = ms->er_eff_0;
  u = w / h;

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

  P = e_r_dispersion(u, e_r, f_n);
  /* effective dielectric constant corrected for dispersion */
  e_r_eff_f = e_r - (e_r - e_r_eff_0) / (1.0 + P);

  D = Z0_dispersion(u, e_r, e_r_eff_0, e_r_eff_f, f_n);
  Z0_f = Z0_0 * D;

  ms->er_eff = e_r_eff_f;
  ms->Z0 = Z0_f;
}


/* conductor_losses() - compute microstrip conductor losses per unit length */
static gfloat conductor_losses(microstrip * ms)
{
  gfloat f, w, e_r_eff_0, Z0_h_1, delta, sigma, rough, tand;
  gfloat K, R_s, Q_c, alpha_c;

  f = ms->f;
  w = ms->w;
  e_r_eff_0 = ms->er_eff_0;
  Z0_h_1 = ms->Z0_h_1;		/* homogeneous stripline impedance */
  delta = ms->skindepth;
  sigma = ms->sigma;
  rough = ms->rough;
  tand = ms->tand;

  if (f > 0.0) {
    /* current distribution factor */
    K = exp(-1.2 * pow(Z0_h_1 / 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)));
    /* strip inductive quality factor */
    Q_c = (M_PI * Z0_h_1 * w * f) / (R_s * C0 * K);
    alpha_c = (20.0 * M_PI / log(10.0)) * f * sqrt(e_r_eff_0) / (C0 * Q_c);
  } else {
    alpha_c = 0.0;
  }

  return alpha_c;
}


/* dielectric_losses() - compute microstrip dielectric losses per unit length */
static gfloat dielectric_losses(microstrip * ms)
{
  gfloat f, e_r, e_r_eff_0, tand;
  gfloat alpha_d;

  f = ms->f;
  e_r = ms->er;
  e_r_eff_0 = ms->er_eff_0;
  tand = ms->tand;

  alpha_d = (20.0 * M_PI / log(10.0)) * (f / C0) * (e_r / sqrt(e_r_eff_0)) * ((e_r_eff_0 - 1.0) / (e_r - 1.0)) * tand;

  return alpha_d;
}


/* microstrip_attenuation() - compute attenuation of microstrip */
static void microstrip_attenuation(microstrip * ms)
{
  ms->skindepth = skin_depth(ms);

  ms->atten_cond = conductor_losses(ms) * ms->l;
  ms->atten_dielectric = dielectric_losses(ms) * ms->l;
}


/* mur_eff_ms - returns effective magnetic permeability */
static void mur_eff_ms(microstrip * ms)
{
  gfloat mur, h, w;
  gfloat mureff;

  mur = ms->mur;
  h = ms->h;
  w = ms->w;

  mureff = (2.0 * mur) / ((1.0 + mur) + ((1.0 - mur) * pow((1.0 + (10.0 * h / w)), -0.5)));

  ms->mur_eff = mureff;
}


/*
 * synth_width - calculate width given Z0 and e_r
 */

gfloat synth_width(microstrip * ms)
{
  gfloat Z0, e_r, a, b, h;
  gfloat w_h, w;


  e_r = ms->er;
  Z0 = ms->Z0;
  h = ms->h;


  a = ((Z0 / 60.) * sqrt((e_r + 1) / 2.)) + ((e_r - 1) / (e_r + 1) * (0.23 + (0.11 / e_r)));
  b = 60. * pow(M_PI, 2) / (Z0 * sqrt(e_r));

  if (a > 1.52) {
    w_h = 8 * exp(a) / (exp(2. * a) - 2);
  } else {
    w_h = (2. / M_PI) * (b - 1. - log((2 * b) - 1.) + ((e_r - 1) / (2 * e_r)) * (log(b - 1.) + 0.39 - 0.61 / e_r));
  }

  if (h > 0.0) {
    w = w_h * h;
    return w;
  } else {
    exit(-1);
  }
}


/* line_angle() - calculate microstrip length in radians */
static void line_angle(microstrip * ms)
{
  gfloat f, l, e_r_eff, mur_eff;
  gfloat v, lambda_g, ang_l;

  f = ms->f;
  l = ms->l;
  e_r_eff = ms->er_eff;
  mur_eff = ms->mur_eff;

  /* velocity */
  v = C0 / sqrt(e_r_eff * mur_eff);
  /* wavelength */
  lambda_g = v / f;
  /* electrical angles */
  ang_l = 2.0 * M_PI * l / lambda_g;	/* in radians */

  ms->ang_l = ang_l;
}


void calc_microstrip(microstrip * ms)
{
  /* effective permeability */
  mur_eff_ms(ms);
  /* static impedance */
  microstrip_Z0(ms);
  /* calculate freq dependence of er and Z0 */
  microstrip_dispersion(ms);
  /* calculate electrical lengths */
  line_angle(ms);
  /* calculate losses */
  microstrip_attenuation(ms);
}


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

void get_microstrip_sub(trans_win * mwin, microstrip * ms)
{
  short curr_unit;


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

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

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

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

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

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

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

void get_microstrip_comp(trans_win * mwin, microstrip * ms)
{
  short curr_unit;

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

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

void get_microstrip_elec(trans_win * mwin, microstrip * ms)
{
  short curr_unit;

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

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


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

void get_microstrip_phys(trans_win * mwin, microstrip * ms)
{
  short curr_unit;

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

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

}



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

  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->electrical_param_combo[0])->entry)));
  sprintf(text, "%g", (float) (ms->Z0 * 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) (ms->ang_l * conv_ang[ANG_RAD][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->physical_param_combo[1])->entry)));
  sprintf(results, "er_eff = %.4g\n", ms->er_eff);
  sprintf(text, "Conductor Losses = %.4g dB\n", ms->atten_cond);
  strcat(results, text);
  sprintf(text, "Dielectric Losses = %.4g dB\n", ms->atten_dielectric);

  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", (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_microstrip(GtkWidget * widget, trans_win * mwin)
{
  /*  trans_win *mwin = (trans_win *) data; */
  gchar *text;
  microstrip *ms;

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

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

    /* Get and assign substrate parameters */
    get_microstrip_sub(mwin, ms);

    /* Get and assign component parameters */
    get_microstrip_comp(mwin, ms);

    /* Get and assign physical parameters */
    get_microstrip_phys(mwin, ms);

    /* compute microstrip parameters */
    calc_microstrip(ms);

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

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


/*
 * synthesis function
 */

void synthesize_microstrip(GtkWidget * widget, trans_win * mwin)
{
  gchar *text;
  microstrip *ms;
  short required_unit;
  gfloat Z0, Z0_current, Z0_result, increment, slope, error;
  gint iteration;

  /*allocate memory for pointer mw */
  if ((ms = g_malloc(sizeof *ms)) != NULL) {

    /* Get and assign substrate parameters */
    get_microstrip_sub(mwin, ms);

    /* Get and assign component parameters */
    get_microstrip_comp(mwin, ms);

    /* Get and assign electrical parameters */
    get_microstrip_elec(mwin, ms);

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


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

    /* required value of Z0 */
    Z0 = ms->Z0;


    /* Newton's method */
    iteration = 0;

    /* compute microstrip parameters */
    calc_microstrip(ms);
    Z0_current = ms->Z0;

    error = fabs(Z0 - Z0_current);

    while (error > MAX_ERROR) {
      iteration++;
      increment = (ms->w / 100.0);
      ms->w += increment;
      /* compute microstrip parameters */
      calc_microstrip(ms);
      Z0_result = ms->Z0;
      /* f(w(n)) = Z0 - Z0(w(n)) */
      /* f'(w(n)) = -f'(Z0(w(n))) */
      /* f'(Z0(w(n))) = (Z0(w(n)) - Z0(w(n+delw))/delw */
      /* w(n+1) = w(n) - f(w(n))/f'(w(n)) */
      slope = (Z0_result - Z0_current) / increment;
      /* printf("%g\n",slope); */
      ms->w += (Z0 - Z0_current) / slope - increment;
      /*      printf("ms->w = %g\n", ms->w); */
      /* find new error */
      /* compute microstrip parameters */
      calc_microstrip(ms);
      Z0_current = ms->Z0;
      error = fabs(Z0 - Z0_current);
      /*      printf("Iteration = %d\n",iteration);
         printf("w = %g\t Z0 = %g\n",ms->w, Z0_current); */
      if (iteration > 100)
	break;
    }


    /*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) (ms->w * conv_length[LENGTH_M][required_unit]));
    gtk_entry_set_text(GTK_ENTRY(mwin->physical_param_text[0]), text);

    free(text);

    /* compute microstrip parameters */
    calc_microstrip(ms);
    /* print results in the subwindow */
    show_results(mwin, ms);

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

/*
 * the window aspect 
 */

/*void microstrip_win (GtkWidget *parent)*/
void microstrip_win(GtkWidget * parent)
/*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(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_microstrip), twin);

  gtk_signal_connect(GTK_OBJECT(twin->Synbutton), "clicked", GTK_SIGNAL_FUNC(synthesize_microstrip), twin);
  /*                  GTK_SIGNAL_FUNC (synthesize_microstrip), twin); */
  if (statusint == INCONSISTENT) {
    analyze_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); */
}
