/* d_trln.c  94.12.09
 * Copyright 1983-1992   Albert Davis
 * Transmission line. (ideal lossless.  for now, AC only)
 */
#include "ecah.h"
#include "ac.h"
#include "argparse.h"
#include "branch.h"
#include "d_trln.h"
#include "error.h"
#include "mode.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static 	void    parse_trnlin(branch_t*,const char*,int*);
static	void	setinitcond(const char*,int*);
static 	void	print_trnlin(const branch_t*,int,int);
static 	int	tr_trnlin(branch_t*);
static 	void	ac_trnlin(branch_t*);
/*--------------------------------------------------------------------------*/
#define LINLENTOL .000001
extern const ac_t ac;
static struct trnlin *x;
static struct trnlin defalt = {(generic_t*)NULL, sizeof(struct trnlin),
    DEFAULT_Z0, DEFAULT_TD, DEFAULT_F, DEFAULT_NL, {0.,0.,0.,0.}, 0., NO};
/*--------------------------------------------------------------------------*/
functions_t dev_trnlin = {
   (generic_t*)&defalt,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   (functions_t*)NULL,	/* super */
   4, 			/* numnodes */
   rnTWOPORT,		/* refnode */
   rnTWOPORT,		/* isdevice */
   create_std,		/* create */
   copy_std,		/* copy */
   parse_trnlin,	/* parse */
   print_trnlin,	/* print */
   NULL,		/* expand */
   NULL,		/* probe */
   NULL,		/* tr_probe */
   NULL,		/* ac_probe */
   NULL,		/* xprobe */
   tr_trnlin,		/* dotr */
   NULL,		/* untr */
   ac_trnlin,		/* doac */
   NULL,		/* trfun1 */
   NULL,		/* trfun0 */
   NULL,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
/*--------------------------------------------------------------------------*/
/* parse_trnlin: parse input for transmission line, set up branch structure
 */
static void parse_trnlin(branch_t *brh, const char *cmd, int *cnt)
{
 x = (struct trnlin*)brh->x;

 parselabel(brh,cmd,cnt);
 (void)parsenodes(brh,cmd,cnt);
 for (;;){
    if (argparse(cmd,cnt,REPEAT,
	"Z",	a2DOUBLE,   &x->z0,	&x->z0,
	"Freq",	aUDOUBLE,   &x->f,
	"Nl",	aUDOUBLE,   &x->nl,
	"Ic",	aFUNCTION,  setinitcond,
	""))
	;
    else{
	syntax_check(cmd,cnt,bWARNING);
	break;
    }
 }
 if (x->nl == 0.)
    x->nl = DEFAULT_NL;
 x->reson = x->f * (.25 / x->nl);
}
/*--------------------------------------------------------------------------*/
/* setinitcond: set initial conditions
 * called indirectly thru argparse
 * reads NUM_INIT_COND args, put them in static struct x.
 * passed this way because of inability of argparse to return values,
 * and that only cmd and cnt are passed by argparse
 */
static void setinitcond(const char *cmd, int *cnt)
{
 int i;
 x->icset = YES;
 for (i=0;  i<NUM_INIT_COND;  i++)
    x->ic[i] = ctof(cmd,cnt);
}
/*--------------------------------------------------------------------------*/
/* print_trnlin: print (to "where") the transmission line data structure
 */
static void print_trnlin(const branch_t *brh, int where, int detail)
{
 struct trnlin *x;
 (void)printlabel(brh,where);
 printnodes(brh,where);
 x = (struct trnlin*)brh->x;
 mprintf(where, "  Z0=%s  F=%s  NL=%s",
	ftos(x->z0, "", 7, 0),
	ftos(x->f,  "", 7, 0),
	ftos(x->nl, "", 7, 0));
 if (x->icset){
    int i;
    mprintf(where, "  IC=");
    for (i=0;  i<NUM_INIT_COND;  i++)
	mprintf(where, "%s ",ftos(x->ic[i],"", 7, 0));
 }
 mputc('\n', where);
}
/*--------------------------------------------------------------------------*/
/* tr_trnlin:  transmission line for transient analysis
 * stub: doesn't work
 * always returns failure
 */
static int tr_trnlin(branch_t *brh)
{
 error(bWARNING, "%s: no transmission line in dc or transient\n",
 		printlabel(brh,NO));
 return brh->converged = YES;
}
/*--------------------------------------------------------------------------*/
/* ac_trnlin:  transmission line procesing for AC analysis
 */
static void ac_trnlin(branch_t *brh)
{
 double y11, y12;	/* equivalent y parameters (y22, y21 are same)	    */
 double lenth;		/* length, first in quarter waves, then radians	    */
 double dif;		/* difference between actual length and resonance   */
 struct trnlin *x;

 x = (struct trnlin*)brh->x;

 lenth = ac.freq / x->reson;
 dif = lenth - floor(lenth+.5);
 if (fabs(dif) < LINLENTOL){						    
    error(bPICKY,
  	"%s: transmission line too close to resonance\n", printlabel(brh,NO));
    lenth = (dif<0.) ? floor(lenth+.5)-LINLENTOL : floor(lenth+.5)+LINLENTOL;
 }
 lenth *= (kPId2);					  /* now in radians */

 y12 = -1 / ( x->z0 * sin(lenth) );
 y11 = tan(lenth/2) / x->z0 + y12;

 *im(brh->n[OUT1].m,brh->n[OUT1].m) += y11; /* BUG: bypasses load functions */
 *im(brh->n[OUT2].m,brh->n[OUT2].m) += y11; /* result is flags may not be   */
 *im(brh->n[OUT1].m,brh->n[OUT2].m) -= y11; /* updated.  No problem yet in  */
 *im(brh->n[OUT2].m,brh->n[OUT1].m) -= y11; /* AC but this will not work in */
					    /* transient.		    */
 *im(brh->n[IN1].m,brh->n[IN1].m) += y11;
 *im(brh->n[IN2].m,brh->n[IN2].m) += y11;
 *im(brh->n[IN1].m,brh->n[IN2].m) -= y11;
 *im(brh->n[IN2].m,brh->n[IN1].m) -= y11;

 *im(brh->n[OUT1].m,brh->n[IN1].m) -= y12;
 *im(brh->n[OUT2].m,brh->n[IN2].m) -= y12;
 *im(brh->n[OUT1].m,brh->n[IN2].m) += y12;
 *im(brh->n[OUT2].m,brh->n[IN1].m) += y12;

 *im(brh->n[IN1].m,brh->n[OUT1].m) -= y12;
 *im(brh->n[IN2].m,brh->n[OUT2].m) -= y12;
 *im(brh->n[IN1].m,brh->n[OUT2].m) += y12;
 *im(brh->n[IN2].m,brh->n[OUT1].m) += y12;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
