char E12_rcsid[] ="@(#)$Header: /Work/User/src/E12/RCS/E12.c 2.3 1997/11/03 21:55:34 cts Exp $";
/*+ "RCS info"*/
/* E12 functions                                                            *
 * input:  resistor value R, 1<= R < 10                                     *
 * output: E12 value which fits R best                                      *
 *                                                                          *
 * E12_1:  best fit with one resistor                                       *
 * E12_2s: best fit with two resistors in series                            *
 * E12_2p: best fit with two resistor in parallel                           *
 *                                                                          *
#define DEBUG_E12_1
#define DEBUG_E12_ceil
#define DEBUG_E12_floor
#define DEBUG_E12_2s
#define DEBUG_E12_2p

 * $Revision: 2.3 $
 * $State: Exp $
 * $Author: cts $
 * $Locker:  $
 * $Date: 1997/11/03 21:55:34 $
 *
 * $Log: E12.c $
 * Revision 2.3  1997/11/03 21:55:34  cts
 * none
 *
 * Revision 2.2  1997/10/18  02:22:58  cts
 * reverse order for search (2s) -> for 2 solutions values are nearer together. fixed some scale bugs.
 *
 * Revision 2.1  1997/10/18  01:36:50  cts
 * resistor arithmetics. r2 series works!
 *
 * Revision 2.0  1997/10/13 00:42:59  cts
 * create struct for resistor: value, scale, index
 *
 * Revision 1.4  1997/10/12  22:25:16  cts
 * ident info
 *
 * Revision 1.3  1997/10/10  00:32:47  cts
 * type for res+index?, better scaling neccessary
 *
 * Revision 1.2  1997/10/10  00:10:00  cts
 * problems with scale
 *
 * Revision 1.1  1997/10/05  03:07:34  cts
 * E12 1, 2s and 2p
 *
*/
/*- */
#include "main.h"

double E6[]  = { 0, 1.0, 1.5, 2.2, 3.3, 4.7, 6.8, 10 };
double E12[] = { 0, 1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2, 10 };
double E24[] = { 0, 1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7,
3.0, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1, 10 };

/*+ "struct resistor E12_scale(struct resistor r)" */
struct resistor E12_scale(struct resistor r)
/* Wid skalieren auf 1<=r<10, scale setzen */
/* quick'n dirty, mit logarithmus gehts schneller */
/* bug: index wird nicht gesetzt!!! */
{
	int i;
	double deviate1, deviate2;

	while ( ( r.value <1. ) || ( r.value >= 10. ) ) {
/*                printf ("value:%f, scale:%f\n", r.value, r.scale); */
		if ( r.value < 1. ) {
			r.scale /= 10.;
			r.value *= 10.;
		}
		else if ( r.value >= 10. ) {
			r.scale *= 10.;
			r.value /= 10.;
		}
	}
	for ( i = 1; i <= E12_N; i++ )
	{
		if ( ( E12[i] <= r.value ) && ( E12[i+1] > r.value ) ) {
			deviate1 = r.value/E12[i] - 1.;
			deviate2 =  1. - r.value/E12[i+1];
			if ( deviate1 <= deviate2 ) {
				r.index = i;
				return r;
			}
			else {
				r.index = i+1;
				return r;
			}
		}
	}

	return r;
}
/*- */

/*+ "struct resistor E12_1(struct resistor r)" */
struct resistor E12_1(struct resistor r)
{
	int i;
	double deviate1, deviate2;

	if ( r.value == 0. ) {
		return r;
	}
	r = res_scale(r);
	if ( ( r.value < 1. ) || ( r.value >= 10.) ) {
		printf("value: %8.3f\n", r.value);
		r.value = -1.;
		r.scale = -1.;
		r.index = -1;
		puts("ERROR in E12_1 (value out of range) !!!");
		exit(EXIT_FAILURE);
		return r;
	}

	for ( i = 1; i <= E12_N; i++ )
	{
		if ( ( E12[i] <= r.value ) && ( E12[i+1] > r.value ) ) {
			deviate1 = r.value/E12[i] - 1.;
			deviate2 = 1. - r.value/E12[i+1];
#ifdef DEBUG_E12_1
			printf("E12_1: %f   %f\n", deviate1, deviate2 );
#endif
			if ( deviate1 <= deviate2 ) {
				r.value = E12[i];
				r.index = i;
				return r;
			}
			else {
				r.value = E12[i+1];
				r.index = i+1;
				return r;
			}
		}
	}
	r.value = -1.;
	r.scale = -1.;
	r.index = -1;
	return r;
}
/*- */

