/*---------------------------------------------------------------------

  pwscal.c written by L. Granroth  12-28-95
  as example code for using "pwslrcal.tab" to calibrate Galileo PWS LRS data.

  These functions are available:

  int pwscal_init (int type);
    reads calibration tables and initializes
    returns 0 for success and errno for failure
    type is the requested calibration units to be returned
      1 is either Volts or nano-Tesla
      2 is either E or B field squared (V^2/m^2 or nT^2)
      3 is spectral density, either V^2/m^2/Hz or nT^2/Hz

  float pwscal_SA (int dn, int chan, int antenna);
    calibrates spectrum analyzer data
    returns float calibrated type specified in pwscal_init
    dn is uncalibrated 8-bit data number (0 - 255)
    chan is SA channel number (1 - 4)
    antenna is 0 for electric and 1 for magnetic

  float pwscal_SFR (int dn, int chan, int antenna);
    calibrates sweep frequency receiver data
    returns float calibrated type specified in pwscal_init
    dn is uncalibrated 8-bit data number (0 - 255)
    chan is SFR channel number (1 - 112)
    antenna is 0 for electric and 1 for magnetic

  float pwscal_HFR (int dn, int chan);
    calibrates electric high frequency receiver data
    returns float calibrated type specified in pwscal_init
    dn is uncalibrated 8-bit data number (0 - 255)
    chan is HFR channel number (1 - 42)

  Note that if pwscal_init is not called successfully or if invalid
  arguments are passed to the calibration routines, float zero is returned.

  ---------------------------------------------------------------------*/

#define CALIBRATED 1
#define FIELDSQUARED  2
#define SPECTRALDENSITY 3

#define ELECTRIC 0
#define MAGNETIC 1

#define CALFILE "PWSLRCAL.TAB"

#include <errno.h>
#include <stdio.h>

FILE *calf;

float SAcal[256];
float SFR1cal[256], SFR2cal[256], SFR3cal[256], SFR4cal[256];
float HFRcal[256];

float SAgain[2][4] = {{0.0}};
float SFRgain[2][112] = {{0.0}};
float HFRgain[42] = {0.0};

float SAbw[4] = {1.0};
float SFRbw[4] = {1.0};
float HFRbw = 1.0;
float Elength = 1.0;

/*---------------------------------------------------------------------

  pwscal_init - initialize Galileo PWS LRS calibrations

  ---------------------------------------------------------------------*/

int
pwscal_init (int type)
{
  int i;
  float bw;

  if (calf) fclose (calf);

  if (!(calf = fopen (CALFILE, "r"))) return (errno);

  for (i = 0; i < 256; i++)
    if (!fscanf (calf, "%g", SAcal+i)) return (errno);

  for (i = 0; i < 256; i++)
    if (!fscanf (calf, "%g", SFR1cal+i)) return (errno);
  for (i = 0; i < 256; i++)
    if (!fscanf (calf, "%g", SFR2cal+i)) return (errno);
  for (i = 0; i < 256; i++)
    if (!fscanf (calf, "%g", SFR3cal+i)) return (errno);
  for (i = 0; i < 256; i++)
    if (!fscanf (calf, "%g", SFR4cal+i)) return (errno);

  for (i = 0; i < 256; i++)
    if (!fscanf (calf, "%g", HFRcal+i)) return (errno);

  for (i = 0; i < 8; i++)
    if (!fscanf (calf, "%g", SAgain[0]+i)) return (errno);

  for (i = 0; i < 224; i++)
    if (!fscanf (calf, "%g", SFRgain[0]+i)) return (errno);

  for (i = 0; i < 42; i++)
    if (!fscanf (calf, "%g", HFRgain+i)) return (errno);

  for (i = 0; i < 4; i++)
    if (!fscanf (calf, "%g", SAbw+i)) return (errno);

  for (i = 0; i < 4; i++)
    if (!fscanf (calf, "%g", SFRbw+i)) return (errno);

  if (!fscanf (calf, "%g", &HFRbw)) return (errno);

  if (!fscanf (calf, "%g", &Elength)) return (errno);

  fclose (calf); calf = (FILE *)0;

  /* manipulate the calibration and gain arrays for various units */

  if (type > CALIBRATED) {

    /* convert calibrated Volts to Volts squared (or nano-Tesla to nT^2) */

    for (i = 0; i < 256; i++) {
      SAcal[i]   *= SAcal[i];
      SFR1cal[i] *= SFR1cal[i];
      SFR2cal[i] *= SFR2cal[i];
      SFR3cal[i] *= SFR3cal[i];
      SFR4cal[i] *= SFR4cal[i];
      HFRcal[i]  *= HFRcal[i];
    }

    /* convert effective electrical length to meters squared */

    Elength *= Elength;

    /* fold electrical length and bandwidths into squared gain multipliers */

    for (i = 0; i < 4; i++) {
      bw = type > FIELDSQUARED ? SAbw[i] : 1.0;
      SAgain[ELECTRIC][i] *= SAgain[ELECTRIC][i] / Elength / bw;
      SAgain[MAGNETIC][i] *= SAgain[MAGNETIC][i] / bw;
    }

    for (i = 0; i < 112; i++) {
      bw = type > FIELDSQUARED ? SFRbw[i/28] : 1.0;
      SFRgain[ELECTRIC][i] *= SFRgain[ELECTRIC][i] / Elength / bw;
      SFRgain[MAGNETIC][i] *= SFRgain[MAGNETIC][i] / bw;
    }

    bw = type > FIELDSQUARED ? HFRbw : 1.0;
    for (i = 0; i < 42; i++)
      HFRgain[i] *= HFRgain[i] / Elength / bw;

  } /* if type > CALIBRATED */

  return (0);

} /* pwscal_init - initialize Galileo PWS LRS calibrations */
        
/*---------------------------------------------------------------------

  pwscal_SA - calibrate Galileo PWS LRS SA

  ---------------------------------------------------------------------*/

float
pwscal_SA (int dn, int chan, int antenna)
{

  if ((dn < 1) || (dn > 255) || (chan < 1) || (chan > 4)) return (0.0);
  antenna &= 1;

  return (SAcal[dn] * SAgain[antenna][--chan]);

} /* pwscal_SA - calibrate Galileo PWS LRS SA */

/*---------------------------------------------------------------------
 
  pwscal_SFR - calibrate Galileo PWS LRS SFR

  ---------------------------------------------------------------------*/

float
pwscal_SFR (int dn, int chan, int antenna)
{

  if ((dn < 1) || (dn > 255) || (chan < 1) || (chan > 112)) return (0.0);
  antenna &= 1;

  chan--;

  switch (chan / 28) {

    case 0: return (SFR1cal[dn] * SFRgain[antenna][chan]);
    case 1: return (SFR2cal[dn] * SFRgain[antenna][chan]);
    case 2: return (SFR3cal[dn] * SFRgain[antenna][chan]);
    case 3: return (SFR4cal[dn] * SFRgain[antenna][chan]);

  } /* switch */

  return 0.0;
   
} /* pwscal_SFR - calibrate Galileo PWS LRS SFR */

/*---------------------------------------------------------------------
 
  pwscal_HFR - calibrate Galileo PWS LRS HFR

  ---------------------------------------------------------------------*/

float
pwscal_HFR (int dn, int chan)
{

  if ((dn < 1) || (dn > 255) || (chan < 1) || (chan > 42)) return (0.0);

  return (HFRcal[dn] * HFRgain[--chan]);
   
} /* pwscal_HFR - calibrate Galileo PWS LRS HFR */

