/* Title: bestind.c
 * Author: Jed Marti KI7NNP
 * Description: Exhaustive search on each equation for the closest inductor.
 * Revision History: (Created Sat Jan 27 11:54:34 2024)
 */


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <string.h>

#include "inductor.h"
#include "equations.h"

// See cmdline.c
extern int32_t W;
extern double  WDIA;
extern double  maxlength;
extern double  minlength;
extern double  maxradius;
extern double  minradius;
extern double  uh;
extern uint8_t E;
extern char    *ENames[];
extern double  reslength;
extern double  resradius;
extern int32_t minturns;
extern int32_t maxturns;

// For recommendations.
extern equations allEqs[];

// The recommendation names (a macro)
char *RNames[] = REC;

void findBest(void)
/*     Find the closest inductance to the request using the requested equation and display the
 *   result.
 * Parameters: none
 * External References:
*   WDIA: Wire diameter in metric.
*   maxlength: The maximum coil length in meters.
*   minlength: The minimum coil length in meters.
*   maxradius: The maximum coil radius in meters.
*   minradius: The minimum coil radius in meters.
*   uh: Requested inductance in uH.
*   E: Index of requested equation.
*   ENames[]: Table of coil names by index E.
*   reslength: Resolution of the length search - integer
*   resradius: Resolution of radius search.
*   minturns: The minimum number of turns to consider.
*   maxturns: The maximum number of turns to consider.
* Returned values: none - results displayed, done.
* Errors detected: Does not consider coils where the wire diameter * turns is greater than the 
*   length.
*/
{
  int32_t len, lencnt;
  int32_t rad, radcnt;
  int32_t turns;
  int32_t i;
  double  leninc;
  double  radinc;
  double  l, r;

  double  bestdiff = 1.0E6;
  double  bestuh;
  double  testuh;
  double  bestlen;
  double  bestrad;
  int32_t bestturns;
  double  wrad;
  
  // Length search.
  leninc = (maxlength - minlength) / reslength;
  lencnt = (int32_t) ((maxlength - minlength) / leninc + 0.5);

  // Radius search values.
  radinc = (maxradius - minradius) / resradius;
  radcnt = (int32_t) ((maxradius - minradius) / radinc + 0.5);

  // All want radius.
  wrad = WDIA / 2.0;
  // Try all the turns.
  for (turns = minturns; turns <= maxturns; ++turns)
  {
    // Scan the available lengths.
    for (len = 0; len < lencnt; ++len)
    {
      l = minlength + len * leninc;

      // Punt if too many turns in too little length.
      if ((turns * WDIA) < l)
      {
        // Scan the radii.
        for (rad = 0; rad < radcnt; ++rad)
        {
          r = minradius + rad * radinc;

          // Select which equation to use.
          switch (E) {
          case eqARRLOriginal:
            testuh = ARRLOriginal(r, turns, l, wrad);
            break;
          case eqARRLTurns:
            testuh = ARRLTurns(r, turns, l, wrad);
            break;
          case eqARRLcspacing:
            testuh = ARRLcspacing(r, turns, l, wrad);
            break;
          case eqARRLall22:
            testuh = ARRLall22(r, turns, l, wrad);
            break;
          case eqARRLall:
            testuh = ARRLall(r, turns, l, wrad);
            break;
          case eqSimple:
            testuh = 1.0e6 * Simple(r, turns, l, wrad);
            break;
          case eqEquation8:
            testuh = Equation8(r, turns, l, wrad);
            break;
          case eqEquationA:
            testuh = 1.0E6 * EquationA(r, turns, l, wrad);
            break;
          case eqEquationD:
            testuh = 1.0E6 * EquationD(r, turns, l, wrad);
            break;
          case eqEquationF:
            testuh = 1.0E6 * EquationF(r, turns, l, wrad);
            break;
          case eqEquationG:
            testuh = 1.0E6 * EquationG(r, turns, l, wrad);
            break;
          case eqEquationH:
            testuh = 1.0E6 * EquationH(r, turns, l, wrad);
            break;
	  case eqEquationI:
	    testuh = 1.0E6 * EquationI(r, turns, l, wrad);
          case eqRFC:
            testuh = rfc(r, turns, l, wrad);
            break;
          case eqRF1:
            testuh = rf1(r, turns, l, wrad);
            break;
          case eqLundin:
            testuh = 1.0e6 * lundin(r, turns, l, wrad);
            break;
          case eqMiller:
            testuh = 1.0e6 * miller(r, turns, l, wrad);
            break;
          }

          // The best?
          if (fabs(testuh - uh) < bestdiff)
          {
            bestdiff = fabs(testuh - uh);
            bestuh = testuh;
            bestlen = l;
            bestrad = r;
            bestturns = turns;
          }
        }
      }
    }
  }

  // The result.
  printf("For equation %s:\n", ENames[E]);
  printf("Best result %g uH, %d turns, length = %g\",  radius = %g\"\n", bestuh, bestturns,
         meters2inches(bestlen), meters2inches(bestrad));


  // Now do the recommendations based on the result.
  printf("Recommendations:\n");
  for (i = 0; i < eqMiller; ++i)
  {
    printf("%20s: %s\n", ENames[i],
	   RNames[(allEqs[i].recommend)(bestrad, bestturns, bestlen, wrad)]);
  }

  // Execute this.
  printf("\nExecute this:\n");
  printf("coil inductor.scad -radius %g -length %g -turns %d\n", meters2inches(bestrad),
	 meters2inches(bestlen), bestturns);
}


// EOF