/*+ "struct resistor E12_ceil(struct resistor r)" */
struct resistor E12_ceil(struct resistor r)
/* E12_ceil >= r */
{
	struct resistor res;

	res = E12_1(r);
	if ( res.value < r.value) {
		res.index += 1 ;
		res.value = E12[res.index];
	}

	return res;
}
/*- */

/*+ "struct resistor E12_floor(struct resistor r)" */
struct resistor E12_floor(struct resistor r)
/* E12_1_floor <= r */
{
	struct resistor res;

	res = E12_1(r);
	if ( res.value > r.value) {
		res.index -= 1 ;
		res.value = E12[res.index];
	}

	return res;
}
/*- */

/*+ "double E12_2s(double r, int *index1, int *index2)" */
double E12_2s(struct resistor r, struct resistor *r1, struct resistor *r2)
{
/* 1.Wid <= r, 1.Wid >= r/2
   best fit für (r-1.wid) -> 2.Wid
 */
	int i;
	double res, deviate;
	struct resistor res1, res2, r1min, r1max;

	deviate = res_val(r);
	r1max = E12_floor(r); /* r1 <= r */
	r1min = E12_ceil( res_set( res_val(r)/2. ) ); /* r1 >= r/2 */
#ifdef DEBUG
	printf("E12_2s: search R1 from %8.3f to %8.3f\n", res_val(r1min), res_val(r1max));
#endif
	if ( r1min.scale == r1max.scale ) {
/*+ "same scale"*/
		for (i = r1min.index; i <= r1max.index ; i++) {
			res1 = res_set(E12[i] * r1max.scale);
			res2 = E12_1( res_sub(r, res1) );
			res  = res_val(res1) + res_val(res2);
#ifdef DEBUG
			printf("E12_2s_1: %8.3f ~= %8.3f = %8.3f + %8.3f\n", res_val(r), res, res_val(res1), res_val(res2));
#endif
			if ( pow( (res_val(r) - res), 2) < pow( deviate, 2) ) {
				*r1 = res_eq(res1);
				*r2 = res_eq(res2);
				deviate = res_val(r) - res;
			}
		}
	}
/*- "same scale"*/
	else {
/*+ "diff scale"*/
		for (i =r1min.index; i <= E12_N; i++) {
			res1 = res_set(E12[i] * r1min.scale);
			res2 = E12_1( res_sub(r, res1) );
			res  = res_val(res1) + res_val(res2);
#ifdef DEBUG
			printf("E12_2s_3: %8.3f ~= %8.3f = %8.3f + %8.3f\n", res_val(r), res, res_val(res1), res_val(res2));
#endif
			if ( pow( (res_val(r) - res), 2) < pow( deviate, 2) ) {
				*r1 = res_eq(res1);
				*r2 = res_eq(res2);
				deviate = res_val(r) - res;
			}
		}
		for (i = 1; i <= r1max.index; i++) {
			res1 = res_set(E12[i] * r1max.scale);
			res2 = E12_1( res_sub(r, res1) );
			res  = res_val(res1) + res_val(res2);
#ifdef DEBUG_E12_2s
			printf("! r:%8.3f res1:%8.3f r-res1:%8.3f res2=r-res1:%8.3f\n", res_val(r), res_val(res1), res_val(r) - res_val(res1), res_val(res2));
#endif
#ifdef DEBUG
			printf("E12_2s_2: %8.3f ~= %8.3f = %8.3f + %8.3f\n", res_val(r), res, res_val(res1), res_val(res2));
#endif
			if ( pow( (res_val(r) - res), 2) < pow( deviate, 2) ) {
				*r1 = res_eq(res1);
				*r2 = res_eq(res2);
				deviate = res_val(r) - res;
			}
		}
	}
/*- "diff scale"*/
/*        else {
		printf("internal error!\n");
		printf("r1min.scale %f|%f\n", r1min.scale, 0.1 - r1min.scale);
		exit(EXIT_FAILURE);
end of check, does not work anymore...
	}
*/
	return ( res_val(*r1) + res_val(*r2) );

}
/*- */

