This is sspice.c in view mode; [Download] [Up]
/***************************************************************************
* STEVE SPICE steve punte 10-24-87
*
* This program is frequency domain only version of spice. It
* was developed for the ece-149 class for the simulation of
* passive and active filters on standard IBM-ATs that normally
* have insufficient memory for even the reduced version of
* pspice. This program is written very flexibbly to request
* memory from the operating system as it is needed. Unfortionately
* the micro-soft C compiler requires that the maximum amount of
* memory ever needed be stated before hand. Never the less
* this is a portable program to any system that compiles C.
*
*****************************************************************************
*
* This is the header file. All global variables are defined here.
* If this file is used in file "main", then the phrase "extern"
* is stripped of from all declarations. Otherwise it remains for
* use in other files.
*
****************************************************************************/
#include <stdio.h>
#include <math.h>
#define TRUE 1
#define FALSE 0
#define PIE 3.141592653
#define STR_LNGTH 20
#define MAIN
#ifdef MAIN /* Removes extern if used in main.c */
#define extern
#endif
#define ALLCODE /* If all code is present, allows proper compliation*/
/* Convenient pointers to dynamically allocated arrays */
#define addm(I, J) (addm_mtrx_ptr + I + N * J)
#define curr(I ) (curr_vect_ptr + I )
extern struct component
{
char name[ STR_LNGTH ]; /* Name of component */
int node_i; /* One connection of the component */
char name_i[ STR_LNGTH ]; /* Name of first node */
int node_j; /* The second connection of the component */
char name_j[ STR_LNGTH ]; /* Name of second node */
int node_k; /* A third connection, if existing */
char name_k[ STR_LNGTH ]; /* Name of third node */
int node_l; /* A Fourth connection, if existing */
char name_l[ STR_LNGTH ]; /* Name of fourth node */
double value; /* The value of the component */
struct component *link; /* Link foward to next structure or NULL */
};
extern struct component *begin_caps ; /* Start of capacitor link list */
extern struct component *begin_inds ; /* Start of inductor link list */
extern struct component *begin_res ; /* Start of resistor link list */
extern struct component *begin_vcv ; /* Start of VCV link list */
extern struct component *begin_vci ; /* Start of VCI link list */
extern struct component *end_caps ; /* Last entry of capacitor link list */
extern struct component *end_inds ; /* Last entry of inductor link list */
extern struct component *end_res ; /* Last entry of resistor link list */
extern struct component *end_vcv ; /* Last entry of VCV link list */
extern struct component *end_vci ; /* Last entry of VCI link list */
extern struct component VS_source; /* Special entry for source */
extern struct component OUT_node; /* Special entry for output node marker */
extern int flag_FS ;
extern int flag_FE ;
extern int flag_FP ;
extern int flag_LOG ;
extern int flag_PHASE ;
extern int flag_RADS ;
extern int flag_PRTCMP ;
extern int flag_VS ;
extern int flag_OUT ;
extern int flag_MTRX ;
extern double freq_start; /* Starting Frequency */
extern double freq_end; /* Ending Frequency */
extern int freq_part; /* Number of partitions */
extern int N; /* Number of distinct nodes */
extern struct cmplx_num *addm_mtrx_ptr; /* Addmittance Matrix Pointer */
extern struct cmplx_num *curr_vect_ptr; /* Impedance Matrix Pointer */
/* -------------------------------------------------------------------*/
/*************************************************************************
*
* ENHANCED MATH PACKAGE
* An extra set of math functions, and in particular
* macros that perform complex number operations. Note:
* all arguenments pass to the complex number macros MUST
* be pointers to a complex structure, and not an
* actual structure. Also the use of variable names "den"
* and "cmplx_tmp" will create problems. These are macros,
* and not subroutines!
*
**************************************************************************/
struct cmplx_num { /* The Complex number structure */
double real;
double imag;
};
#define abs(X) ( X > 0 ? X : -X )
#define sqr(X) ( X )*( X )
#define cset(X, Y, Z) X->real = Y; X->imag = Z
#define cmpl(X) X->imag = - X->imag
#define cadd(X, Y, Z) Z->real = X->real + Y->real;\
Z->imag = X->imag + Y->imag
#define csub(X, Y, Z) Z->real = X->real - Y->real;\
Z->imag = X->imag - Y->imag
#define cmul(X, Y, Z) { \
struct cmplx_num cmplx_tmp; \
cmplx_tmp.real = X->real * Y->real - X->imag * Y->imag ; \
cmplx_tmp.imag = X->real * Y->imag + X->imag * Y->real ; \
Z->real = cmplx_tmp.real; \
Z->imag = cmplx_tmp.imag; \
}
#define cdiv(X, Y, Z) { \
struct cmplx_num cmplx_tmp; \
double den; \
den = sqr( Y->real ) + sqr( Y->imag ); \
cmplx_tmp.real = X->real * Y->real + X->imag * Y->imag ; \
cmplx_tmp.imag = X->imag * Y->real - X->real * Y->imag ; \
Z->imag = cmplx_tmp.imag / den; \
Z->real = cmplx_tmp.real / den; \
}
#define cmag(X) sqrt( sqr( X->real) + sqr( X->imag))
/* ----------------------------------------------------------------------------*/
/************************************************************************
*
* Main.c contains the primary loop of the spice simulation, namely
* the loop that increments frequency. Main also first calls
* subroutines to read in all the net list, to check for critical
* information, and to possibly print the input data. For each
* frequency, the addmitance matrix is recalculated, then
* inverted. The proper element is picked off, and printed.
*
*************************************************************************/
#ifndef ALLCODE
#include "header.h"
#endif
main()
{
double freq_delta; /* Frequency increment */
double freq; /* Current frequency of calculations */
int i;
initialize();
read_input();
if( flag_PRTCMP == TRUE ) print_components(); /* Print all component values */
check_input();
/* Allocate Space for addmitance matrix */
addm_mtrx_ptr = (struct cmplx_num *)malloc( N * N * sizeof( struct cmplx_num) );
if( addm_mtrx_ptr <= NULL ) {
fprintf( stderr, "Insufficient Malloc memory allocations. Fatal error \n");
exit(1);
}
curr_vect_ptr = (struct cmplx_num *)malloc( N * sizeof( struct cmplx_num) );
if( curr_vect_ptr <= NULL ) {
fprintf( stderr, "Insufficient Malloc memory allocations. Fatal error \n");
exit(1);
}
#ifdef IBM
printf( "1 \n %d , SSPICE \n", freq_part );
#endif
freq_delta = (freq_end - freq_start ) /freq_part;
freq = freq_start ;
for( i = 0; i <= freq_part ; i++ ) {
double omega;
fprintf( stderr, "*");
if( flag_RADS == TRUE ) omega = freq ;
else omega = 2 * PIE * freq ;
/* Fill addmittance matrix */
fill_matrix( omega);
if( flag_MTRX == TRUE ) print_mtrx( addm_mtrx_ptr );
/* Take inverse of addmittance matrix */
inverse_matrix();
if( flag_MTRX == TRUE ) print_mtrx( addm_mtrx_ptr );
print_output( freq );
freq += freq_delta ;
}
} /* End of main */
/* ----------------------------------------------------------------------- */
/************************************************************************
*
* This file contains two main subroutines: "fill_matrix" walks
* through all the component link lists, and makes numeric entries
* into the addmittance matrx. This is only done for one frequency
* at a time. "inverse_matrx" actually solves for the voltages
* of all nodes. The solution ends up in the vector "curr", which
* originaly stands for the net current at each node. The net current
* at each node is zero, with the exception of the source node. It
* is assigned an external current of 1.0.
*
***************************************************************************/
#ifndef ALLCODE
#include "header.h"
#endif
fill_matrix( omega)
double omega;
{
struct component *x;
struct cmplx_num addmitt;
int i, j;
if( omega == 0.0 ) omega = 0.000001 ; /* To prevent division by zero */
/* Sets entire addmitance matrix to zero */
for( i=0 ; i < N ; i++ ) {
for( j=0 ; j < N ; j++ ) {
addm( i, j)->real = 0.0;
addm( i, j)->imag = 0.0;
}
}
/* Enters all resistor addmittances to matrix */
for( x = begin_res; x != NULL ; x = x->link ) { /* Walks throught all res. */
cset( (&addmitt) , (1.0 / x->value), 0.0 );
add_element( &addmitt, x );
}
/* Enters all capacitor addmittances to matrix */
for( x = begin_caps; x != NULL ; x = x->link ) { /* Walks throught all cap. */
cset( (&addmitt) , 0.0 , (omega * x->value) );
add_element( &addmitt, x );
}
/* Enters all inductor addmittances to matrix */
for( x = begin_inds; x != NULL ; x = x->link ) { /* Walks throught all ind. */
cset( (&addmitt) , 0.0 , ( -1.0 / (omega * x->value)) );
add_element( &addmitt, x );
}
/* Enters all Voltage Controlled Current Sources addmittances to matrix */
for( x = begin_vci; x != NULL ; x = x->link ) {
cset( (&addmitt) , x->value, 0.0 );
if( x->node_k >= 0 ) { /* Not a ground node */
if( x->node_i >= 0 ) {
addm( x->node_k, x->node_i)->real -= addmitt.real;
addm( x->node_k, x->node_i)->imag -= addmitt.imag;
}
if( x->node_j >= 0 ) {
addm( x->node_k, x->node_j)->real += addmitt.real;
addm( x->node_k, x->node_j)->imag += addmitt.imag;
}
}
if( x->node_l >= 0 ) { /* Not a ground node */
if( x->node_i >= 0 ) {
addm( x->node_l, x->node_i)->real += addmitt.real;
addm( x->node_l, x->node_i)->imag += addmitt.imag;
}
if( x->node_j >= 0 ) {
addm( x->node_l, x->node_j)->real -= addmitt.real;
addm( x->node_l, x->node_j)->imag -= addmitt.imag;
}
}
}
/* Enters all Voltage Controlled Voltage Sources addmittances to matrix */
for( x = begin_vcv; x != NULL ; x = x->link ) {
cset( (&addmitt) , x->value, 0.0 );
for( i = 0 ; i < N ; i ++) {
addm( x->node_k, i)->real = 0.0 ;
addm( x->node_k, i)->imag = 0.0 ;
}
cset( addm( x->node_k, x->node_k), 1.0, 0.0 );
if( x->node_j >= 0 ) { /* Not a ground node */
addm( x->node_k, x->node_j)->real = x->value ;
}
if( x->node_i >= 0 ) { /* Not a ground node */
addm( x->node_k, x->node_i)->real = -( x->value) ;
}
}
/* Enters source addmittance to matrix */
for( i = 0 ; i < N ; i ++) {
addm( (&VS_source)->node_i, i)->real = 0.0 ;
addm( (&VS_source)->node_i, i)->imag = 0.0 ;
}
cset( addm( (&VS_source)->node_i, (&VS_source)->node_i), 1.0, 0.0 );
/* Initialize current vertor */
for( i = 0; i < N; i++ ) { cset( curr( i ), 0.0 , 0.0 ); }
cset( curr( (&VS_source)->node_i), 1.0, 0.0 );
} /* End of enter_matrix */
add_element( a, x)
struct cmplx_num *a;
struct component *x;
{
if( (x->node_i >= 0) && (x->node_j >=0) ) {
addm( x->node_i, x->node_i)->real += a->real;
addm( x->node_i, x->node_i)->imag += a->imag;
addm( x->node_j, x->node_j)->real += a->real;
addm( x->node_j, x->node_j)->imag += a->imag;
addm( x->node_i, x->node_j)->real -= a->real;
addm( x->node_i, x->node_j)->imag -= a->imag;
addm( x->node_j, x->node_i)->real -= a->real;
addm( x->node_j, x->node_i)->imag -= a->imag;
}
else if( (x->node_i >= 0) && (x->node_j < 0) ) {
addm( x->node_i, x->node_i)->real += a->real;
addm( x->node_i, x->node_i)->imag += a->imag;
}
else if( (x->node_i < 0) && (x->node_j >= 0) ) {
addm( x->node_j, x->node_j)->real += a->real;
addm( x->node_j, x->node_j)->imag += a->imag;
}
else {
fprintf( stderr, "Component %s Seems to have no conections to any active nodes. It is ignored \n", x->name );
}
}
#define csubeq(X, Y) { \
X->real -= Y->real; \
X->imag -= Y->imag; \
}
/********************************************************************
* The following routing is an enhanced inversion gaussain elimination
* inversion routing. Is seeks the largest value in any column, and
* then performs pivoting and elimination using this entry. In order to
* keep track of which columns have already been pivoted, the algorithm
* checks the sum of the magnitude of the elements along the row to
* just before the test pivot element. If this sum is zero, or very
* close to it, it is assumed that this row has already been pivoited.
**********************************************************************/
inverse_matrix()
{
struct cmplx_num one_x, tmp_x, scale_x;
struct cmplx_num *one, *tmp, *scale;
int i, j, k, ii;
double pre_max; /* Previous Maximum */
double cur_max; /* Current Maximum */
double par_row_sum ; /* Partial Row Sum. To detect if this row has already been cleared */
/* Need Temporary space that are pointers */
one = &one_x;
tmp = &tmp_x;
scale = &scale_x;
cset( one, 1.0, 0.0);
/* Scan across all columns */
for( j = 0; j < N; j++) {
/* Find Maximun entry in this row. The magnitude of all previous entries in
this row is sumed in "par_row_sum". Only if this sum is zero is it
valid to pivot on this row. */
pre_max = 0.0 ;
for( i = 0; i < N; i++ ) {
par_row_sum = 0.0;
for( k = 0; k < j ; k++ ) par_row_sum += cmag( addm( i, k) ) ;
cur_max = cmag( addm( i, j) );
/* test this pivot point */
if( ( cur_max > pre_max ) && ( cur_max > (1000000000 * par_row_sum ) )) {
ii = i; /* Mark this N as ii */
pre_max = cur_max ;
}
}
/* Normalize the row chosen above */
if( cmag( addm( ii, j )) == 0.0 ) {
fprintf( stderr,"##ERROR##\n, division by zero.\n");
exit(0);
}
cdiv( one , addm( ii, j), scale );
for( k = j; k < N; k++ ) {
cmul( addm( ii, k), scale, addm( ii, k) );
}
cmul( curr( ii), scale, curr( ii) );
/* Null out all other entries in this column, except
choses entry to zero. */
for( i = 0; i < N; i++ ) {
/* Don't do if pivot row, or if semi-pivot element is zero */
if( ( i != ii ) && ( cmag( addm( i , j ) ) != 0.0) ) {
cmul( addm( i, j), curr( ii ), tmp );
csubeq( curr( i ), tmp );
for( k = N-1; k >= j ; k-- ) {
cmul( addm( i, j), addm( ii, k), tmp );
csubeq( addm( i, k), tmp );
}
}
}
} /* End of Column Scan */
} /* End of matrix inversion */
/*****************************************************************************
*
* This file contains subroutines for reading in the net list, processing
* the node names into node numbers, setting true appropriate flags, and
* recording misc. infomation, such as starting frequency, etc.
*
*****************************************************************************/
#ifndef ALLCODE
#include "header.h"
#endif
#define fscanf my_fscanf
/* Primary input read loop. Exits when EOF is detected */
read_input()
{
char str[ STR_LNGTH ] ; /* String buffer for input reading */
FILE *fp_in = stdin;
/* Loops over all input lines, and enters data into proper variables */
while( fscanf( fp_in, "%s", str) != EOF ) {
double scan_modifier();
struct component *add_cmpt_link();
if( !strcmp( str, "FS") ) {
fscanf( fp_in, "%f", &freq_start);
freq_start *= (int)scan_modifier( fp_in );
flag_FS = TRUE;
}
else if( !strcmp( str, "FE") ) {
fscanf( fp_in, "%f", &freq_end);
freq_end *= (int)scan_modifier( fp_in );
flag_FE = TRUE;
}
else if( !strcmp( str, "FP") ) {
fscanf( fp_in, "%d", &freq_part);
freq_part *= (int)scan_modifier( fp_in );
flag_FP = TRUE;
}
else if( !strcmp( str, "PHASE") ) {
flag_PHASE = TRUE;
scan_modifier( fp_in );
}
else if( !strcmp( str, "LOG") ) {
flag_LOG = TRUE;
scan_modifier( fp_in );
}
else if( !strcmp( str, "MTRX") ) {
flag_MTRX = TRUE;
scan_modifier( fp_in );
}
else if( !strcmp( str, "RADS") ) {
flag_RADS = TRUE;
scan_modifier( fp_in );
}
else if( !strcmp( str, "PRTCMP") ) {
flag_PRTCMP = TRUE;
scan_modifier( fp_in );
}
else if( !strcmp( str, "OUT") ) {
flag_OUT = TRUE;
fscanf( fp_in, "%s", OUT_node.name_i );
OUT_node.node_i = node_numb( OUT_node.name_i);
scan_modifier( fp_in );
}
else if( *str == 'L' ) {
add_cmpt_link( &begin_inds, &end_inds );
strcpy( end_inds->name, str);
fscanf( fp_in, "%s", end_inds->name_i );
end_inds->node_i = node_numb( end_inds->name_i);
fscanf( fp_in, "%s", end_inds->name_j );
end_inds->node_j = node_numb( end_inds->name_j);
fscanf( fp_in, "%f", &end_inds->value );
end_inds->value *= scan_modifier( fp_in );
}
else if( *str == 'C' ) {
add_cmpt_link( &begin_caps, &end_caps );
strcpy( end_caps->name, str);
fscanf( fp_in, "%s", end_caps->name_i );
end_caps->node_i = node_numb( end_caps->name_i);
fscanf( fp_in, "%s", end_caps->name_j );
end_caps->node_j = node_numb( end_caps->name_j);
fscanf( fp_in, "%f", &end_caps->value );
end_caps->value *= scan_modifier( fp_in );
}
else if( *str == 'R' ) {
add_cmpt_link( &begin_res, &end_res );
strcpy( end_res->name, str);
fscanf( fp_in, "%s", end_res->name_i );
end_res->node_i = node_numb( end_res->name_i);
fscanf( fp_in, "%s", end_res->name_j );
end_res->node_j = node_numb( end_res->name_j);
fscanf( fp_in, "%f", &end_res->value );
end_res->value *= scan_modifier( fp_in );
}
else if( !strcmp( str, "VCI") ) {
add_cmpt_link( &begin_vci, &end_vci );
strcpy( end_vci->name, str);
fscanf( fp_in, "%s", end_vci->name_i );
end_vci->node_i = node_numb( end_vci->name_i);
fscanf( fp_in, "%s", end_vci->name_j );
end_vci->node_j = node_numb( end_vci->name_j);
fscanf( fp_in, "%s", end_vci->name_k );
end_vci->node_k = node_numb( end_vci->name_k);
fscanf( fp_in, "%s", end_vci->name_l );
end_vci->node_l = node_numb( end_vci->name_l);
fscanf( fp_in, "%f", &end_vci->value );
end_vci->value *= scan_modifier( fp_in );
}
else if( !strcmp( str, "VCV") ) {
add_cmpt_link( &begin_vcv, &end_vcv );
strcpy( end_vcv->name, str);
fscanf( fp_in, "%s", end_vcv->name_i );
end_vcv->node_i = node_numb( end_vcv->name_i);
fscanf( fp_in, "%s", end_vcv->name_j );
end_vcv->node_j = node_numb( end_vcv->name_j);
fscanf( fp_in, "%s", end_vcv->name_k );
end_vcv->node_k = node_numb( end_vcv->name_k);
fscanf( fp_in, "%f", &end_vcv->value );
end_vcv->value *= scan_modifier( fp_in );
}
else if( !strcmp( str, "VS") ) {
flag_VS = TRUE;
fscanf( fp_in, "%s", VS_source.name_i );
VS_source.node_i = node_numb( VS_source.name_i);
scan_modifier( fp_in );
}
else {
fprintf( stderr, "Syntax Error: Unrecognized input string \"%s\". String ignored. \n", str );
}
} /* End of while */
} /* End of read routine */
/* Assigns a number to any ascii node name. Number are chosen in
* sequential order beginning with zero. If the name passed to
* this routing already exits, then the node number assigned
* to this name previously is returned. Gnd and several variations
* are special reserved names which always have the value -1
* associated with them.
*/
node_numb( str )
char *str;
{
struct name_list { /* Link List structure to keep node names */
char name[ STR_LNGTH ];
int node_number;
struct name_list *link;
};
static struct name_list *bgn_nm_lst = NULL;
static struct name_list *end_nm_lst = NULL;
struct name_list *new_link, *x;
if( !strcmp( str, "GND") || !strcmp( str, "gnd") || !strcmp( str, "Gnd") ) return( -1 );
for( x = bgn_nm_lst; x != NULL; x = x->link )
{
if( !strcmp( x->name, str)) return( x->node_number );
}
new_link = (struct name_list *)malloc( sizeof (struct name_list));
new_link->link = NULL;
if( bgn_nm_lst == NULL ) bgn_nm_lst = new_link; /* IF first link, start chain */
else end_nm_lst->link = new_link; /* link head */
end_nm_lst = new_link; /* Update end pointer */
strcpy( new_link->name, str);
new_link->node_number = N++;
return( new_link->node_number );
}
#undef fscanf
/* A lousy fucking patch for micro-soft C. It doesn't
* seem to read floating point numbers properly.
*/
my_fscanf( fp, str, reg)
FILE *fp;
char *str;
union {
int x;
double y;
char t;
} *reg;
{
double atof();
if( !strcmp( str, "%f") ) {
char temp[40];
fscanf( fp, "%s", temp);
reg->y = atof( temp);
}
else fscanf( fp, str, reg);
}
#define fscanf my_fscanf
/* ------------------------------------------------------------------------ */
/********************************************************************
*
* This file contains all routines which print anything to
* the user.
*
**********************************************************************/
#ifndef ALLCODE
#include "header.h"
#endif
#define FLG_STR(X) if( X == TRUE ) strcpy( str, "TRUE" ); \
else strcpy( str, "FALSE")
/* Prints components and all other important information */
print_components()
{
FILE *fp_out = stdout;
char str[ STR_LNGTH ] ; /* String buffer for input reading */
struct component *x; /* a pointer to current component structure */
FLG_STR(flag_FS);
fprintf( fp_out,"+Starting frequency flag is set %s \n", str);
FLG_STR(flag_FE);
fprintf( fp_out,"+Ending frequency flag is set %s \n", str);
FLG_STR(flag_FP);
fprintf( fp_out,"+Number of Points flag is set %s \n", str);
FLG_STR(flag_RADS);
fprintf( fp_out,"+Radian flag is set %s \n", str);
FLG_STR(flag_LOG);
fprintf( fp_out,"+Logarithmitic flag is set %s \n", str);
FLG_STR(flag_VS);
fprintf( fp_out,"+Source designation flag is set %s \n", str);
FLG_STR(flag_OUT);
fprintf( fp_out,"+Output designation flag is set %s \n", str);
fprintf( fp_out,"\n");
if( flag_FS == TRUE ) fprintf( fp_out,"+Starting Frequency = %f \n", freq_start);
if( flag_FE == TRUE ) fprintf( fp_out,"+Ending Frequency = %f \n", freq_end);
if( flag_FP == TRUE ) fprintf( fp_out,"+Number of partitions is = %d \n", freq_part);
fprintf( fp_out, "\n Component I Node J Node K Node L Node Value \n");
for( x = begin_res; x != NULL ; x = x->link )
fprintf( fp_out, "+ %10s %8s %8s %10e Ohms \n", x->name, x->name_i, x->name_j, x->value);
for( x = begin_inds; x != NULL ; x = x->link )
fprintf( fp_out, "+ %10s %8s %8s %10e Heneries \n", x->name, x->name_i, x->name_j, x->value);
for( x = begin_caps; x != NULL ; x = x->link )
fprintf( fp_out, "+ %10s %8s %8s %10e Farads \n", x->name, x->name_i, x->name_j, x->value);
for( x = begin_vcv; x != NULL ; x = x->link )
fprintf( fp_out, "+ %10s %8s %8s %8s %10e Av \n", x->name, x->name_i, x->name_j, x->name_k , x->value);
for( x = begin_vci; x != NULL ; x = x->link )
fprintf( fp_out, "+ %10s %8s %8s %8s %8s %10e Mohs \n", x->name, x->name_i, x->name_j, x->name_k , x->name_l , x->value);
fprintf( fp_out, "+ VS %8s \n", VS_source.name_i);
fprintf( fp_out, "+ OUT %8s \n", OUT_node.name_i);
} /* End of print routine */
/* Prints out all elements of a complex matrix
* Primarily to be used for checking and debugging
*/
print_mtrx( mtrx )
struct cmplx_num *mtrx;
{
FILE *fp_out = stdout ;
int i, j;
fprintf( fp_out,"------------------------------------------------------------ \n");
for( i=0; i<N ; i++ ) {
for( j=0; j<N ; j++ ) fprintf( fp_out, "%6.2f ", (mtrx + i + N*j)->real);
fprintf( fp_out, " %6.2f\n", curr( i )->real);
for( j=0; j<N ; j++ ) fprintf( fp_out, "%6.2f ", (mtrx + i + N*j)->imag);
fprintf( fp_out, " %6.2f\n", curr( i )->imag);
fprintf( fp_out, "\n");
}
fprintf( fp_out,"------------------------------------------------------------ \n");
}
/* Prints the output transfer function */
print_output( omega)
double omega;
{
double magnitude, phase;
int i, ii, out;
double pre_max;
out = OUT_node.node_i ;
pre_max = 0.0 ;
for( i =0 ; i < N ; i++ ) {
if( cmag( addm( i, out )) > pre_max ) {
ii = i;
pre_max = cmag( addm( i, out ));
}
}
phase = atan2( curr( ii )->imag, curr( ii )->real );
magnitude = cmag( curr( ii ) );
if( magnitude == 0.0 ) magnitude = 1000000000.0;
#ifdef IBM
if( flag_LOG == TRUE ) printf( "%f , %f \n", omega, ( -20 * log10( magnitude ) ) );
else if( flag_PHASE == TRUE ) printf( "%f , %f \n", omega, ( 180 * phase / PIE) );
else printf( "%f , %f \n", omega, magnitude );
#else
if( flag_LOG == TRUE ) printf( "%f %f \n", omega, ( -20 * log10( magnitude ) ) );
else if( flag_PHASE == TRUE ) printf( "%f %f \n", omega, ( 180 * phase / PIE ) );
else printf( "%f %f \n", omega, magnitude );
#endif
}
/* ----------------------------------------------------------------------------- */
/****************************************************************************
*
* General miscellaneous subroutines that I didn't want to
* be cluttering up the more improtant files.
*
*****************************************************************************/
#ifndef ALLCODE
#include "header.h"
#endif
/* Looks for some type of value modifie, such as kilo (x1000)
* or micro (x0.000001). Then will be expecting a colon as end
* of line marker. Returns a double persion number for
* scaling purposes.
*/
double scan_modifier( input )
FILE *input;
{
double scale = 1.0;
char string[ STR_LNGTH ];
while( (fscanf( input, "%s", string) != EOF) && (*string != ';' ) ) {
switch( *string) {
case 'K':
scale = 1000;
break;
case 'M':
scale = 1000000;
break;
case 'G':
scale = 1000000000;
break;
case 'm':
scale = 0.001;
break;
case 'u':
scale = 0.000001;
break;
case 'n':
scale = 0.000000001;
break;
case 'p':
scale = 0.000000000001;
break;
case 'E':
{
int K;
fscanf( input, "%d", &K);
if( K > 30 ) K = 30;
if( K < -30 ) K = -30;
while( K-- > 0 ) scale *= 10;
while( K++ < 0 ) scale *= 0.1;
}
break;
default:
fprintf( stderr, "Unrecognized string \"%s\" \n", string);
fprintf( stderr, "Metric modifying unit expected. \n" );
fprintf( stderr, "String Ignored. \n");
}
}
return( scale );
}
/* Add a Component structor to the Link. A component structor is
* added to the link list. The end_ptr_add arguement is the ADDRESS of a
* pointer which points to the last structure in the list. In the
* case of a zero list, "pointer_address" is the ADDRESS of the
* variable "begin_list"
*/
struct component *add_cmpt_link( bgn_ptr_add, end_ptr_add )
struct component **end_ptr_add;
struct component **bgn_ptr_add;
{
struct component *new_link;
if( ( new_link = (struct component *)malloc( sizeof ( struct component ) ) ) == NULL ) {
fprintf( stderr, "Operating system fault Insufficient memory resources. \n");
fprintf( stderr, "Fatal Error. \n");
exit(1);
}
new_link->link = NULL; /* Link tail */
if( *bgn_ptr_add == NULL ) *bgn_ptr_add = new_link; /* IF first, Start Chain */
else (*end_ptr_add)->link = new_link; /* link head */
*end_ptr_add = new_link; /* Update end pointer */
return( new_link );
}
/*
* Initializes global variables only.
* This cannot be nicely done in header.h due to
* its dual nature use with a makefile
*/
initialize()
{
begin_caps = NULL; /* Start of capacitor link list */
begin_inds = NULL; /* Start of inductor link list */
begin_res = NULL; /* Start of resistor link list */
begin_vcv = NULL; /* Start of VCV link list */
begin_vci = NULL; /* Start of VCI link list */
end_caps = NULL; /* Last entry of capacitor link list */
end_inds = NULL; /* Last entry of inductor link list */
end_res = NULL; /* Last entry of resistor link list */
end_vcv = NULL; /* Last entry of VCV link list */
end_vci = NULL; /* Last entry of VCI link list */
flag_FS = FALSE;
flag_FE = FALSE;
flag_FP = FALSE;
flag_LOG = FALSE;
flag_PHASE = FALSE;
flag_RADS = FALSE;
flag_PRTCMP = FALSE;
flag_VS = FALSE;
flag_OUT = FALSE;
flag_MTRX = FALSE;
N = 0;
}
/* Checks if essential input informaiton is present */
check_input()
{
if( flag_VS == FALSE ) {
fprintf( stderr, "No source node has been specified! \n" );
fprintf( stderr, "Fatal Error. \n");
exit(1);
}
if( flag_OUT == FALSE ) {
fprintf( stderr, "No output node has been specified! \n" );
fprintf( stderr, "Fatal Error. \n");
exit(1);
}
if( flag_FS == FALSE ) {
fprintf( stderr, "Starting frequency unspecified! \n" );
fprintf( stderr, "Fatal Error. \n");
exit(1);
}
if( flag_FE == FALSE ) {
fprintf( stderr, "Ending frequency unspecified! \n" );
fprintf( stderr, "Fatal Error. \n");
exit(1);
}
if( flag_FP == FALSE ) {
fprintf( stderr, "Number of frequency partitions unspecified! \n" );
fprintf( stderr, "Default of 20 will be used. \n");
freq_part = 20;
}
}
/* ------------------------------------------------------------------------- */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.