home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- * This program calculates the magnitude of a transfer function
- * given all the pole and zero locations. A scalar constant
- * K can also be entered.
- * Steven Punte
- * Sept. 24 1987
- ***********************************************************************/
-
- #include <stdio.h>
- #include <math.h>
- #define TRUE 1
- #define FALSE 0
- #define MAX_ARRAY 50 /* Max number of poles or zeros */
- #define PIE 3.141592653
- #define STR_LNGTH 20
- #define scanf my_scanf
-
- #define abs(X) ( X > 0 ? X : -X )
- #define sqr(X) ( X )*( X )
- #define scal(X, Y) while( abs( X ) > 1000) { X *= 0.0001; Y += 4; } \
- while( abs( X ) < 0.0001) { X *= 10000; Y -= 4; }
- #define clear(X) X.real = 0; X.imag = 0
- #define cmov(X, Y) Y.real = X.real; Y.imag = X.imag
- #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 tmp; \
- tmp.real = X.real * Y.real - X.imag * Y.imag ; \
- tmp.imag = X.real * Y.imag + X.imag * Y.real ; \
- Z.real = tmp.real; \
- Z.imag = tmp.imag; \
- }
- #define cdiv(X, Y, Z) { \
- struct cmplx_num tmp; \
- double den; \
- den = sqr( Y.real ) + sqr( Y.imag ); \
- tmp.real = X.real * Y.real + X.imag * Y.imag ; \
- tmp.imag = X.imag * Y.real - X.real * Y.imag ; \
- Z.imag = tmp.imag / den; \
- Z.real = tmp.real / den; \
- }
- #define cmag(X) sqrt( sqr( X.real) + sqr( X.imag))
-
-
- struct cmplx_num {
- double real;
- double imag;
- };
-
- int flag_S = FALSE;
- int flag_E = FALSE;
- int flag_PT = FALSE;
- int flag_LOG = FALSE;
- int flag_RADS = FALSE;
- int flag_PHASE = FALSE;
- int flag_STEP = FALSE;
-
- double start; /* Starting Frequency */
- double endd; /* Ending Frequency */
- int points; /* Number of partitions */
- double K_coeff = 1.0; /* Front Scaler coeffficient (1.0 default value) */
- int K_exp = 0;
-
- int numb_poles = 0; /* Number of poles (either real or complex) */
- int numb_zeros = 0; /* Number of zeros (either real or complex) */
-
- int i; /* Index for summation calculations */
- char str[ STR_LNGTH ] ; /* String buffer for input reading */
- int data_set = 0; /* Number of sets of data to be processed */
- double ctemp; /* Used for complex divide */
-
- struct cmplx_num poles[ MAX_ARRAY ];
- struct cmplx_num zeros[ MAX_ARRAY ];
- struct {
- double x[500];
- double y[500];
- int numb_point;
- char name[ STR_LNGTH ];
- } output[ 5 ];
-
- main()
- {
- int done_chk;
-
- do {
- done_chk = read_set();
- check_input();
-
- if( flag_STEP == TRUE ) step_response();
- else transfer_respones();
-
- data_set++;
- } while( done_chk != EOF );
-
- display();
-
- } /* End of main */
-
-
-
- transfer_respones()
- {
- double delta; /* Frequency increment in hertz */
- double x; /* Frequency being analysized in hertz */
- double ampl;
- double angle;
- double gamma;
- int pnt;
- struct cmplx_num cgamma, tmp;
- struct cmplx_num K_scale;
- double scale_data();
-
- gamma = scale_data();
- cset( K_scale, K_coeff, 0);
-
- delta = (endd - start) / points;
-
- /* Main loop; Calculates magnitude at each frequency */
-
- pnt = 0;
- for( x = start; x < endd ; x += delta ) {
-
- struct cmplx_num numerator; /* Numerator of magnitude calculation */
- struct cmplx_num denominator; /* Denominator of mangitude calculation */
- struct cmplx_num magnitude; /* Final resulting magnitude */
- struct cmplx_num temp1, temp2;
- struct cmplx_num omega;
-
- if( flag_RADS == FALSE ) { cset( omega, 0, (2*PIE*x / gamma ) ); }
- else { cset( omega, 0, ( x / gamma )); }
-
- cset( numerator, 1, 0 );
- cset( denominator, 1, 0 );
-
- /* Main calculations here */
- for( i = 0; i < numb_zeros ; i++ ) {
- csub( omega, zeros[ i ], temp1 );
- cmul( temp1, numerator, numerator);
- }
- for( i = 0; i < numb_poles ; i++ ) {
- csub( omega, poles[ i ], temp1 );
- cmul( temp1, denominator, denominator);
- }
-
- /* In case of underflow */
- if( cmag( denominator) == 0.0 ) {
- cset( magnitude, 100000000000000.0, 0.0 );
- }
- else {
- cdiv( numerator, denominator, magnitude );
- cmul( magnitude, K_scale, magnitude );
- }
-
- if( flag_PHASE == TRUE ) {
- angle = 180 / PIE * atan2( magnitude.imag, magnitude.real );
- /*
- printf( "%15.5f %15.5f \n", x, angle );
- */
- output[ data_set ].x[ pnt ] = x;
- output[ data_set ].y[ pnt ] = angle;
- pnt++;
-
- }
-
- else {
- ampl = cmag( magnitude );
-
- if( flag_LOG == TRUE ) {
- if( ampl == 0.0 ) ampl = -1000;
- else ampl = -20 * log10( ampl );
- }
-
- /*
- printf( "%15.5f %15.5f \n", x, ampl );
- */
- output[ data_set ].x[ pnt ] = x;
- output[ data_set ].y[ pnt ] = ampl;
- pnt++;
- }
- }
- if( flag_PHASE == TRUE ) strcpy( output[ data_set ].name, "Phase" );
- else strcpy( output[ data_set ].name, "Magnitude" );
-
- output[ data_set ].numb_point = pnt;
-
- } /* End of transfer response */
-
- step_response()
- {
- double delta; /* Frequency increment in hertz */
- double x; /* Frequency being analysized in hertz */
- double gamma ;
- struct cmplx_num C[ MAX_ARRAY ];
- int k;
- int pnt;
-
- gamma = scale_data();
-
- for( k = 0; k < numb_poles ; k++) {
- struct cmplx_num numerator; /* Numerator of magnitude calculation */
- struct cmplx_num denominator; /* Denominator of mangitude calculation */
- struct cmplx_num magnitude; /* Final resulting magnitude */
- struct cmplx_num temp1, temp2;
-
- cset( numerator, K_coeff, 0 );
- cset( denominator, 1, 0);
-
- for( i = 0; i < numb_zeros ; i++ ) {
- csub( poles[k], zeros[i], temp1 );
- cmul( temp1, numerator, numerator );
- }
-
- for( i = 0; i < numb_poles ; i++ ) {
- if( i != k) {
- csub( poles[k], poles[i], temp1 );
- cmul( temp1, denominator, denominator );
- }
- }
- cdiv( numerator, denominator, C[k]);
- }
-
- delta = (endd - start) / points;
-
- /* Main loop; Calculates magnitude at each frequency */
-
- for( x = start; x < endd ; x += delta ) {
-
- struct cmplx_num temp1, temp2, temp3, sum;
- cset( sum, 0, 0);
-
- for( k = 0; k < numb_poles ; k++) {
-
- cset( temp1, ( x * gamma ), 0);
- cmul( poles[k], temp1, temp2);
- cset( temp1, cos( temp2.imag), sin( temp2.imag) );
- cset( temp2, exp( temp2.real), 0);
- cmul( temp1, temp2, temp3 );
- cset( temp1, 1, 0);
- csub( temp3, temp1, temp2);
- cmul( temp2, C[k], temp3);
- cdiv( temp3, poles[k], temp1);
-
- cadd( sum, temp1, temp2);
- cmov( temp2, sum);
-
- }
- /*
- printf( "%15.5f %15.5f %f15.5 \n", x, sum.real, sum.imag );
- printf( "%15.5f %15.5f \n", x, sum.real);
- */
- output[ data_set ].x[ pnt ] = x;
- output[ data_set ].y[ pnt ] = sum.real;
- pnt++;
- }
- strcpy( output[ data_set ].name, "Step" );
- output[ data_set ].numb_point = pnt;
- }
-
- /* Stack overflow error routing and exit */
- overflow_error()
- {
- fprintf( stderr, "Internal Array Size has been exceeded \n");
- fprintf( stderr, "Recompile with larger \"MAX_ARRAY\" size. \n");
- fprintf( stderr, "Fatal Error \n");
- exit(1);
- }
-
-
-
- /* Loops over all input lines, and enters data into proper variables */
- read_set()
- {
- double scan_modifier();
- int expon; /* The tens power exponent of the metric scale factor */
- *str = EOF;
-
- flag_LOG = FALSE;
- flag_RADS = FALSE;
- flag_PHASE = FALSE;
- flag_STEP = FALSE;
- K_coeff = 1.0; /* Front Scaler coeffficient (1.0 default value) */
-
- numb_poles = 0; /* Number of poles (either real or complex) */
- numb_zeros = 0; /* Number of poles (either real or complex) */
-
- while( (scanf( "%s", str) != EOF) && ( *str != '#') ) {
-
- if( !strcmp( str, "FS") || !strcmp( str, "TS") || !strcmp( str, "S" )) {
- scanf( "%f", &start);
- start *= scan_modifier( stdin, &expon );
- flag_S = TRUE;
- }
-
- else if( !strcmp( str, "FE") || !strcmp( str, "TE") || !strcmp( str, "E" )) {
- scanf( "%f", &endd);
- endd *= scan_modifier( stdin, &expon );
- flag_E = TRUE;
- }
-
- else if( !strcmp( str, "FP") || !strcmp( str, "TP") || !strcmp( str, "PT" )) {
- scanf( "%d", &points);
- points *= (int)scan_modifier( stdin, &expon );
- flag_PT = TRUE;
- }
-
- else if( !strcmp( str, "K") ) {
- scanf( "%f", &K_coeff);
- scan_modifier( stdin, &expon );
- K_exp = expon;
- }
-
- else if( !strcmp( str, "P") ) {
- if( numb_poles >= MAX_ARRAY) overflow_error();
- scanf( "%f", &poles[ numb_poles ].real);
- poles[ numb_poles ].real *= scan_modifier( stdin, &expon );
- poles[ numb_poles++ ].imag = 0.0;
- }
-
- else if( !strcmp( str, "Z") ) {
- if( numb_poles >= MAX_ARRAY) overflow_error();
- scanf( "%f", &zeros[ numb_zeros ].real);
- zeros[ numb_zeros ].real *= scan_modifier( stdin, &expon );
- zeros[ numb_zeros++ ].imag = 0.0;
- }
-
- else if( !strcmp( str, "PC") ) {
- double real, imag, temp;
- if( numb_poles >= MAX_ARRAY - 1) overflow_error();
- /* Assumes as complex conjugate pair */
- scanf( "%f", &real);
- scanf( "%f", &imag);
- temp = scan_modifier( stdin, &expon );
- real *= temp;
- imag *= temp;
- poles[ numb_poles ].real = real;
- poles[ numb_poles++ ].imag = imag;
- /* Also enter complex pair */
- poles[ numb_poles ].real = real;
- poles[ numb_poles++ ].imag = - imag;
- }
-
- else if( !strcmp( str, "ZC") ) {
- double real, imag, temp;
- if( numb_poles >= MAX_ARRAY - 1) overflow_error();
- /* Assumes as complex conjugate pair */
- scanf( "%f", &real);
- scanf( "%f", &imag);
- temp = scan_modifier( stdin, &expon );
- real *= temp;
- imag *= temp;
- zeros[ numb_zeros ].real = real;
- zeros[ numb_zeros++ ].imag = imag;
- /* Also enter complex pair */
- zeros[ numb_zeros ].real = real;
- zeros[ numb_zeros++ ].imag = - imag;
- }
-
- else if( !strcmp( str, "LOG") ) {
- scan_modifier( stdin, &expon );
- flag_LOG = TRUE;
- }
-
- else if( !strcmp( str, "RADS") ) {
- scan_modifier( stdin, &expon );
- flag_RADS = TRUE;
- }
-
- else if( !strcmp( str, "PHASE") ) {
- scan_modifier( stdin, &expon );
- flag_PHASE = TRUE;
- }
-
- else if( !strcmp( str, "STEP") ) {
- scan_modifier( stdin, &expon );
- flag_STEP = TRUE;
- }
-
- else {
- fprintf( stderr, "Syntax Error, ");
- fprintf( stderr, "Unrecognized input string \"%s\". ", str );
- fprintf( stderr, "String ignored. \n");
- }
- }
-
- if( *str != '#' ) *str = EOF ;
- return( *str );
- } /* End of read subroutine */
-
- /* Checks if essential input informaiton is present */
- check_input()
- {
- if( flag_S == FALSE ) {
- fprintf( stderr, "Starting point unspecified! " );
- fprintf( stderr, "Fatal Error. \n");
- exit(1);
- }
-
- if( flag_E == FALSE ) {
- fprintf( stderr, "Ending point unspecified! " );
- fprintf( stderr, "Fatal Error. \n");
- exit(1);
- }
-
- if( flag_PT == FALSE ) {
- fprintf( stderr, "Number of data points unspecified! \n" );
- fprintf( stderr, "Default of 20 will be used. \n");
- points = 20;
- }
- }
-
-
- /* Looks for some type of value modifie, such as kilo (x1000)
- * or micro (x0.000001). Then will be expecting a colon as endd
- * of line marker. Returns a double persion number for
- * scaling purposes.
- */
-
- double scan_modifier( input, expon )
- FILE *input;
- int *expon;
- {
- double scale = 1.0;
- char string[ STR_LNGTH ];
-
- while( (fscanf( input, "%s", string) != EOF) && (*string != ';' ) ) {
-
- switch( *string) {
-
- case 'K':
- scale = 1000;
- *expon = 3;
- break;
-
- case 'M':
- scale = 1000000;
- *expon = 6;
- break;
-
- case 'G':
- scale = 1000000000;
- *expon = 9;
- break;
-
- case 'T':
- scale = 1000000000000;
- *expon = 12;
- break;
-
- case 'm':
- scale = 0.001;
- *expon = -3;
- break;
-
- case 'u':
- scale = 0.000001;
- *expon = -6;
- break;
-
- case 'n':
- scale = 0.000000001;
- *expon = -9;
- break;
-
- case 'p':
- scale = 0.000000000001;
- *expon = -12;
- break;
-
- case 'E':
- {
- int K;
- fscanf( input, "%d", &K);
- *expon = 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 );
- }
-
- display()
- {
- int i, j;
-
- /*
- printf("%d \n", data_set);
- */
-
- for(i = 0; i < data_set ; i++ ) {
- printf( "%d %s \n", output[i].numb_point, output[i].name );
- printf( "%d \n", output[i].numb_point);
- for(j = 0; j < output[ i ].numb_point ; j++) {
- printf( "%15f, %15f \n", output[i].x[j], output[i].y[j]);
- }
- }
- }
-
-
- double scale_data()
- {
- double net_mean ;
- int mean_order ;
- double gamma, mag;
- struct cmplx_num cgamma;
-
- net_mean = 0.0;
- mean_order = 0;
-
- /* Find geometric mean of all non zeros and poles */
- for( i = 0; i < numb_zeros ; i++ ) {
- mag = cmag( zeros[i] );
- if( mag > 0 ) {
- net_mean += log( mag);
- mean_order++;
- }
- }
- for( i = 0; i < numb_poles ; i++ ) {
- mag = cmag( poles[i] );
- if( mag > 0 ) {
- net_mean += log( mag);
- mean_order++;
- }
- }
- gamma = exp( net_mean / (double)mean_order );
-
- /* Set complex scaling constant, and scale all poles and zeros */
- cset( cgamma, (1 / gamma), 0);
-
- for( i = 0; i < numb_zeros ; i++ ) {
- cmul( zeros[i], cgamma, zeros[i]);
- }
- for( i = 0; i < numb_poles ; i++ ) {
- cmul( poles[i], cgamma, poles[i]);
- }
-
- /* Rescale K_coeff, note: care for overflow must be observed */
- K_coeff = exp( (double)(numb_zeros - numb_poles)*log( gamma ) + log( K_coeff ) + 2.30258509 * (double)K_exp );
-
- return( gamma );
- } /* End of data scale routine */
-
-
- #undef scanf
- /* A lousy fucking patch for micro-soft C. It doesn't
- * seem to read floating point numbers properly.
- */
- my_scanf( str, reg)
- char *str;
- union {
- int x;
- double y;
- char t;
- } *reg;
-
- {
- double atof();
- if( !strcmp( str, "%f") ) {
- char temp[40];
- scanf( "%s", temp);
- reg->y = atof( temp);
- }
- else scanf( str, reg);
- }
-