/*+ "double E12_2p(double r, int *index1, int *index2)" */
double E12_2p(struct resistor r, struct resistor *r1, struct resistor *r2)
{
/* 1.Wid >= r, 1.Wid <= r*2
   best fit für (r-1.wid) -> 2.Wid
 */
	int i;
	double res, deviate;
	double s, s1, s2; /* Leitfähigkeit */
	struct resistor res1, res2, r1min, r1max;

	deviate = res_val(r);
	if (res_val(r) > 0.) {
		s = 1. / res_val(r);
	}
	else {
		s = 0.;
	}
	r1min = E12_ceil(r); /* r1 >= r */
	r1max = E12_floor( res_set( res_val(r) * 2. ) ); /* r1 <= r*2 */
#ifdef DEBUG_E12_2p
	printf("E12_2p: search R1 from %8.3f to %8.3f\n", res_val(r1min), res_val(r1max));
#endif
	if ( r1min.scale == r1max.scale ) {
/*+ "same scale"*/
		for (i = r1min.index; i <= r1max.index ; i++) {
			res1 = res_set(E12[i] * r1max.scale);
			if ( res_val(res1) > 0. ) {
				s1 = 1. / res_val(res1);
			}
			else {
				s1 = 0.;
			}
			s2 = s - s1;
			if ( s2 > 0. ) {
				res2 = E12_1( res_set(1./s2) );
				if (res_val(res2)> 0. ) {
					s2 = 1. / res_val(res2);
					res  = 1. / ( s1 + s2 );
				}
				else {
				res  = res_val(res1);
				}
			}
			else {
				s2 = 0;
				res  = res_val(res1);
			}
#ifdef DEBUG_E12_2p
			printf("E12_2p_1: %8.3f ~= %8.3f = %8.3f p %8.3f\n", res_val(r), res, res_val(res1), res_val(res2));
#endif
			if ( pow( (res_val(r) - res), 2) < pow( deviate, 2) ) {
				*r1 = res_eq(res1);
				*r2 = res_eq(res2);
				deviate = res_val(r) - res;
			}
		}
	}
/*- "same scale"*/
	else { /* ( r1min.scale != r1max.scale ) */
/*+ "diff scale"*/
		for (i =r1min.index; i <= E12_N; i++) {
			res1 = res_set(E12[i] * r1max.scale);
			if ( res_val(res1) > 0. ) {
				s1 = 1. / res_val(res1);
			}
			else {
				s1 = 0.;
			}
			s2 = s - s1;
			if ( s2 > 0. ) {
				res2 = E12_1( res_set(1./s2) );
				if (res_val(res2)> 0. ) {
					s2 = 1. / res_val(res2);
					res  = 1. / ( s1 + s2 );
				}
				else {
				res  = res_val(res1);
				}
			}
			else {
				s2 = 0;
				res  = res_val(res1);
			}
#ifdef DEBUG_E12_2p
			printf("E12_2p_2: %8.3f ~= %8.3f = %8.3f p %8.3f\n", res_val(r), res, res_val(res1), res_val(res2));
#endif
			if ( pow( (res_val(r) - res), 2) < pow( deviate, 2) ) {
				*r1 = res_eq(res1);
				*r2 = res_eq(res2);
				deviate = res_val(r) - res;
			}
		}
		for (i = 1; i <= r1max.index; i++) {
			res1 = res_set(E12[i] * r1max.scale);
			if ( res_val(res1) > 0. ) {
				s1 = 1. / res_val(res1);
			}
			else {
				s1 = 0.;
			}
			s2 = s - s1;
			if ( s2 > 0. ) {
				res2 = E12_1( res_set(1./s2) );
				if (res_val(res2)> 0. ) {
					s2 = 1. / res_val(res2);
					res  = 1. / ( s1 + s2 );
				}
				else {
				res  = res_val(res1);
				}
			}
			else {
				s2 = 0;
				res  = res_val(res1);
			}
#ifdef DEBUG_E12_2p
			printf("E12_2p_3: %8.3f ~= %8.3f = %8.3f p %8.3f\n", res_val(r), res, res_val(res1), res_val(res2));
#endif
			if ( pow( (res_val(r) - res), 2) < pow( deviate, 2) ) {
				*r1 = res_eq(res1);
				*r2 = res_eq(res2);
				deviate = res_val(r) - res;
			}
		}
	}
/*- "diff scale"*/
	return ( 1. / ( 1./ res_val(*r1) + 1. / res_val(*r2) ) );

}
/*- */
