/* generator.c  93.12.19
 * Copyright 1983-1992   Albert Davis
 * set up generator for transient analysis
 */
#include "ecah.h"
#include "error.h"
#include "io.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	void	cmd_generator(const char*,int*);
	double	gen(void);
/*--------------------------------------------------------------------------*/
#define ARGS 12
#define freq    argv[0]
#define ampl    argv[1]
#define phaz    argv[2]

#define maxv    argv[3]
#define minv    argv[4]
#define offset  argv[5]

#define init    argv[6]
#define rise    argv[7]
#define fall    argv[8]

#define delay   argv[9]
#define width   argv[10]
#define period  argv[11]

extern const struct ioctrl io;
extern double trtime0;
static double argv[ARGS] =
    { 0.   , 1.   , 0.    , 1.    , 0.    , 0.     ,
      0.   , 1e-12, 1e-12 , 0.    , 0.    , 0.     };
static const char *argnam[ARGS] =
    {"Freq","Ampl","Phase","MAx"  ,"MIn"  ,"Offset",
     "Init","Rise","Fall" ,"Delay","Width","PEriod"};
static int positive[ARGS] =
    { YES  , NO   , NO    , NO    , NO    , NO     ,
      NO   , YES  , YES   , YES   , YES   , YES    };
/*--------------------------------------------------------------------------*/
void cmd_generator(const char *cmd, int *cnt)
{
 int ii;                   /* iteration counter                    */
 int where;

 where = (cmd[*cnt])  ?  0  :  io.mstdout;

 for (ii=0;  ii<ARGS;  ++ii){       /* try to match each name in the list   */
    if (pmatch(cmd,cnt,argnam[ii])){            /* match the control name   */
       if (isfloat(cmd[*cnt]))                  /* if match, assign a value */
	  argv[ii] = (positive[ii])
		? fabs(ctof(cmd,cnt))
		:      ctof(cmd,cnt);
       ii = -1;                                /* start over               */
    }
 }

 syntax_check(cmd,cnt,bWARNING);

 for (ii=0;  ii<ARGS;  ++ii){
    mprintf( where, " %s=%s ", 
	    argnam[ii],
	    ftos(argv[ii], "", 6, 0));
 }
 mprintf( where, "\n" );
}
/*--------------------------------------------------------------------------*/
double gen(void)
{
 double loctime;
 double level;

 if (trtime0 <= delay)
    return init;
 loctime = trtime0 - delay;
 if (period > 0.){
    if    (loctime > period * 1048576.)
       error(bERROR, "step size much too large\n");
    while (loctime > period * 65536.)
       loctime -= period * 65536.;
    while (loctime > period * 4096.)		/* to improve code, */
       loctime -= period * 4096.;		/* use fmod.        */
    while (loctime > period * 256.)
       loctime -= period * 256.;
    while (loctime > period * 16.)
       loctime -= period * 16.;
    while (loctime > period)
       loctime -= period;
 }
 if (trtime0 <= delay + rise)                         /* initial rise */
    level = (maxv - 0) * (loctime/rise) + 0;
 else if (loctime <= rise)                           /* rising       */
    level = (maxv - minv) * (loctime/rise) + minv;
 else if (width==0.  ||  (loctime-=rise) <= width)   /* pulse on     */
    level = maxv;
 else if ((loctime-=width) <= fall)                  /* falling      */
    level = (minv - maxv) * (loctime/fall) + maxv;
 else                                                /* pulse off    */
    level = minv;
 level *= (freq == 0.) 
    ? ampl
    : ampl * sin(kPIx2*freq*(trtime0-delay) + phaz*DTOR);
 return (trtime0 <= delay + rise)
    ? level + (offset - init) * (loctime/rise) + init
    : level + offset;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
