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.