// HDL_ANT3.CPP     copyright 1994,1995,1996,1998,2003 Paul Wade W1GHZ, N1BWT
// version 3.0 *BETA 4 * March 2003
// corrections W2IMU feedhorn - slight numerical error
// version 3.0 *BETA 3 * November 1998
// adding W2IMU feedhorn
// version 3.0 *BETA 2 * April 1998
// adding curve-fitting for offset dishes
// adding conical horns
// and correcting offset dish to axis

// version 2.1e   1 April 1996
// 2.1 fixes precision problem
// e version for the metric-impaired
//
//      Any licensed radio amateur may use this program without 
//      charge; all other persons must send $73 to the 
//      ARRL Foundation, 225 Main St., Newington, CT 06111

//The source file, HDLANT3.CPP, was compiled using Borland C++
//version 4.52.  Any part of it may be modified or used as part
//of another program by any amateur radio operator, provided
//that credit is given and provided there is no charge for
//its use.

//Send problems, suggestions, and comments to Paul Wade, W1GHZ.
//Expect support commensurate with the cost of the program!

//antenna.h - header file for antenna.cpp
//
// N1BWT 1994
// compiled with Borland C++ version 3.1
// 1995 Borland C++ version 4.0
// 1998 Borland C++ version 4.52

#include <math.h>
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>
#include <ctype.h>
#include <strstrea.h>
#include <string.h>
#include <bios.h>
//#include <constrea.h>
#include <conio.h>

extern unsigned _stklen = 32004; // increase stack size


//#include <ps.h>         // PostScript commands
// inlining because compiler won't handle multiple files

// ps.h for HDL_ANT.CPP
//
// started from
//point.h
// from Gorlen, K.E., Orlow, S.M., and Plexico, P.S., 
// Data Abstraction and Object-Oriented Programming in C++,
// -------------------------------------------------------
// Wiley, 1990, p. 105

//#include <iostream.h>

class Point
{
    double xc,yc;          // x-y coordinates

friend ostream& operator<<(ostream&, const Point& );
    
public:
    Point()                             { xc = yc = 0; }
    Point(double newx, double newy)     { xc = newx; yc = newy; }
    double x() const                    { return xc; }
    double x(double newx)               { return xc = newx; }
    double y() const                    { return yc; }
    double y(double newy)               { return yc = newy; }

    Point operator+(const Point& p)  { return Point(xc + p.xc, yc + p.yc); } 

    void operator+=(const Point& p) 
    {   
        xc += p.x();
        yc += p.y();
    }

    void printOn(ostream& strm = cout) const;

};

void Point::printOn(ostream& strm) const
{
    strm << '(' << xc << ',' << yc << ')';
}    
 
ostream& operator<<(ostream& strm, const Point& p)
{
    p.printOn(strm);
    return strm;
}



class PS_point: public Point
{
    double xl,yl;          // x-y coordinates

friend ostream& operator<<(ostream&, const PS_point& );

public:
    PS_point()                     { xl = yl = 0; }
    PS_point(double newx, double newy)   { xl = newx; yl = newy; }
    PS_point(const Point& p)	    { xl = p.x(); yl = p.y(); }

    void operator=(const Point& p)    { xl = p.x(); yl = p.y(); }
  //				{ return PS_point(p.x(),p.y());}

    PS_point operator+(const PS_point& p)
				     { return PS_point(xl + p.xl, yl + p.yl);}

    void operator+=(const Point& p)
    {
	xl += p.x();
	yl += p.y();
    }

    void printOn(ostream& strm = cout) const;

};

void PS_point::printOn(ostream& strm) const
{
    strm << xl << " mm "  << yl << " mm ";
}

ostream& operator<<(ostream& strm, const PS_point& p)
{
    p.printOn(strm);
    return strm;
}



class PS_lineto: public Point
{
    double xl,yl;          // x-y coordinates

friend ostream& operator<<(ostream&, const PS_lineto& );

public:
    PS_lineto()                             { xl = yl = 0; }
    PS_lineto(double newx, double newy)     { xl = newx; yl = newy; }
    PS_lineto(const Point& p)	            { xl = p.x(); yl = p.y(); }

    void operator=(const Point& p)          { xl = p.x(); yl = p.y(); }
  //				{ return PS_lineto(p.x(),p.y());}

    PS_lineto operator+(const PS_lineto& p)
				     { return PS_lineto(xl + p.xl, yl + p.yl);}

    void operator+=(const Point& p)
    {
	xl += p.x();
	yl += p.y();
    }

    void printOn(ostream& strm = cout) const;

};

void PS_lineto::printOn(ostream& strm) const
{
    strm << xl << " mm "  << yl << " mm lineto";
}

ostream& operator<<(ostream& strm, const PS_lineto& p)
{
    p.printOn(strm);
    return strm;
}


class PS_moveto: public Point
{
    double xl,yl;          // x-y coordinates

friend ostream& operator<<(ostream&, const PS_moveto& );

public:
    PS_moveto()                                 { xl = yl = 0; }
    PS_moveto(double newx, double newy)         { xl = newx; yl = newy; }
    PS_moveto(const Point& p)	                { xl = p.x(); yl = p.y(); }

    void operator=(const Point& p)              { xl = p.x(); yl = p.y(); }

//    PS_moveto operator=(const Point& p)  //   { xl = p.x(); yl = p.y(); }
  //				{ return PS_moveto(p.x(),p.y());}

    PS_moveto operator+(const PS_moveto& p)
      			        { return PS_moveto(xl + p.xl, yl + p.yl);}

    void operator+=(const Point& p)
    {
	xl += p.x();
	yl += p.y();
    }

    void printOn(ostream& strm = cout) const;

};

void PS_moveto::printOn(ostream& strm) const
{
    strm << xl << " mm "  << yl << " mm moveto";
}

ostream& operator<<(ostream& strm, const PS_moveto& p)
{
    p.printOn(strm);
    return strm;
}


class PS_translate: public Point
{
    double xl,yl;          // x-y coordinates

friend ostream& operator<<(ostream&, const PS_translate& );

public:
    PS_translate()                           { xl = yl = 0; }
    PS_translate(double newx, double newy)   { xl = newx; yl = newy; }
    PS_translate(const Point& p)	     { xl = p.x(); yl = p.y(); }

    void operator=(const Point& p)           { xl = p.x(); yl = p.y(); }
  //				{ return PS_translate(p.x(),p.y());}

    PS_translate operator+(const PS_translate& p)
				{ return PS_translate(xl + p.xl, yl + p.yl);}

    void operator+=(const Point& p)
    {
	xl += p.x();
	yl += p.y();
    }

    void printOn(ostream& strm = cout) const;

};

void PS_translate::printOn(ostream& strm) const
{
    strm << xl << " mm "  << yl << " mm translate ";
}

ostream& operator<<(ostream& strm, const PS_translate& p)
{
    p.printOn(strm);
    return strm;
}


class PS_dashline1: public Point
{
    double xl,yl;          // x-y coordinates

friend ostream& operator<<(ostream&, const PS_dashline1& );

public:
    PS_dashline1()                          { xl = yl = 0; }
    PS_dashline1(double newx, double newy)  { xl = newx; yl = newy; }
    PS_dashline1(const Point& p)	    { xl = p.x(); yl = p.y(); }

    void operator=(const Point& p)          { xl = p.x(); yl = p.y(); }

//    PS_dashline1 operator=(const Point& p)  //  { xl = p.x(); yl = p.y(); }
  //				{ return PS_dashline1(p.x(),p.y());}

    PS_dashline1 operator+(const PS_dashline1& p)
      			        { return PS_dashline1(xl + p.xl, yl + p.yl);}

    void operator+=(const Point& p)
    {
	xl += p.x();
	yl += p.y();
    }

    void printOn(ostream& strm = cout) const;

};

void PS_dashline1::printOn(ostream& strm) const
{
    strm << xl << " mm "  << yl << " mm [8 4 8 4 3 3 3 3 3 15] lp";
}

ostream& operator<<(ostream& strm, const PS_dashline1& p)
{
    p.printOn(strm);
    return strm;
}


class PS_dashline: public Point
{
    double x1,y1,x2,y2;          // x-y coordinates

friend ostream& operator<<(ostream&, const PS_dashline& );

public:
    PS_dashline()                           { x1 = y1 = 0; }
    PS_dashline(double newx, double newy)   { x1 = y1 = 0; 
                                              x2 = newx; y2 = newy; }
    PS_dashline(const Point& p)	            { x1 = y1 = 0; 
                                              x2 = p.x(); y2 = p.y(); }
    PS_dashline(double newx1, double newy1, double newx2, double newy2)   
                                            { x1 = newx1; y1 = newy1;
                                              x2 = newx2; y2 = newy2; }
    PS_dashline(const Point& p1, const Point& p2)	    
                                            { x1 = p1.x(); y1 = p1.y();
                                              x2 = p2.x(); y2 = p2.y(); }
    PS_dashline(double newx1, double newy1, const Point& p)
                                            { x1 = newx1; y1 = newy1;
                                              x2 = p.x(); y2 = p.y(); }
    PS_dashline(const Point& p, double newx2, double newy2)   
                                            { x1 = p.x(); y1 = p.y(); 
                                              x2 = newx2; y2 = newy2; }
        

    void printOn(ostream& strm = cout) const;

};

void PS_dashline::printOn(ostream& strm) const
{
    strm << x1 << " mm " << y1 << " mm " << x2 << " mm "
         << y2 << " mm [8 4 8 4 3 3 3 3 3 15] lp";
}

ostream& operator<<(ostream& strm, const PS_dashline& p)
{
    p.printOn(strm);
    return strm;
}



#define LINESIZE 1024
#define CTRL_C 0x2e03
#define UP_ARROW 0x4800
#define DOWN_ARROW 0x5000
#define HOME_KEY 0x4700
#define END_KEY 0x4f00
#define ENTER_KEY 0x1c0d



// global constants
    const double c = 299792456.0;     //  meters per second 
    const double pi = 3.1415927 ;
    const double crad = 57.29578 ;

    const int max_pts = 23;     // for curve fitting

// other globals
    
    int lib_init = 1;		/* if lib_init, then we need to initialize
				   the library routines */
    int ph_init = 1;

    char *units = " mm.  ";

    float metric = 1.0;

    char *unit_type = "Metric ";
//






// start of ANTENNA.H - class declarations

class Antenna           // Abstract base class
{
public:
    Antenna();
    void helpscreen();
    void get_freq();
    void get_wg();
    void horn_dimensions();
    void horn_calcgain();
    void horn_phasecenters();
    void horn_angles();
    void G3RPE_approximation(double);
    void banner(ostream&);
    void info_listing(ostream&);
    void post_print(ostream&);
    void PANFI_corr();
    void range_calc();
    void sun_gnd_NF();
    void check_aperture();
    double get_fod() {return fod;};
    double get_wl() {return wavelength;};
    int bad_input() {return bad;};

    double wavelength;          // in mm */
      
protected:
    double freq;      
    double H_wg;                // waveguide H dim. in mm. */ 
    double E_wg;                // waveguide E dim. in mm. */ 
    double axial_length;        // axial length of feed horn flare in mm */
    double H_aperture;          // horn E-Plane aperture in mm */ 
    double E_aperture;          // horn H-Plane aperture in mm */ 
    double horn_gain;       
    double E_phase_center;
    double H_phase_center;
    double E_flare_angle;       // angle from axis to E-side
    double H_flare_angle;       // angle from axis to H-side
    double E_side;
    double E_ang;
    double H_side;
    double H_ang;
    double aperture;
    double efficiency;
    double rayleigh_dist;
    double directivity;
    double fod;
    int bad;                    // problem with input
};


class Horn : public Antenna
{
public:
    Horn();
    void lookup();
    void simple_gain();
    void coords();
    void PS_template();
    void write_data(ostream&, int);
        
private:

    double simplegain;       
    Point inner[6];
    Point outer[6];

};
//







class Dish : public Antenna
{
public:
    Dish();
    void d_init();
    void illumination();
    void calc_gain();
    void phasecenters();
    void PS_template();

    
private:
                // all dimensions in mm.
    double freq;
    double diameter;                
    double depth;                   // at center of dish
    double focal_length;        
    double f_over_D;
    double feedangle;               // diameter subtended angle from focal point
    double feedang_deg;
    double R_edge;                  // distance from focal point to edge
    double space_attn;
    double desired_taper;
    double BW3;                     // 3 dB beamwidth
    double simple_horn_diameter;
    double dish_gain;                 
};


class OffsetDish : public Antenna
{
public:
    OffsetDish();
//    void offset_init();
    void offset_illumination();
    void offset_calc_gain();
    void offset_init2();
    void curve_fit();
    void display_results();
    void three_points();
//    void phasecenters();
//    void PS_template();
    
private:
                // all dimensions in mm.
    double freq;
    double diameter;                
    double small_diameter;          // small axis of oval offset reflector   
    double large_diameter;          // large axis of oval offset reflector      
    double depth;                   // at center of full parabola
    double odepth;                  // deepest point in offset reflector
    double odepth_position;         // distance across rim to deepest pt.
    double tilt_angle;
    double focal_length;        
    double equiv_f_over_D;          // focal length over small diameter
    double f_over_D;
    double feedangle;               // diameter subtended angle from focal point
    double feedang_deg;
    double small_feedangle;         // in plane of small axis
    double small_feedang_deg;       
    double large_feedangle;         // in plane of large axis   
    double large_feedang_deg;          
    double R_edge;                  // distance from focal point to edge
    double R_aim;                   // distance from focal point to aiming pt.
    double space_attn;
    double desired_taper;
    double BW3;                     // 3 dB beamwidth
    double simple_horn_diameter;
    double dish_gain;                 
    double xbot;
    double ybot;
    double xtop;
    double ytop;
};

class Lens : public Antenna
{

public:
    Lens();
    void dimension();    
    void calculate();
    void phasecheck();
    void plates();
    void write_data(ostream &, int);
    void crude_graphics(ostream &);
    
private:

    double Lens_diam ;       /* Lens diameter in mm */
    double spacing   ;       /* metal plate spacing in mm */
    double width_increase ;  /* plates get wider toward edge */
    double shift[25];        /* H-plane phase compensation */
    int N ;                  /* number of plates in lens */
    double BW_E_horn ;           /* feed horn E-plane Beamwidth in degrees */
    double lens_focal_length ;   /* in mm */
    double Gain_lens ;           /* dB added by lens */
    double index ;               /* effective index of refraction */
    double lens_to_horn;        // horn mouth to lens curve center in mm.
    double step;                // step distance in zoned lens plate */
    int compensate ;            // flag for phase center compensation needed
};

class Conical_horn : public Antenna
{ 
public:
    Conical_horn();
    void dimensions();
    void optimum_horn();
    void PS_template();
    void simple_gain();
    void gain();
    void W2IMU_feedhorn();
        
private:
    double axial_length;
    double con_aperture_dia;
    double circ_wg_diam;
    double flare_angle;
    double con_gain;    
};


// end of ANTENNA.H - class declarations

//






// start of ANTENNA.CPP - class member functions

  
Antenna::Antenna()              // Constructor
{
    freq = 0.0;      
    H_wg = 0.0; 
    E_wg = 0.0;
    wavelength = 0.0;
    horn_gain = 0.0;        
    axial_length = 0.0;
    H_aperture = 0.0;
    E_aperture = 0.0;   
    H_flare_angle = 0.0;
    E_flare_angle = 0.0;
    E_side = 0.0;
    E_ang = 0.0;
    H_side = 0.0;
    H_ang = 0.0;
    aperture = 0.0;
    efficiency = 0.0;
    rayleigh_dist = 0.0;
    directivity = 0.0;
    bad = 0;
}

void Antenna::banner(ostream& ostrm)
{  /* a banner */
        
    ostrm << "\n\n\n\n";
    ostrm << "             ***************** \n";
    ostrm << "             *               * \n";
    ostrm << "             *    HDL_ANT    * \n";
    ostrm << "             *  version 3b4  * \n";
    ostrm << "             *BETA3 TEST 3/03* \n";
    ostrm << "             ***************** \n";
    ostrm << "  Please report bugs and comments to w1ghz@arrl.net \n";
    ostrm << "\n       copyright 1994,1995,1996,1998,2003 Paul Wade W1GHZ (N1BWT) \n\n";
    ostrm << "      Version 3 adds conical horn calculations,\n";
    ostrm << "                W2IMU dual-mode feedhorn calculations,\n";
    ostrm << "                and makes some improvements for offset dishes\n";
    ostrm << "      Version 2.1 with option for the metric-impaired\n";
    ostrm << "      -> fixes roundoff error problem with Version 2.0.\n\n";
    ostrm << "      Any licensed radio amateur may use this program "
          << "without \n";
    ostrm << "      charge; all other persons must send $73 to the \n";
    ostrm << "      ARRL Foundation, 225 Main St., Newington, CT 06111";
    ostrm << "\n\n";
}

void Antenna::info_listing(ostream& ostrm)
{

ostrm << "HDL_ANT does the calculations needed to successfully implement\n";
ostrm << "several microwave antennas: horns, parabolic dishes, and \n";
ostrm << "metal-plate lenses.  It also does the calculations involved in\n";
ostrm << "setting up an antenna range for antenna gain measurement.  More\n";
ostrm << "detailed explanations of the antennas and measurements may be\n";
ostrm << "found in the series of QEX articles entitled 'Practical Microwave\n";
ostrm << "Antennas,' in the September, October, and November 1994 issues.\n\n";

ostrm << "An additional article, 'More on Parabolic Dish Antennas,' in the\n";
ostrm << "December 1995 issue of QEX, gave the descriptions for Offset \n";
ostrm << "dishes, Penny feeds, and the use of sun noise to measure antenna\n";
ostrm << "performance and receiver noise figure.\n\n";

ostrm << "All of the above articles and much more are in the 'ARRL UHF/Microwave \n";
ostrm << "Projects Book, Volume 2' with N1BWT and KB1VC on the cover.  A good\n";
ostrm << "reference for all microwave operators.\n\n";

ostrm << "VERSION 3:\n\n";
ostrm << "We recently discovered that the RCA DSS offset dishes are a section \n"; 
ostrm << "of a parabola whose lower edge is the center of the full parabola. \n";
ostrm << "Calculations in previous versions of HDL_ANT may have the bottom  \n";
ostrm << "edge offset from the center; the result was an error in the tilt angle \n"; 
ostrm << "and small error in the focal point.  Version 3 assumes that all offset \n";
ostrm << "dishes start at the center of the full parabola, which may not be true \n";
ostrm << "for odd ones like the oblong Primestar dish. \n\n";

ostrm << "All dimensions are in millimeters, since one mm. is about the \n";
ostrm << "accuracy required for antennas to work well at 10 GHz.\n";
ostrm << "However, there is an option for dimensions in inches, for the\n";
ostrm << "metric-impaired.\n\n";

ostrm << "MENU CHOICES:\n\n";
ostrm << "  H\n\n";

ostrm << "For horn antennas, HDL_ANT will design an 'optimum' horn with \n";
ostrm << "a specified gain (between 10 and 25 dB) for any frequency - use \n";
ostrm << "menu entry 'H' for this option.  It will then create a PostScript\n";
ostrm << "template file which may be used to print a paper template for\n";
ostrm << "horn construction.  The paper template is attached to a sheet of\n";
ostrm << "copper or brass which is cut and folded on the template lines,\n";
ostrm << "then soldered together and soldered to a waveguide.\n\n";
ostrm << "See menu entry 'P' for more details on printing a "
      << "PostScript file.\n\n";

ostrm << "  E\n\n";

ostrm << "Menu entry 'E' is used to calculate the gain and other parameters\n";
ostrm << "for an existing horn - perhaps one you found at a hamfest.  It \n";
ostrm << "can also create a template, to duplicate a horn known to have\n";
ostrm << "good dimensions.\n\n";

ostrm << "  D\n\n";

ostrm << "Parabolic dish calculations are under menu entry 'D'.  The most\n";
ostrm << "important dish dimension is the focal length, and the easiest way\n";
ostrm << "to find it is to measure the depth of the dish in the center,\n";
ostrm << "measured from a straightedge across the rim of the dish.  HDL_ANT\n";
ostrm << "then calculates the focal length and f/D ratio, to allow\n";
ostrm << "selection of the best feed antenna - see the QEX series for\n";
ostrm << "details on feedhorn selection.  For smaller dishes, HDL_ANT can\n";
ostrm << "also generate a PostScript template file;  the printed template\n";
ostrm << "is used to check the accuracy of the parabolic curve of the dish.\n";
ostrm << "If it is not a good fit, sometimes a template for a slightly\n";
ostrm << "larger or smaller f/D ratio gives a better fit, since dishes\n";
ostrm << "sometimes have a flat area or large hole in the center which\n";
ostrm << "yields a misleading depth measurement.\n\n";

ostrm << "  L\n\n";

ostrm << "Menu entry 'L' is used to design metal-plate lens antennas.\n";
ostrm << "These are normally fed by a horn; if an appropriate horn is not\n";
ostrm << "already available, then the 'H' entry may be used to design the\n";
ostrm << "horn.  It may take a few trials to find a good combination of\n";
ostrm << "horn and lens.  Note that the 'optimum' horns designed under the\n";
ostrm << "'H' entry of the HDL_ANT program do not usually have the matched\n";
ostrm << "E-plane and H-plane phase centers needed for good lens\n";
ostrm << "performance; some adjustment of horn dimensions can improve the\n";
ostrm << "phase center matching.  The lens design does not create templates\n";
ostrm << "since the lens curves are all simple circles which can be drawn\n";
ostrm << "more accurately with a compass.\n\n";

ostrm << "  R\n\n";

ostrm << "Antenna range design is selected by menu entry 'R'.  HDL_ANT\n";
ostrm << "calculates the minimum length and measurement height required for\n";
ostrm << "a specified maximum antenna aperture, and then calculates the\n";
ostrm << "height of the source antenna needed to have the RF field peak at\n";
ostrm << "the measurement height.\n\n";

ostrm << "  M  (was C in previous versions)\n\n";

ostrm << "If a noise figure meter is used to measure antenna gain as\n";
ostrm << "described in the November 1994 QEX article, then it is necessary\n";
ostrm << "to convert noise figure readings into antenna gain.  \n";
ostrm << "Menu entry 'M' makes these calculations.\n\n";

ostrm << "  P\n\n";

ostrm << "Menu entry 'P' is a short explanation of how to print PostScript\n";
ostrm << "files.\n\n";

ostrm << "  I\n\n";

ostrm << "Menu entry 'I' is this summary of information about HDL_ANT.\n\n";

ostrm << "  U\n\n";

ostrm << "Menu entry 'U' allows you to select dimensions in either\n" 
      << "millimeters or inches.  HDL_ANT defaults to millimeters.\n\n";

ostrm << "  O\n\n";

ostrm << "Menu entry 'O' is a new feature for version 2.0 which does\n"
      << "calculations for oval-shaped offset-fed parabolic reflectors.\n"
      << "This routine uses a curve-fitting algorithm to find the focal\n"
      << "point and tilt angle for aiming the dish.  Required input data\n"
      << "are the dimensions of the large and small axis of the oval, and\n"
      << "the depth and location of the deepest point in the reflector,\n"
      << "measured along a straightedge placed across the rim on the large\n"
      << "axis.\n\n"
      << "For offset reflectors that are not oval shaped, please read my\n"
      << "article in QEX, December, 1995 on offset dishes for suggestions.\n\n";
ostrm << "There is an option to design a rectangular feedhorn as descibed\n"
      << "in Menu entry 'F'.\n\n";      

ostrm << "  F\n\n";

ostrm << "Menu entry 'F' is a new feature for version 2.0 which will\n"
      << "design a rectangular feedhorn for a dish with a specified f/D\n"
      << "using a straightline approximation to the G3RPE curves.  The\n"
      << "approximation is accurate to about 2% for f/D < 0.8, and about\n"
      << "6% for larger f/D. It will then create a PostScript\n";
ostrm << "template file which may be used to print a paper template for\n";
ostrm << "horn construction as described for Menu Entry 'H'.  \n\n";
ostrm << "The feedhorn dimensions generated by the approximation do not\n";
ostrm << "necessarily have equal E- and H-plane phase centers, so you may\n";
ostrm << "need to adjust the axial length of the horn to find a length that\n";
ostrm << "matches the phase centers to within 0.1 wavelengths without \n";
ostrm << "reporting any errors in the phase center routines.\n\n";
ostrm << "Also, the feedhorn dimensions assume a reflector which has\n";
ostrm << "symmetrical illumination angles in both planes.  For reflectors\n";
ostrm << "requiring assymetrical illumination, run this option once for each\n";
ostrm << "illumination angle ( or equivalent f/D ), note the dimensions, \n";
ostrm << "and adjust the horn dimensions to use the appropriate one in each \n";
ostrm << "plane.  Make sure the E-plane matches the normal polarization,\n";
ostrm << "i.e., E-plane horizontal for horizontal polarization, or E-plane\n";
ostrm << "vertical for vertical polarization.\n\n";



ostrm << "  N\n\n";

ostrm << "Menu entry 'N' is a new feature for version 2.0 which calculates\n"
      << "receiver noise figure by comparing noise received from \n"
      << "cold sky and warm ground.\n\n";


ostrm << "  C\n\n";

ostrm << "Menu entry 'C' is a new feature for Version 3.0 used to design and\n";
ostrm << "calculate the gain for a conical horn.  Simple conical horns are not\n";
ostrm << "recommended as dish feeds because the E- and H-plane phase centers are\n";
ostrm << "not identical; 'scalar horns' have corrugated walls to eliminate the currents\n";
ostrm << "which cause the differences.\n\n"; 
ostrm << "The W2IMU dual-mode feed horn has a flared section which generates the second\n";
ostrm << "mode.  The flare angle controls the relative amplitudes of the two modes.\n";  
ostrm << "This option can make a template for the flare section of a W2IMU feed by\n"; 
ostrm << "specifying the input and output (aperture) diameters and the desired \n"; 
ostrm << "flare angle.\n\n";
ostrm << "It can also create a PostScript template.  The PostScript template\n";
ostrm << "file may be used to print a paper template for horn construction.  The\n";
ostrm << "paper template is attached to a sheet of copper or brass which is cut\n";
ostrm << "and rolled up so the straight edges on the templatemeet, then soldered\n";
ostrm << "along the straight edges and soldered to a circular waveguide.  For large\n";
ostrm << "whose template does not fit on a sheet of paper, generate a template for a\n";
ostrm << "much higher frequency, then use the dimensions displayed for the desired\n";
ostrm << "frequency to construct a large template similar to the higher frequency one\n\n";
ostrm << "See menu entry 'P' for more details on printing a "
      << "PostScript file.\n\n";


ostrm << "  G\n\n";

ostrm << "Menu entry 'G' is a new feature for Version 3.0 used to design an optimal\n";
ostrm << "conical horn for a specified gain.  An optimum horn achieves the desired gain \n";
ostrm << "with a minimum amount of material.  Efficiency is about 52%.\n";
ostrm << "It can also create a PostScript template.\n\n";


ostrm << "  W\n\n";

ostrm << "Menu entry 'W' is a new feature for Version 3.0 used to design W2IMU\n";
ostrm << "dual-mode feedhorns with a range of apertures for different f/D.\n\n";
ostrm << "The W2IMU dual-mode feedhorn has a flared section which generates the second\n";
ostrm << "mode.  The flare angle controls the relative amplitudes of the two modes.\n";  
ostrm << "This option can make a PostScript template for the flare section of a W2IMU\n";
ostrm << "feed like the conical horn template above.\n\n";
 

ostrm << "  Q\n\n";

ostrm << "'Q' for Quit ends the program.\n\n\n";


ostrm << "The source file, HDLANT3.CPP, was compiled using Borland C++ \n";
ostrm << "version 4.52.  Any part of it may be modified or used as part\n";
ostrm << "of another program by any amateur radio operator, provided\n";
ostrm << "that credit is given and provided there is no charge for\n";
ostrm << "its use.\n\n";

ostrm << "Send problems, suggestions, and comments to Paul Wade, N1BWT.\n";
ostrm << "Expect support commensurate with the cost of the program!\n";
}

void Antenna::post_print(ostream& ostrm)
{
ostrm << "\n            PRINTING POSTSCRIPT[tm] FILES\n\n";
        
ostrm << "      The easiest way to print PostScript files is with a \n";
ostrm << "      PostScript compatible laser printer.  These have become\n";
ostrm << "      more affordable and are becoming more common; for\n";
ostrm << "      instance, the public library in my small town has one\n";
ostrm << "      attached to a public-access computer.   However, they are\n";
ostrm << "      still roughly twice as expensive as the dot-matrix\n";
ostrm << "      printers that most of us use with our personal computers.\n";
ostrm << "      \n";
ostrm << "      An alternative to a laser printer is software that\n";
ostrm << "      interprets PostScript language commands for display on a\n";
ostrm << "      computer VGA display or a dot-matrix printer.  I know of\n";
ostrm << "      several versions of this type of software:  GoScript, a\n";
ostrm << "      commercial product, Ultrascript, a commercial product,\n";
ostrm << "      Freedom of Press , a commercial product, and Ghostscript,\n";
ostrm << "      [Copyright (C) 1990, 1992 Aladdin Enterprises.  All\n";
ostrm << "      rights reserved.  Distributed by Free Software\n";
ostrm << "      Foundation, Inc.], which is freeware.  \n";
ostrm << "      \n";
ostrm << "      I have only used Ghostscript, version 2.5 and later.  While 286,\n";
ostrm << "      386, and windows versions are available, the 286 version\n";
ostrm << "      seems to work most reliably even on a 386 or 486 PC.  It\n";
ostrm << "      uses Unix style command strings which are difficult to\n";
ostrm << "      remember, so I've included two BAT files to help:\n";
ostrm << "      GS_VIEW.BAT for viewing on a screen, and GS_PRINT.BAT for\n";
ostrm << "      printing on an Epson dot-matrix printers.  For other\n";
ostrm << "      brands of printer, the command will have to be changed\n";
ostrm << "      appropriately, which will require reading of the\n";
ostrm << "      documentation.  Type GS_VIEW <filename.ps> or GS_PRINT\n";
ostrm << "      <filename.ps> to use them.  Be sure to type QUIT when you\n";
ostrm << "      are through or your PC may be left in an unhappy state\n";
ostrm << "      requiring rebooting.  \n\n";
ostrm << "      The newer versions, currenty 5.10, and Ghostview, work much\n";
ostrm << "      better under Windows 95 and NT.  They may be downloaded from\n";
ostrm << "          http://www.cs.wisc.edu/~ghost/index.html\n\n";
ostrm << "      I've also included a sample PostScript file, SQUARE.PS,\n";
ostrm << "      which draws a four inch square to make sure that\n";
ostrm << "      templates will be drawn to scale, and a sample horn\n";
ostrm << "      template, HORN18.PS, to get you started.  If the\n";
ostrm << "      dimensions of the printed square are slightly off, you\n";
ostrm << "      can correct them.  Each template has a line near the\n";
ostrm << "      beginning of the file:\n";
ostrm << "      \n";
ostrm << "              1.0 1.0 scale\n";
ostrm << "              \n";
ostrm << "      the first number is the scale factor in the x\n";
ostrm << "      (horizontal) direction, and the second is the scale\n";
ostrm << "      factor in the y (vertical) direction.  Edit the SQUARE.PS\n";
ostrm << "      file with an editor to change these numbers slightly;\n";
ostrm << "      when you find a combination that prints a square exactly\n";
ostrm << "      four inches on a side, then you have compensated for your\n";
ostrm << "      printer.  Edit these same numbers into any template to be\n";
ostrm << "      printed on the same printer and the dimensions will come\n";
ostrm << "      out right.\n";
ostrm << "      \n";
ostrm << "      The Ghostscript files are available on many bulletin\n";
ostrm << "      boards and Internet locations.  They are in ZIP format,\n";
ostrm << "      so they must me downloaded, unZIPped, and installed\n";
ostrm << "      according to the README documentation.\n";
ostrm << "      \n";
ostrm << "      I have not used any of the commercial products, but I\n";
ostrm << "      would expect a commercial product to be much easier to\n";
ostrm << "      install and use than freeware or shareware.   \n";
ostrm << "      \n";
ostrm << "      The batch files are as follows:\n\n";
ostrm << "GS_VIEW.BAT\n\n";
ostrm << "   gs %1\n\n";
ostrm << "GS_PRINT.BAT\n\n";
ostrm << "   gs -sDEVICE=epson -r60x60 %1\n";
}

void Antenna::PANFI_corr()
{
// correction for PANFI readings to Antenna Gain

    float Tex_dB;  // Excess noise calibration

    cout << "\nPANFI calibration setting - Excess noise in dB: " ;
    cout.flush();
    cin >> Tex_dB;

    float std_db;
	 cout << "\nGain of standard gain antenna: " ;
    cout.flush();
    cin >> std_db;
    cout << "\n\n";

    double nf = 0.0;   // indicated noise figure in dB

    cout << "Enter a negative Noise Figure to return to Main Menu\n\n\n";

    while (nf >= 0.0)
    {
        double std_nf;
        cout << "\nIndicated Noise Figure for Standard gain antenna: " ;
	cout.flush();
	cin >> std_nf ;

        double ratio = pow(10.0,(0.1 * (Tex_dB - std_nf)));
        double Y_std = 10.0 * log10( 1.0 + ratio);
        cout << setprecision(3) 
	     << "\n            Y factor = " << Y_std <<  " dB\n\n";

        cout << "\nIndicated Noise Figure for antenna under test: " ;
	cout.flush();
	cin >> nf ;

        ratio = pow(10.0,(0.1 * (Tex_dB - nf)));
        double Y_db = 10.0 * log10( 1.0 + ratio);

        cout << setprecision(3) 
	     << "\n           Y factor = " << Y_db <<  " dB\n\n";


	double G_db = Y_db - Y_std + std_db;
	cout << setprecision(3)
	     << "      Corrected gain = " << G_db <<  " dBi\n\n";

	float dia;
	cout << "Aperture diameter in " << units << ": " ;
	cout.flush();
	cin >> dia ;
        dia *= metric;

        double g_ratio = pow(10.0,(0.1 * G_db));

        directivity = pi * pi * dia * dia /( wavelength * wavelength);

//cout << "Directivity = " << directivity;

        efficiency = g_ratio / directivity;
                
        cout << setprecision(2) 
             << "\n\n      Aperture efficiency = " << (efficiency * 100) 
             <<  " %\n\n\n";        
    }
}


void Antenna::range_calc()
{
// calculations for Antenna Range design
// this routine returns feet or meters so has hard constants

    cout << "\nLargest aperture diameter to be measured, in "
         << units << ": ";
    cout.flush();
    cin >> aperture;
    
    aperture *= metric;

    rayleigh_dist = 2.0 * aperture * aperture / wavelength;

    float big_u;
    char *big_units = "xxxxxx";

    if (metric == 1.0)
    {
        big_u = 1000.0;
        big_units = "meters";
    }
    else
    {
        big_u = 304.8;
        big_units = "feet  ";
    }
        
     cout << "\n\nRayleigh distance (minimum range length) = "
          << setprecision(3) << (rayleigh_dist / big_u) << " "
          << big_units << "\n\n";

     cout << "Suggested measurement height = "
          << setprecision(3) << (aperture * 4.0 / big_u) << " "
          << big_units << "\n\n";

    double range_length;
    cout << "Enter desired range length in " << big_units << ": ";
    cout.flush();
    cin  >> range_length;
    
    range_length *= big_u;      // mm.
    
    if (range_length < rayleigh_dist)
        cout << "\n\nWARNING - range too short for "
             << "accurate gain measurement\n\n";

        double meas_height;
        cout << "\n\nEnter desired measurement height in "
             << big_units << ": ";
        cout.flush();
        cin  >> meas_height;
             
        meas_height *= big_u;      // mm.
    
    if (meas_height < (3.2 * aperture))
        cout << "\n\nWARNING - measurement height insufficient for "
             << "accurate gain measurement\n\n";

    double source_height = wavelength * range_length / (4.0 * meas_height);
    
    cout << "\n\nHeight of source antenna should be "
         << setprecision(4) << (source_height / metric) << " "
         << units << " \n\n";
}


void Antenna::sun_gnd_NF()
{
// calculate NF from sun and ground noise as hot and cold sources

    double Tsky;    
    cout << "\nEnter temperature of cold sky in K: " ;
    cout.flush();
    cin >> Tsky;

    float Tground;
    if (metric > 1.0)
    {
        cout << "\nEnter temperature of ground in degrees Fahrenheit: " ;
        cout.flush();
        cin >> Tground;
        Tground = 273.0 + ((Tground - 32.0) / 1.8);
    }
    else
    {
        cout << "\nEnter temperature of ground in K: " ;
        cout.flush();
        cin >> Tground;
    }
    cout << "\n\n";

    double Te;          // receiver noise figure
    double nf_db;

    double Y_db = 0.0;  // measured Y-factor in dB
    double Y_factor ;        

    cout << "Enter a negative Y-factor to return to Main Menu\n\n\n";

    cout << "\nEnter Y-factor (difference between sky and ground) in dB: ";
    cout.flush();
    cin >> Y_db;


	 while (Y_db > 0.0)
    {


        Y_factor = pow(10.0,(0.1 * Y_db));

        Te = (Tground - Y_factor * Tsky) / (Y_factor -1.0);
        
        nf_db = 10.0 * log10((Te / 290.0) + 1.0); 

        cout << setprecision(4) 
		  << "\n    Receiver Noise temperature = " << Te <<  " K\n\n";

        cout << setprecision(3) 
	     << "\n    Receiver Noise figure = " << nf_db <<  " dB\n\n";

        cout << "\nEnter Y-factor (difference between sky and ground) in dB: ";
        cout.flush();
	cin >> Y_db;

    }
}


//




Dish::Dish() : Antenna()
{               // constructor 
    freq = 0.0;                 
    diameter = 0.0;             
    depth = 0.0;                
    focal_length = 0.0;         
    f_over_D = 0.0;             
    feedangle = 0.0;            
    feedang_deg = 0.0;          
    R_edge = 0.0;                    
    space_attn = 0.0;           
    desired_taper = 0.0;        
    BW3 = 0.0;                  
    simple_horn_diameter = 0.0; 
    wavelength = 0.0;           
    dish_gain = 0.0;                 
    
}

void Dish::d_init()
{
    cout << "\nDiameter of dish in " << units << ": " ;
    cout.flush();
    cin >> diameter ;
    diameter *= metric;   //mm

    char mode = 'n';
    cout << "\nDo you know the f/D ratio [Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
    {
        cout << " \n Enter f/D ratio: ";
	cout.flush();
	cin >> f_over_D;

	focal_length = f_over_D * diameter ;
    }
    else
    {
	cout << " \n Enter Depth of dish in " << units << ": " ;
	cout.flush();
	cin >> depth;
        depth *= metric;      //mm

	focal_length = (diameter * diameter) / ( 16.0 * depth);
	f_over_D = focal_length / diameter ;

	cout << "\n\n     f/D = " << setprecision(2) << f_over_D << "\n" ;
    }

    cout << "\nFocal length = "
         << setprecision(4) <<  (focal_length / metric) 
         << " " << units << endl;

}

void Dish::illumination()
{
	feedangle = 2 * atan2(1.0,((2.0 * f_over_D) - (1.0/(8.0 * f_over_D))));
	feedang_deg = crad * feedangle ;   // degrees conversion

		// R_edge = distance from focal point to edge

	R_edge = 2.0 * focal_length / ( 1 + cos(feedangle/2.0));

		// Space_attn is additional path loss to edge of dish
	double Space_attn = (20.0 * log10(R_edge / focal_length));

		// Desired_taper to achieve 10 dB actual edge taper
	double Desired_taper = 10.0 - Space_attn;  // dB

	BW3 = feedangle * sqrt( 3.0 / Desired_taper) ;

	double Simple_horn_diameter = 66.0 / (BW3 * crad) ; // wavelengths

	cout << "\n\n  Illumination angle for feed = "
	     << setprecision(3) <<  feedang_deg << " degrees";

	cout << "\n  Space attenuation = "
	     << setprecision(2) << Space_attn << " dB ";
	cout << "\n  Desired taper = "
	     << setprecision(2) << Desired_taper << " db "
	     << "for 10 dB edge illumination";

	cout << "\n\nA simple feed horn would have a diameter of "
	     << setprecision(2) << Simple_horn_diameter << " wavelengths";

	cout << "\n   for a 3 dB beamwidth of "
	     << setprecision(3) << (BW3 * crad) << " degrees\n";


//        Write_PS(diameter, focal_length);

}

void Dish::calc_gain()
{
    efficiency = 0.5;     // assume 50% efficiency

    double radius = 0.5 * diameter;

    aperture = pi * radius * radius;

    dish_gain = efficiency * aperture * 4.0 * pi / (wavelength * wavelength);

    dish_gain = 10.0 * log10(dish_gain);

    cout << "\nGain at 50% efficiency = " << setprecision(3) << dish_gain
	 << " dBi \n";
}


void Dish::PS_template()
{                      // PostScript template on one page

    char descriptor[LINESIZE] = " ";
    char outname[LINESIZE];

    cin.ignore(LINESIZE,'\n');
    cout << " Dish description line: ";
    cout.flush();
    cin.get(descriptor,LINESIZE,'\n');

    cout << "File name for dish template (should be .PS ): ";
    cout.flush();
    cin >> outname ;

    ofstream outfil(outname);

    if (!outfil)
    {
	cerr << "Cannot open output file for output";
    }

// header

    outfil << "%! PostScript\n";

    outfil << "% template for " << (diameter/metric) 
           << " " << units << " parabolic dish\n";
    outfil << "% with f/d = " << f_over_D << " and focal length = "
           << (focal_length/metric) << " " << units << "\n";
    
    outfil << "% generated by HDLANT3b by N1BWT 1994,1995,1996,1998 \n";
    outfil << "%\n";
    outfil << "%" << descriptor;
    outfil << "%\n";
    outfil << "% Print on PostScript printer\n";
    outfil << "% cut along the curve,\n";
    outfil << "% and use it as a template for the dish.\n\n\n";
    
    outfil << "%\n";
    outfil << "/in { 72 mul } def\n";
    outfil << "/mm { 2.834646 mul } def\n";

    outfil << "%\n";
    outfil << "% 100% scaling factors - change for printer correction\n";
    outfil << "1.0 1.0 scale \n";
    outfil << "%\n";

outfil << "% DISH **********************************************\n\n";

//    Point offset =  Point(50.0,(100.0 - (diameter/4.0))) ;
    Point offset =  Point(50.0, 260.0);

    outfil << offset.x() << " mm " << offset.y() << " mm translate" << endl;

    outfil << "% DISH\n";
outfil << "gsave\n";

// and dish outline 

// NOTE: I'm doing this directly in picas, so can't use PS_lineto
        
    int prad = int(2.834636 * diameter / 2.0);         // radius in picas 
    double pa = 4.0 * focal_length * 2.834636;       // 4 * f in picas 
        
    outfil << "newpath\n";

    outfil << PS_moveto() << endl;
        
    double i_d;    
    double curvature;
    for ( int i = 0; i <= prad; i++)
    {
        i_d = (double)i;
        curvature = i_d * i_d / pa ;
        outfil << curvature << " " << (-i) << " lineto\n";   // draw it vertically
    }
    outfil << "stroke \n\n";
            
// and draw a box around it 

    outfil << "newpath\n";
    outfil << curvature << " " << (-prad) << " moveto" << endl;
    outfil << curvature << " 0 lineto " << endl;
    outfil << "0 0 lineto " << endl;
    outfil << "0 " << (-prad) << " lineto" << endl;
    outfil << curvature << " " << (-prad) << " lineto" << endl;
    outfil << "stroke\n";    

// Text
    outfil << "/Helvetica-Bold findfont\n";
    outfil << "14 scalefont\n";
    outfil << "setfont\n";
// position title

    outfil << "-25 mm -25 mm moveto\n";
    outfil << "(Template for " << diameter << "mm dish with f/d = " 
           << f_over_D << " ) show\n";
    outfil << "-25 mm  -35 mm moveto\n";
    outfil << " (N1BWT 1994,1998) show \n";


    outfil << "% END DISH **********************************************\n";
    outfil << "grestore\n";

    outfil << "showpage\n";
    outfil << "%\n";

    outfil.close();
//cerr << "outfile closed";
}
 


//

OffsetDish::OffsetDish() : Antenna()
{               // constructor 
    freq = 0.0;                 
    small_diameter = 0.0;             
    large_diameter = 0.0;             
    odepth = 0.0;
    odepth_position = 0.0;                
    tilt_angle = 0.0;
    focal_length = 0.0;         
    equiv_f_over_D = 0.0;
    f_over_D = 0.0;             
    small_feedangle = 0.0;            
    small_feedang_deg = 0.0;          
    large_feedangle = 0.0;            
    large_feedang_deg = 0.0;          
    R_edge = 0.0;                    
    R_aim = 0.0;
    space_attn = 0.0;           
    desired_taper = 0.0;        
    BW3 = 0.0;                  
    simple_horn_diameter = 0.0; 
    wavelength = 0.0;           
    dish_gain = 0.0;                 
    
}

void Rotate_point(double xa, double ya, double angle, double &xr, double &yr)
    { 
    xr = ya * cos(angle) - xa * sin(angle);
    yr = ya * sin(angle) + xa * cos(angle);
    }


void OffsetDish::offset_init2()
{
    bad = 1 ;
    while (bad >= 1)
        {    
        cout << "\nPLEASE ENTER:\n\nDiameter of large axis of dish in" << units << ": " ;
        cout.flush();
        cin >> large_diameter ;
        large_diameter *= metric;   //mm

	cout << "\nDiameter of small axis of dish in" << units << ": " ;
        cout.flush();
        cin >> small_diameter ;
        small_diameter *= metric;   //mm

	if (large_diameter < small_diameter)
            {
            cerr << " WARNING - Large diameter smaller than small diameter\n\n";
            cout << " Enter 0 to continue, 1 to try again: ";
            cout.flush();
            cin >> bad;
            if (bad > 3) break;
            }
        else bad = 0;
        }

    cout << "\nDepth of dish at deepest point in" << units << ": " ;
    cout.flush();
    cin >> odepth;
    odepth *= metric;   //mm

    cout << "\nDistance of deepest point from bottom edge along large axis  in" << units << ": " ;
    cout.flush();
    cin >> odepth_position ;
	 odepth_position *= metric;   //mm

} // end of OffsetDish::offset_init2()


void OffsetDish::three_points()
{
// new v3: bottom edge of offset dish must be at center of full parabola

//******** start near tilt angle
    double est_tilt_angle = asin(small_diameter / large_diameter);

    double xb;
    double yb;
    double xd;
    double yd;
    double xt;
    double yt;
    double Den;
    double D1;
    double D2;

// test header for loop
//    cout << "Tilt_angle  focal   xb   yb   bottom    top string" << "\n\n";
    
//    for (double xta = -0.05; xta <= 0.05; xta += 0.005)

// now let's search for minimum yb
    int searching = 1;
    int tries = 0;
    double tilt_inc = 0.05;
    tilt_angle = 0.9 * est_tilt_angle;
    while (searching >= 1)
        {
        tries++;
        //tilt_angle = est_tilt_angle + xta;
    
// rotate coordinates by tilt angle    
// bottom
        //    double xb = 0.0;
        //    double yb = 0.0;

// deepest point
        xd = odepth_position * cos(tilt_angle) - odepth * sin(tilt_angle);
        yd = odepth_position * sin(tilt_angle) + odepth * cos(tilt_angle);
//debug// cout << setprecision(5) << "\n          rotated deep point = " << xd << " , " << yd ;

// top
        xt = large_diameter * cos(tilt_angle);
        //    yt = small_diameter; // = large_diameter * sin(tilt_angle);
        // not exactly a circular projection!
        yt = large_diameter * sin(tilt_angle);
//debug// cout << "\n          rotated top point = " << xt << " , " << yt ;

// curve fitting

// determinants
	Den = 8.0 * xd * yt - 8.0 * xt * yd;
        D1 = yd * yd * 2.0 * yt - yt * yt * 2.0 * yd;
        D2 = yt * yt * 4.0 * xd - yd * yd * 4.0 * xt;
//debug// cout << "\n          D = " << Den;    
//debug// cout << "\n          D1 = " << D1;    
//debug// cout << "\n          D2 = " << D2;    

	 focal_length = D1 / Den;

// bottom offset from vertex
	 yb = - D2 / Den;
	 xb = yb * yb / (4.0 * focal_length);


// test print while looping
//         cout << (tilt_angle * crad) << "   "
//             << (focal_length / metric) << "    " 
//             << (xb / metric) << "     "
//             << (yb / metric) << "     "
//             << (bottom_string / metric) << "     "
//             << (top_string / metric) << "     "
//             << "\n";             

        if (tries > 500)        // don't loop forever
            {
            cerr << "\n\n\nCurve fitting for offset reflector failed - send input data to N1BWT\n";
            break;
            }
            
// now the search test
        if (yb > 0.01) tilt_angle += tilt_inc;
        else if (yb < -0.01) 
            {
            tilt_angle -= tilt_inc;
            tilt_inc *= 0.5;
            }
        else searching = 0;     // bottom edge at center
        }    // end of search loop

        xbot = xb;
        ybot = yb;
        xtop = xt;
        ytop = yt;

        f_over_D = focal_length / (2.0 * ( ytop + ybot)) ;

} // end of OffsetDish::three_points()

void OffsetDish::display_results()
{

// display some results

        cout << "\nFocal length = "
		<< setprecision(4) <<  (focal_length / metric)
		<< " " << units << endl;

        cout << "\nThis offset reflector is a section of a full parabola with a diameter \nof "
		<< setprecision(5) << (2.0 * ( ytop + ybot) / metric) << " " << units;
                
        if (ybot < 1.0)
            cout << "whose vertex is at the bottom edge of the offset reflector.\n" 
                 << setprecision(2)
		 << "The full parabola has an f/D = " << f_over_D << ", which determines "
		 << "criticality of focal \nlength.";
        else
            cout << "whose vertex is " << setprecision(4) << (xbot / metric) << " " << units
		 << "behind and "
		 << (ybot / metric) << " " << units << "below"
		 << "\nthe bottom edge of the offset reflector."
                 << setprecision(2)
		 << "  The full parabola has \nan f/D = " << f_over_D << ", which determines "
		 << "criticality of focal length.";


// string length

	 double bottom_angle = atan2(ybot,(focal_length - xbot));
	 double bottom_string = (focal_length - xbot) / cos(bottom_angle);

	 double top_angle = atan2(ytop,(focal_length - xtop));
	 double top_string = ytop / sin(top_angle);

	 double aim_angle = bottom_angle + 0.5 * (top_angle - bottom_angle);
	 R_aim = 2.0 * focal_length / (1.0 + cos(aim_angle));

	 large_feedangle = top_angle - bottom_angle;

//debug// cout << "\nbottom angle = " << setprecision(4) << (bottom_angle*crad );
//debug// cout << "  top angle = " << (top_angle*crad );
//debug// cout << "  aim angle = " << (aim_angle*crad );
//debug// cout << "  aiming distance = " << R_aim << units;


// this is a reasonable approximation
        small_feedangle = 2.0 * atan2((small_diameter / 2.0),(R_aim - odepth));

        cout << "\n\nThe focal point of the dish is "
		<< setprecision(5) << (bottom_string / metric) << " " << units
		<< "from the bottom edge of the \nreflector and "
		<< setprecision(5) << (top_string / metric) << " " << units
		<< "from the top edge of the reflector.\n";

        cout << " \nFor operation with the main beam on the horizon with the feed at the bottom, "
		<< "\nthe dish must be tilted forward"
		<< " so that the large axis is "
		<< setprecision(3) << (tilt_angle * crad) << " degrees"
		<< " \nabove horizontal." ;


//debug// pause after test print for looping
//    char mode = 'n';
//    cout << "Hit y to continue  ";
//    cout.flush();
//    cin >> mode ;
//    mode = toupper(mode);

//    if (mode == 'Y');

}   // end of OffsetDish::display_results()



void OffsetDish::curve_fit()
// fit parabolic curve to measured set of points, 
// searching thru f/D = 0.2 to 0.5 and up to 100% offset from apex
{
    int i;
    int off_num;
    int last_error = 0;
    int wrong_way = 0;
    
    double xin[max_pts];
    double yin[max_pts];
    double xoff[max_pts];
    double yoff[max_pts];
    double xcalc;
    double error;
    double min_error = 1000000.0;
    double min_f;
    double min_tilt_angle;
    double x_offset;
    double y_offset;
    double min_y_offset;

    
    cout << "\nNumber of additional points for curve fitting: " ;
    cout.flush();
    cin >> off_num;

    off_num += 2;
    
    xin[0] = 0.0;
    yin[0] = 0.0;
    xin[1] = odepth;            // deepest point
    yin[1] = odepth_position;    
    xin[off_num] = 0.0;
    yin[off_num] = large_diameter;

    for (i = 2; i <= (off_num - 1); i++)      //read other points - arbitrary order
        {
        cout << "\nDepth of dish at next point in" << units << ": " ;
        cout.flush();
        cin >> xin[i];
        xin[i] *= metric;   //mm

        cout << "\nDistance of next point from bottom edge along large axis  in" << units << ": " ;
        cout.flush();
        cin >> yin[i] ;
        yin[i] *= metric;   //mm
        }

// now search the space for a minimum

        
// test header for loop
// cout << "Tilt_angle  focal   error  min-error" << "\n\n";

//    tilt_angle = 1.0;   // just to get past first test

    for (focal_length = 0.4 * large_diameter; focal_length <= large_diameter; 
             focal_length += 0.1)
        {        
        tilt_angle = 1.0;   // just to get past first test
        wrong_way = 0;
        for (y_offset = 0; (y_offset <= large_diameter && tilt_angle > 0.1 && wrong_way <= 5);
                y_offset++)
            {
            x_offset = y_offset * y_offset / (4.0 * focal_length);
            
                    // solve for top of dish on parabolic curve
            xoff[off_num] = sqrt(4.0 * focal_length * focal_length + large_diameter * large_diameter);
            xoff[off_num] += x_offset - (2.0 * focal_length);
            yoff[off_num] = y_offset + sqrt(4.0 * (xoff[off_num] - x_offset) * focal_length);

            tilt_angle = acos(xoff[off_num] / large_diameter);         // from horizontal

            error = 0;
            for (int i = 0; i < off_num; i++)
                {
                Rotate_point((xin[i] - x_offset), (yin[i] - y_offset), tilt_angle, xoff[i], yoff[i]);
                
                xcalc = x_offset + ((yoff[i] - y_offset) * (yoff[i] - y_offset) / (4.0 * focal_length));
                
                error += (xcalc - xoff[i]) * (xcalc - xoff[i]);         // min error is best least-squares fit
                }

            if (error > last_error) 
                wrong_way++;
            else wrong_way = 0;
                
            if (error < min_error)
                {
                min_error = error;
                min_f = focal_length;
                min_y_offset = y_offset;
                min_tilt_angle = tilt_angle;
                }
// test print while looping

//        cout << (tilt_angle * crad) << "   "
//             << (focal_length / metric) << "    " 
//             << error << "     "
//             << min_error << "     "
//             << "\n";             
//        delay(5);        
            }
        cout << " Curve fitting, error = "
             << error << ",  minimum error = "
             << min_error 
             << "\n";             
        }

// and output the best fit

    focal_length = min_f;
    tilt_angle = min_tilt_angle;
    ybot = min_y_offset;
    xbot = min_y_offset * min_y_offset / (4.0 * focal_length);
    Rotate_point(xin[off_num], yin[off_num], tilt_angle, xtop, ytop);
    f_over_D = focal_length / (2.0 * ( ytop + ybot)) ;

    cout << "Average surface error for " << (off_num - 1) << " points on surface = "
         << (sqrt(min_error / (off_num - 1))) << units ;
        
}   // end of OffsetDish::curve_fit()



void OffsetDish::offset_illumination()
{
//	feedangle = 2 * atan2(1.0,((2.0 * f_over_D) - (1.0/(8.0 * f_over_D))));

	large_feedang_deg = crad * large_feedangle ;   // degrees conversion
	small_feedang_deg = crad * small_feedangle ;   // degrees conversion

	cout << "\n\nIllumination angle for feed = "
		  << setprecision(3) <<  large_feedang_deg
                  << " degrees on the large axis and "
		  << setprecision(3) <<  small_feedang_deg 
		  << " degrees \non the small axis.  ";


		// R_edge = distance from focal point to edge

// some reasonable approximations for feeds
	equiv_f_over_D = R_aim / small_diameter;

	R_edge = 2.0 * R_aim/ ( 1 + cos(small_feedangle/2.0));

		// Space_attn is additional path loss to edge of dish
	double Space_attn = (20.0 * log10(R_edge / R_aim));

		// Desired_taper to achieve 10 dB actual edge taper
	double Desired_taper = 10.0 - Space_attn;  // dB

	BW3 = small_feedangle * sqrt( 3.0 / Desired_taper) ;

	cout << "A feedhorn with a 3 dB beamwidth of "
		  << setprecision(3) << (BW3 * crad) << " degrees is \nneeded,"
		  << "equivalent to the feed for a conventional dish with f/D = "
		  << setprecision(2) << equiv_f_over_D ;

//	double Simple_horn_diameter = 66.0 / (BW3 * crad) ; // wavelengths


//debug//	cout << "\n  Space attenuation = "
//debug//		  << setprecision(2) << Space_attn << " dB ";
//debug//	cout << "\n  Desired taper = "
//debug//		  << setprecision(2) << Desired_taper << " db "
//debug//		  << "for 10 dB edge illumination";

//	cout << "\n\nA simple feed horn would have a diameter of "
//	     << setprecision(2) << Simple_horn_diameter << " wavelengths";

        fod = equiv_f_over_D;

// straight line approximation to G3RPE curves - within 2% for f/D < 0.8
// for small axis only

    H_aperture = wavelength * ((equiv_f_over_D * 2.864) - 0.575);
        
    E_aperture = wavelength * ((equiv_f_over_D * 1.727) - 0.129);

	 axial_length = H_aperture; //any rough guess - correct for phase centers later

}

void OffsetDish::offset_calc_gain()
{
    efficiency = 0.5;     // assume 50% efficiency

    double radius = 0.5 * small_diameter;

    aperture = pi * radius * radius;

    dish_gain = efficiency * aperture * 4.0 * pi / (wavelength * wavelength);

    dish_gain = 10.0 * log10(dish_gain);

    cout << "\n\nGain at 50% efficiency = " << setprecision(3) << dish_gain
	 << " dBi ";

    efficiency = 0.6;     // recalculate for 60% efficiency
    dish_gain = efficiency * aperture * 4.0 * pi / (wavelength * wavelength);
    dish_gain = 10.0 * log10(dish_gain);

    cout << "\nIf you do really well, you might get 60% efficiency for a gain = "
			<< setprecision(3) << dish_gain << " dBi ";
    cout << "\n\nTo design a feedhorn, use f/D = "
         << setprecision(2) << equiv_f_over_D 
         << " in Menu option F";

}



//





Horn::Horn() : Antenna()
{               // constructor 
    freq = 0;        
    H_wg = 0;        
    E_wg = 0;        
    wavelength = 0;  
    horn_gain = 0;        
    axial_length = 0;
    H_aperture = 0;
    E_aperture = 0;   
    E_phase_center = 0;
    H_phase_center = 0;
    simplegain = 0;        
    E_flare_angle = 0;
    E_side = 0;
    E_ang = 0;
    H_flare_angle = 0;
    H_side = 0;
    H_ang = 0;
}
            

void Antenna::get_freq()
{                   // reads initial data
    cout << "\n" << "Frequency in MHz: " ;
    cout.flush();
    cin >> freq ;

    wavelength = c / (1000.0 * freq);
}

void Antenna::get_wg()
{
    cout << "         ____________     \n";
    cout << "        |     E      |   waveguide  \n";
    cout << "        |     ^ -->H |             Hint: for WR-90\n";
    cout << "        |     |      |               H = 22.86 mm. = 0.9 in.,\n";
    cout << "         ------------                E = 10.16 mm. = 0.4 in. \n\n";

    bad = 1 ;
    while (bad >= 1)
    {    
        cout << "\n" << "Enter H-plane inside dimension of waveguide in "
             << units << ": ";
	cout.flush();
	cin >> H_wg;
        H_wg *= metric;         //mm

        cout << "\n" << "Enter E-plane inside dimension of waveguide in "
             << units << ": ";
	cout.flush();
	cin >> E_wg;
        E_wg *= metric;         //mm
    
	if (wavelength < (0.98 * H_wg) || wavelength > ( 2.0 * H_wg ))
                        /* slight fudge to get edges */
        {
            cout << " ERROR - frequency out of waveguide range \n";
            bad++ ;
            if (bad > 3) break;
        }
        else bad = 0;
    }
}

void Antenna::check_aperture()
{
    if ( H_wg > H_aperture)
    {
        cout << "\n\n *** ERROR - waveguide H dimension larger than horn"
             << " aperture \n\n"
             << " *** Probably can't use a rectangular feedhorn for this"
             << " f/D and waveguide.\n";
        bad = 4;   
    }        
}     


void Antenna::horn_dimensions()
{                               // input dimensions of a horn
        
    cout << "\n" << "ENTER DESIRED PHYSICAL DIMENSIONS OF HORN: ";
    

    cout << "\n" << "Enter axial length of horn in "
         << units << ": ";
    cout.flush();
    cin >> axial_length;
    axial_length *= metric;
    
    cout << "\n" << "Enter H-plane aperture of horn in "
         << units << ": ";
    cout.flush();
    cin >> H_aperture;
    H_aperture *= metric;
    
    cout << "\n" << "Enter E-plane aperture of horn in "
         << units << ": ";
    cout.flush();
    cin >> E_aperture;
    E_aperture *= metric;
}        

void Antenna::G3RPE_approximation(double target_f_over_D)
{
// straight line approximation to G3RPE curves for rectangular feedhorn 
// - within 2% for f/D < 0.8


    H_aperture = wavelength * ((target_f_over_D * 2.864) - 0.575);
        
    E_aperture = wavelength * ((target_f_over_D * 1.727) - 0.129);

    double apex_length = H_aperture * H_aperture / wavelength; //approximation

    axial_length = apex_length * ( (H_aperture - H_wg) / H_aperture);

    cout << "\n\nEstimated feedhorn dimensions:";
    cout << "\n\n   H aperture = " << (H_aperture/metric) << " " << units
         << "\n   E aperture = " << (E_aperture/metric) << " " << units
         << "\n   Axial length = " << (axial_length/metric) << " " << units
         << endl;
    cout << "\n\n *** YOU must adjust the length of the horn to "
			<< "match phase centers ***\n";
}

void Horn::lookup()
{

//   Lookup table based on 
//    D.E. Cozzens, "Tables Ease Horn Design," _Microwaves_, March 1966, p37.
//   from which I eyeballed nominal values;
//   anyway, the program calculates a new gain later 
         
    float G[ 26];
    
    for (int i = 0; i < 10; i++)
        G[i] = 0;
        
    G[10] = 0.080;
    G[11] = 0.24;
    G[12] = 0.4;
    G[13] = 0.6;
    G[14] = 0.88;
    G[15] = 1.25;
    G[16] = 1.7;
    G[17] = 2.25;
    G[18] = 3.0;
    G[19] = 4.0;
    G[20] = 5.2;
    G[21] = 6.7;
    G[22] = 8.7;
    G[23] = 11.2;
    G[24] = 14.3;
    G[25] = 18.3;

    bad = 1;
    
    double gain;    

    while (bad)
    {
        cout << "\n" << "Enter desired gain of horn in dB: ";
	cout.flush();
	cin >> gain;

        if ((gain < 10.0) || (gain > 25.0))
            cout << "Gain must be between 10 and 25 dB";
        else bad = 0;
    }        

    axial_length = wavelength * G[int(gain)];

// {need gain as a ratio to find horn apertures }
// {**** NOTE y=z**x -> y:=exp(x*ln(z)) ****}

    double gain_ratio = exp(0.2302585 * (int(gain)));            

    H_aperture = wavelength * 0.4675 * sqrt(gain_ratio);

    E_aperture = wavelength * 0.3463 * sqrt(gain_ratio);

    cout << "\n" << " CALCULATED HORN DIMENSIONS: \n";   
    
    cout << "\n" << "   Axial length of horn is "
         << setprecision(4) << (axial_length/metric) << " "
	 << units;
    cout << "\n" << "   H-plane aperture of horn is "
	 << setprecision(4) << (H_aperture/metric) << " "
	 << units;
    cout << "\n" << "   E-plane aperture of horn is "
	 << setprecision(4) << (E_aperture/metric) << " "
	 << units;
}


void Horn::simple_gain()
{                 // temp - simple formula from Kraus

    simplegain = 4.5 * (H_aperture/wavelength) * (E_aperture/wavelength);

    simplegain = 10.0 * log10(simplegain) + 2.14 ;   //{ dBi }
            
//    cout << " Simple (uncorrected aperture) gain of horn is "
//         << setprecision(3) << simplegain << " dBi \n";
}            

double Le(double s)
{
//    MathCad fit by Matt Reilly of Fig. 23 from Balanis

//    input is Maximum input phase error in wavelengths
//    returns loss due to phase error in dB.

//	Le(s) = sum(from i=1 to 10) Xle[i] * s^i

    if ( s < 0 || s > 1)
    {
        cerr << "ERROR: excessive phase error in Le\n\n";
        return 1;
    }

    double Xle[11];

// Xle[i] = 
    Xle[1] =   10.5075396618;
    Xle[2] =  -236.610713851;
    Xle[3] =   2603.14290758;
    Xle[4] =  -15318.8133545;
    Xle[5] =   55318.7209697;
    Xle[6] =  -125471.932662;
    Xle[7] =   178426.752358;
    Xle[8] =  -153811.177005;
    Xle[9] =   73233.5757222;
    Xle[10] =  -14743.1657614;

    double Le = 0;

    for (int i = 1; i < 11; i++)
    {
	Le += Xle[i] * pow(s,i);
    }
    return Le;
}

double Lh(double t)
{
//    MathCad fit by Matt Reilly of Fig. 23 from Balanis

//    input is Maximum input phase error in wavelengths
//    returns loss due to phase error in dB.

//	Lh(t) = sum(from i=1 to 10) Xlh[i] * t^i

    if ( t < 0 || t > 1)
    {
        cerr << "ERROR: excessive phase error in Lh\n\n";
        return 1;
    }

    double Xlh[11];

// Xlh[i] =
    Xlh[1] =   -13.9134920465;
    Xlh[2] =      398.4347217;
    Xlh[3] =   -4241.37951372;
    Xlh[4] =    24010.7335428;
    Xlh[5] =    -79636.863311;
    Xlh[6] =    162957.754379;
    Xlh[7] =   -208325.065791;
    Xlh[8] =    162037.036743;
    Xlh[9] =   -70133.3772858;
    Xlh[10] =     12951.940007;

    double Lh = 0;

    for (int i = 1; i < 11; i++)
    {
        Lh += Xlh[i] * pow(t,i);
    }
    return Lh;
}

double phase_error(double aperture, double flare_angle, double wavelength)
{
    double rho = 0.5 * aperture / sin(flare_angle);
//cout << setprecision(4) << "\n aperture = " << aperture
//     << " flare angle = " << flare_angle
//     << " rho =  " << rho ;   
    double error = aperture * aperture / ( 8.0 * wavelength * rho );
    
    return error;
}

void Antenna::horn_calcgain()
{
//improved algorithm from
// Balanis, C.A., "Horn Antennas", Chapter 8 in 
// Lo, Y.T. and Lee, S.W.
// Antenna Handbook: Theory, Applications and Design, Van Nostrand, 1988
// pp 8-39 to 8-42.


    horn_gain = 10.0 * ( 1.008 + 
                 log10( E_aperture * H_aperture / (wavelength * wavelength)));


// correct for phase error


    double s = phase_error(E_aperture, H_flare_angle, wavelength);
//cout << setprecision(4) << "\n s = " << s << "  Le(s) = " << (Le(s));

    double t = phase_error(H_aperture, E_flare_angle, wavelength);
//cout << setprecision(4) << "\n t = " << t << "  Lh(t) = " << (Lh(t)) << endl;

    horn_gain -= (Le(s) + Lh(t));               // dBi

//    cout << " Improved gain (corrected for flare angle and length) of horn is "
//         << setprecision(3) << horn_gain << " dBi \n";

}


void Horn::write_data(ostream& ostrm, int interactive)
{
    // anti warning hack.
    int i, j;
    for(i = j = 0; i < 10; i++) j = j + interactive;

    ostrm << " \nSimple (uncorrected aperture) gain of horn is "
	  << setprecision(3) << simplegain << " dBi \n";

    ostrm << " \nImproved gain (corrected for flare angle and length) of horn is "
	  << setprecision(3) << horn_gain << " dBi \n\n";

    ostrm << "H-Plane phase center is "
         << setprecision(3) << H_phase_center
         << " wavelengths inside horn mouth\n"; 
    ostrm << "E-Plane phase center is "
	  << setprecision(3) << E_phase_center
	  << " wavelengths inside horn mouth\n";
}

void Antenna::horn_angles()
{                
// note definition of E_flare_angle is the angle that the E side is 
// flared at, which is the flare angle in the H plane

    E_flare_angle = atan2((0.5 * (H_aperture - H_wg)) , axial_length);
    E_side = axial_length / cos(E_flare_angle);
    E_ang = atan2((0.5 * (E_aperture - E_wg)) , E_side);

    H_flare_angle = atan2((0.5 * (E_aperture - E_wg)) , axial_length);
    H_side = axial_length / cos(H_flare_angle);
    H_ang = atan2((0.5 * (H_aperture - H_wg)) , H_side);

// test

//    cout << setprecision(4) 
//         << "Flare angles " << E_flare_angle << "   " << H_flare_angle << "\n";
//    cout << setprecision(4) 
//         <<  "Side lengths" << E_side << "   " << H_side << "\n";
//    cout << setprecision(4) 
//         << "Angles " << E_ang << "   " << H_ang << "\n";
}


void Horn::coords()
{
// TEST
//    cout << " ENTERING fixed Horn::coords()" << endl;

    double fold_ang = E_ang + H_ang;

    inner[1] = inner[0] + Point(E_wg,0);

    inner[2] = inner[1] + Point((H_wg * cos(fold_ang)),-(H_wg * sin(fold_ang)));

    inner[3] = inner[2] + Point((E_wg * cos(2 * fold_ang)),
                                -(E_wg * sin(2 * fold_ang)));
                           
    inner[4] = inner[3] + Point((H_wg * cos(3 * fold_ang)),
                                -(H_wg * sin(3 * fold_ang)));

    outer[0] += Point(-(0.5 * (E_aperture - E_wg)),E_side);

    outer[1] = outer[0] + Point(E_aperture,0);

    outer[2] = outer[1] + Point((H_aperture * cos(fold_ang)),
				-(H_aperture * sin(fold_ang)));

    outer[3] = outer[2] + Point((E_aperture * cos(2 * fold_ang)),
				-(E_aperture * sin(2 * fold_ang)));

    outer[4] = outer[3] + Point((H_aperture * cos(3 * fold_ang)),
				-(H_aperture * sin(3 * fold_ang)));

	// and a solder flap


    inner[5] = inner[4] + Point((7 * cos(3*fold_ang - 0.7854 + H_ang)),
			       (-(7 * sin(3*fold_ang - 0.7854 + H_ang))));

    outer[5] = outer[4] + Point((7 * cos(3*fold_ang + 0.7854 + H_ang)),
                                (-(7 * sin(3*fold_ang + 0.7854 + H_ang))));



//%t   cout << "H_angle = " << H_ang << endl;
    
//%t   cout << "fold_angle = " << fold_ang << endl;
    
//%t   Point in5_pt = Point((7 * cos(3*fold_ang - 0.7854 + H_ang)),
//			       (-(7 * cos(3*fold_ang - 0.7854 + H_ang))));

//%t   cout << "inner_5 increment = " << in5_pt << endl;

//%t   Point out5_pt = Point((7 * cos(3*fold_ang + 0.7854 + H_ang)),
//				(-(7 * cos(3*fold_ang + 0.7854 + H_ang))));

//%t   cout << "outer_5 increment = " << out5_pt << endl;

}
//






void Horn::PS_template()
{                      // PostScript template on one page
                       // or two pages for larger horns
                       
    char descriptor[LINESIZE] = " ";
    char outname[LINESIZE];

    cin.ignore(LINESIZE,'\n');
    cout << " Horn description line: ";
    cout.flush();
    cin.get(descriptor,LINESIZE,'\n');

    cout << "File name for horn template (should be .PS ): ";
    cout.flush();
    cin >> outname ;

    ofstream outfil(outname);

    if (!outfil) 
    {
        cerr << "Cannot open output file for output";
    }
    
    int pages = 2;
    
    Point offset;

    if ((outer[0].y() - outer[4].y()) < 260)         // horn fits on page 
    {
        pages = 1;
        if (outer[4].x() < outer[0].x())
            offset = Point(-outer[4].x(), -outer[0].y());
        else offset = Point(-outer[0].x(), -outer[0].y());
    }
    else offset = Point(-outer[0].x(), -outer[0].y());

    offset =  Point(25,254) + offset;
            
    
//      PostScript header 


    outfil << "%! PostScript \n";
    outfil << "/mm { 2.834646 mul } def\n";
    outfil << "/in { 72 mul } def\n";

    outfil << "%\n";
    outfil << "% 100% scaling factors - change for printer correction\n";
    outfil << "1.0 1.0 scale \n";
    outfil << "%\n";

    outfil << setprecision(3)
           << "% Template for " << horn_gain << " dBi pyramidal horn for " 
           << setprecision(5)
           << freq << " MHz" << endl;
    outfil << "% generated by HDLANT3b by N1BWT 1994,1995,1996,1998 " << endl;
    outfil << "%" << endl;
    outfil << "%" << descriptor;
    outfil << "%" << endl;
    
// put the horn dimensions in the PS file for future reference
    outfil << "\n" << "%   Axial length of horn is "
           << setprecision(4) << (axial_length/metric) << " "
	   << units;
    outfil << "\n" << "%   H-plane aperture of horn is "
	   << setprecision(4) << (H_aperture/metric) << " "
	   << units;
    outfil << "\n" << "%   E-plane aperture of horn is "
	   << setprecision(4) << (E_aperture/metric) << " "
	   << units;
    outfil << "\n%   H-Plane phase center is "
           << setprecision(3) << H_phase_center
           << " wavelengths inside horn mouth\n"; 
    outfil << "%   E-Plane phase center is "
	   << setprecision(3) << E_phase_center
	   << " wavelengths inside horn mouth\n\n";
    outfil << "% Print on PostScript printer" << endl;
    outfil << "% stick to flashing copper";
    outfil << "% and cut out pieces." << endl;
    outfil << "% Then fold up and solder horn";
    outfil << "% then solder it to waveguide flange." << endl;
    outfil << setprecision(4);
    outfil << "% Waveguide size is " << (H_wg/metric) << " "
           << units << " x " << (E_wg/metric) << " " << units << "\n";
    outfil << "%" << endl;
    outfil << "%" << endl;
    
    outfil << "gsave" << endl;
    outfil << "% HORN **********************************************" << endl;
    outfil << "%" << endl;
    
    outfil << offset.x() << " mm " << offset.y() << " mm translate" << endl;
    
    outfil << "%" << endl;
    outfil << "%" << endl;
    outfil << "% HORN" << endl;
    outfil << "%" << endl;

// Text

    outfil << "/Helvetica-Bold findfont" << endl;
    outfil << "14 scalefont" << endl;
    outfil << "setfont" << endl;

    outfil << (outer[0].x() + 10) << " mm "
           << (outer[1].y() + 12) << " mm moveto" << endl;

    outfil << "(Template for " << horn_gain << " dBi horn for "
	   <<  int(freq) << " MHz) show" << endl;

    outfil << "-10.0 mm " << (outer[1].y() - 7) << " mm moveto" << endl;

    outfil << "(E-plane) show" << endl;
    outfil << "-10.0 mm " << (outer[1].y() - 14) << " mm moveto" << endl;

    outfil << " (N1BWT 1994,1998) show " << endl;

// and horn outline for single page

    if (pages == 1)
    {
        outfil << "newpath" << endl;
        outfil << PS_moveto() << "\n";
            
        for (int i = 0; i <= 4; i++)
            outfil << PS_lineto(outer[i]) << "\n";

        for ( i = 4; i >= 0; i--)
            outfil << PS_lineto(inner[i]) << "\n";

        outfil << "stroke" << endl;

        outfil << "%" << endl;

// and fold lines 

        outfil << "% fold lines" << endl;


        for ( i = 0; i <= 5; i++)
        {
            outfil << "newpath" << endl;
            outfil << "[10 10] 0 setdash\n" ;
            outfil << PS_moveto(inner[i]) << "\n";
            outfil << PS_lineto(outer[i]) << "\n";
            outfil << "stroke" << endl;
        }

        outfil << "% finish solder flap" << endl;

        outfil << "newpath" << endl;
        outfil << "[10 10] 0 setdash\n" ;
        outfil << PS_moveto(inner[4]) << "\n";
        outfil << PS_lineto(inner[5]) << "\n";
        outfil << "stroke" << endl;

        outfil << "newpath" << endl;
        outfil << "[10 10] 0 setdash\n" ;
        outfil << PS_moveto(outer[4]) << "\n";
        outfil << PS_lineto(outer[5]) << "\n";
        outfil << "stroke" << endl;

        outfil << "% END HORN ***************************************" << endl;
        outfil << "grestore" << endl;

        outfil << "showpage" << endl;

    }
    
    else        // two pages
    {

// E-plane side: coordinates same as single page

outfil << "% E-plane side of HORN ***************************************\n";


        outfil << "newpath" << endl;
        outfil << PS_moveto() << "\n";
            
        for (int i = 0; i <= 1; i++)
            outfil << PS_lineto(outer[i]) << "\n";

        for ( i = 1; i >= 0; i--)
            outfil << PS_lineto(inner[i]) << "\n";

        outfil << "stroke" << endl;

        outfil << "%" << endl;
    
        outfil << "% END E-plane side of HORN ****************************\n";
        outfil << "grestore\n";

        outfil << "showpage\n";
        outfil << "%\n";

// H-plane side: new coordinates

        outfil << "gsave" << endl;
outfil << "% H-plane side of HORN ***************************************\n";

// center large aperture as well as we can


        if (H_aperture > 190)
            offset = Point((0.5 * (215.0 - H_aperture) - outer[0].x()),
                            (254 - outer[0].y()));
                            
        outfil << "%" << endl;
    
    outfil << offset.x() << " mm " << offset.y() << " mm translate" << endl;
    
        outfil << "%" << endl;

        inner[1] = inner[0] + Point(H_wg,0);

        outer[0] = Point(-(0.5 * (H_aperture - H_wg)),H_side);

        outer[1] = outer[0] + Point(H_aperture,0);

        outfil << "newpath" << endl;
        outfil << PS_moveto() << "\n";
            
        for ( i = 0; i <= 1; i++)
            outfil << PS_lineto(outer[i]) << "\n";

        for ( i = 1; i >= 0; i--)
            outfil << PS_lineto(inner[i]) << "\n";

        outfil << "stroke" << endl;

        outfil << "%" << endl;

        outfil << "% END E-plane side of HORN ****************************\n";


// text for H-plane side

        outfil << "/Helvetica-Bold findfont" << endl;
        outfil << "14 scalefont" << endl;
        outfil << "setfont" << endl;
    
        outfil << (outer[0].x() + 10) << " mm "
               << (outer[1].y() + 12) << " mm moveto" << endl;
    
        outfil << "(Template for " << horn_gain << " dBi horn for "
               <<  int(freq) << " MHz) show" << endl;
    
        outfil << "-10.0 mm " << (outer[1].y() - 7) << " mm moveto" << endl;
    
        outfil << "(H-plane) show" << endl;
        outfil << "-10.0 mm " << (outer[1].y() - 14) << " mm moveto" << endl;
    
        outfil << " (N1BWT 1994,1998) show " << endl;

        outfil << "grestore\n";
        outfil << "showpage\n";
        outfil << "%\n";
        
        outfil.close();
    }
}    


//






//* predeclare entry points for phase center routines */
    double Phase_center(char, float, float, float, float);
    double H_Phase_Center(double, double, double, double&, double&);
    double E_Phase_Center(double, double, double, double&, double&);
    double fresnel_sin(double, double&, double&);
    double fresnel_cos(double, double&, double&);


void Antenna::horn_phasecenters()
{

/* get the phase centers and decide what to do about them */

    E_phase_center = Phase_center('E', E_aperture, E_wg, 
                                    wavelength, axial_length);
    H_phase_center = Phase_center('H', H_aperture, H_wg, 
                                    wavelength, axial_length);

//    cout << "E-Plane phase center is "
//	 << setprecision(2) << E_phase_center
//	 << " wavelengths inside horn mouth\n";
//    cout << "H-Plane phase center is "
//         << setprecision(2) << H_phase_center
//         << " wavelengths inside horn mouth\n\n"; 

}

double Pi, Pi2, Pi2sq;     // /* precomputed values for Pi and Pi/2

#define	ERRMARGIN	2.0E-3
#define	MAX(a,b)	(a > b ? a : b)
#define	MIN(a,b)	(a < b ? a : b)


double Phase_center(char plane, float aperture, float guide, 
                    float wavelength, float Horn_length)
//    /* convert to wavelengths for phase center routine */
//    char plane ;        /* E or H plane */
//    double aperture ;   /* aperture dimension in mm */
//    double guide ;      /* waveguide dimension in mm */
    
{
    double side_length ;    /* length of horn side in wavelengths */
    double Ap_lambda ;      /* aperture in wavelengths */
    double v ;              /* sqrt(side_length/2.0) */
    double dmin, dmax ;     /* limits check on phase center */
    double PC ;             /* phase center in wavelengths */

    Ap_lambda = aperture / wavelength ;
    side_length = sqrt(Horn_length*Horn_length +
			 ((aperture - guide)/2.0)*((aperture - guide)/2.0));
    side_length = side_length / wavelength ;
    v = sqrt(side_length/2.0);


    if (plane == 'E')
        PC = E_Phase_Center( Ap_lambda, v, side_length, dmin, dmax);
    else 
        PC = H_Phase_Center( Ap_lambda, v, side_length, dmin, dmax);

/* test for bad phase center */

    if ( fabs(dmax - dmin) != (fabs(dmax) - fabs(dmin)))
        cerr << " \n\nERROR: BUG in "
             << plane << "_Phase_Center function\n\n";// call Matt\n";
    else if ((fabs(dmax - dmin) > (PC /16.0)) && (Ap_lambda > 1.0))
        cerr << " \n\nEXCESSIVE ERROR in "
             << plane << "_Phase_Center function \n\n";
        
    return (PC);
}
//












    
 
/* 

 */

    
///* phase_center.c     Matt Reilly 10/28/91 */
// converted for C++  2/17/94 pcw
///* input data:  a       aperture in wavelengths
//                l       length of horn side in wavelengths
//                v       sqrt(l/2) in wavelengths
//                lv      low de value  - error check
//                hv      high de value -  "     "
//                
//    E_Phase_Center returns distance in wavelengths from mouth of horn to
//        E-plane phase center inside horn.
//
//    H_Phase_Center returns distance in wavelengths from mouth of horn to
//        H-plane phase center inside horn.
//
//*/

void phase_init()
{
    ph_init = 0;
}

double epc(double l, double q, double c2, double s2, double C, double S)
//double l, q, c2, s2, C, S;
{
    return l * ( 1 - q * (c2 * C + s2 * S) / (C * C + S * S));
}

double E_Phase_Center(double a, double v, double l, double &lv, double &hv)
//double a, v, l;
//double * lv, * hv;
{
    double q, c2, s2, fc, fcl, fch, fs, fsl, fsh, res;
    
    if(ph_init) phase_init();
    
    q = a / (2 * v);
    
    fc = fresnel_cos(q, fcl, fch);
    fs = fresnel_sin(q, fsl, fsh);
    
    c2 = cos(Pi2 * q * q);
    s2 = sin(Pi2 * q * q);
    
    res = epc(l, q, c2, s2, fc, fs);
    hv = epc(l, q, c2, s2, fch, fsh);
    lv = epc(l, q, c2, s2, fcl, fsl);
    
    return res;
}


double hpc(double l, double r, double t, double c, double s)
//double l, r, t, c, s;
{
    return l * (1 + (((r * c) + (t * s)) / ((c * c) + (s * s))));
}

double H_Phase_Center(double a, double v, double l, double &lv, double &hv)
//double a, v, l;
//double * lv, * hv;
{
    double U, W, CD, CDH, CDL, SD, SDH, SDL, R, T, u2, w2;
    double su, sul, suh, sw, swl, swh;
    double cu, cul, cuh, cw, cwl, cwh;
    double res;


    if(ph_init) phase_init();
        
    U = v / a + a / (2 * v);
    W = v / a - a / (2 * v);
    u2 = Pi2 * U * U;
    w2 = Pi2 * W * W;
    
    
    R = W * cos(u2) - U * cos(w2);
    T = U * sin(w2) - W * sin(u2);
    
    su = fresnel_sin(U, sul, suh);
    sw = fresnel_sin(W, swl, swh);
    cu = fresnel_cos(U, cul, cuh);
    cw = fresnel_cos(W, cwl, cwh);

    CD = cu - cw;
    CDL = cul - cwh;
    CDH = cuh - cwl;    

    SD = - su + sw;
    SDL = - suh + swl;
    SDH = - sul + swh;    
    
    res = hpc(l, R, T, CD, SD);
    hv = hpc(l, R, T, CDH, SDH);
    lv = hpc(l, R, T, CDL, SDL);

    return res;

}

///* 




///* fresnel_integrals.c         Matt Reilly 10/28/91 */
// converted for C++  2/17/94 pcw
//
///*  approximation to Fresnel sine and Fresnel cosine needed to calculate
//    phase centers of horn 
//    
//*/
//
void fresnel_init()
{
    Pi = atan2(0.0, -1.0);
    Pi2 = Pi / 2.0;
    Pi2sq = Pi2 * Pi2;
    lib_init = 0;
}

double fresnel_f(double z)
//double z;
{
    /* from stegun and abramowitz pp 301 and 302. */
    double sum;
    
    sum = (1.0 + 0.926 * z) / (2.0 + 1.792 * z + 3.104 * z * z);
    
    return sum;
}

double fresnel_g(double z)
//double z;
{
    /* from stegun and abramowitz pp 301 and 302. */
    double sum;
    
    sum = 1.0 / (2.0 + 4.142 * z + 3.492 * z * z + 6.670 * z * z * z);
    
    return sum;
}

double fresnel_cos(double z, double &low, double &high)
//double z, *low, *high;
{
//    int n;   /* series index */
    double sum, x, f, g, c, s, fs1, fs2, gc1, gc2, sign;
		 
    sign = 1.0;
    if(lib_init)   fresnel_init();
    
    if (z < 0) 
    {
        z = -z; 
	sign = - 1.0;
    }
    else sign = 1.0;
    
    x = Pi2 * z * z;
    f = fresnel_f(z);
    g = fresnel_g(z);
    c = cos(x);
    s = sin(x);
    

    
    sum = 0.5 + 
	  f * s - 
	  g * c;

    fs1 = (f + ERRMARGIN) * s;
    fs2 = (f - ERRMARGIN) * s;
    gc1 = (g + ERRMARGIN) * c;
    gc2 = (g - ERRMARGIN) * c;

    if(sign > 0)
    {
    	low = (0.5 +  MIN(fs1, fs2) - MAX(gc1, gc2));
    	high = (0.5 + MAX(fs1, fs2) - MIN(gc1, gc2));
    }
    else
    {
        low = -1.0 * (0.5 + MAX(fs1, fs2) - MIN(gc1, gc2));
    	high = -1.0 * (0.5 +  MIN(fs1, fs2) - MAX(gc1, gc2));
    }


    return sum * sign;
}


double fresnel_sin(double z, double &low, double &high)
//double z, *low, *high;
{
//    int n;   /* series index */
	 double sum, x, f, g, c, s, fc1, fc2, gs1, gs2, sign;
		 
		 
    if(lib_init)   fresnel_init();
    

    if (z < 0) 
    {
        z = -z; 
	sign = - 1.0;
    }
    else sign = 1.0;

    x = Pi2 * z * z;
	 f = fresnel_f(z);
    g = fresnel_g(z);
    c = cos(x);
    s = sin(x);
    
    sum = 0.5 - 
	  f * c - 
	  g * s;

    fc1 = (f + ERRMARGIN) * c;
    fc2 = (f - ERRMARGIN) * c;
    gs1 = (g + ERRMARGIN) * s;
	 gs2 = (g - ERRMARGIN) * s;
    
	 if(sign > 0.0)
    {
        low = (0.5 - MAX(fc1, fc2) - MAX(gs1, gs2));
    	high = (0.5 - MIN(fc1, fc2) - MIN(gs1, gs2));
    }
    else
    {
        low = -1.0 * (0.5 - MIN(fc1, fc2) - MIN(gs1, gs2));
    	high = -1.0 * (0.5 - MAX(fc1, fc2) - MAX(gs1, gs2));
    }

    return sign * sum;
}
//

Conical_horn::Conical_horn() : Antenna()        //constuctor
{
    axial_length = 0;
    con_aperture_dia = 0;
    circ_wg_diam = 0;
    flare_angle = 0;
    con_gain = 0;
}

void Conical_horn::dimensions()
{                               // input dimensions of a conical horn
            
    cout << "\n" << "ENTER DESIRED PHYSICAL DIMENSIONS OF CONICAL HORN: \n";
    
    int bad = 1 ;
    while (bad >= 1)
    {    
        cout << "\n" << "Enter input circular waveguide diameter of horn in "
             << units << ": ";
        cout.flush();
        cin >> circ_wg_diam;
        circ_wg_diam *= metric;
    
        cout << "\n" << "Enter aperture diameter of conical horn in "
             << units << ": ";
        cout.flush();
        cin >> con_aperture_dia;
        con_aperture_dia *= metric;
    
        if (con_aperture_dia < circ_wg_diam)
            {
            cerr << " ERROR - aperture smaller than waveguide \n";
            bad++;
            if (bad > 3) break;
            }
            
	else if (wavelength > ( 1.706 * circ_wg_diam ))
            {
            cout << " ERROR - frequency below waveguide cutoff \n";
            bad++ ;
            if (bad > 3) break;
            }
	else if (wavelength < ( 1.306 * circ_wg_diam ))
            {
            cout << " WARNING - waveguide can propagate additional modes \n";
            }
        else bad = 0;
    }    

     
    char mode = 'n';

    while (mode == 'n' && bad == 0)
        {
        cout << "\nNow we need either the AXIAL LENGTH or the FLARE ANGLE; \n" 
             << "Enter L to choose axial Length or F to choose Flare angle: " ;
        cout.flush();
        cin >> mode ;
        mode = toupper(mode);

    
        if (mode == 'L')
            {
            cout << "\n" << "Enter axial length of horn in "
                 << units << ": ";
            cout.flush();
            cin >> axial_length;
            axial_length *= metric;         //mm
        
            cout << "\n\nThe Flare half-angle is measured from the axis to one side.";
            flare_angle = atan(0.5 * (con_aperture_dia - circ_wg_diam) / axial_length);

            cout << "\n     Flare half-angle = " << setprecision(3) 
                 << (flare_angle*crad) << " degrees\n" ;
            }
        else if (mode == 'F')
            {
            cout << " \n The Flare half-angle is measured from the axis to one side.";
            cout << " \n Enter Flare half-angle in degrees: " ;
            cout.flush();
            cin >> flare_angle;
            flare_angle = flare_angle / crad;      

            axial_length = 0.5 * (con_aperture_dia - circ_wg_diam) / tan(flare_angle);
        
	    cout << "\n\n     Axial length = " << setprecision(3) 
                 << (axial_length / metric) << " "
                 << units << " \n\n";        
            }
        else mode = 'n';
        }
}

void Conical_horn::optimum_horn()
//calculates "optimal" conical horn for a given gain
{
    bad = 1;
    
    double gain;    

    while (bad)
    {
        cout << "\n" << "Enter desired gain of conical horn in dBi: ";
	cout.flush();
	cin >> gain;

        if ((gain < 10.0) || (gain > 25.0))
            {
            cout << "Gain must be between 10 and 25 dB";
            bad ++;
            }
        else bad = 0;

        cout << "\n" << "Enter input circular waveguide diameter of horn in "
             << units << ": ";
        cout.flush();
        cin >> circ_wg_diam;
        circ_wg_diam *= metric;
    
	if (wavelength > ( 1.706 * circ_wg_diam ))
        {
            cout << " ERROR - frequency below waveguide cutoff \n";
            bad++ ;
            if (bad > 3) break;
        }
	else if (wavelength < ( 1.306 * circ_wg_diam ))
        {
            cout << " WARNING - waveguide can propagate additional modes \n";
        }
    }        
    
    double circum = wavelength * pow(10.0,((gain + 2.82)/20.0));
    
    con_aperture_dia = circum / pi;
    
    double l = con_aperture_dia  * con_aperture_dia / (3.0 * wavelength);
    
    flare_angle = asin(0.5 * con_aperture_dia / l);
    
    axial_length = 0.5 * (con_aperture_dia - circ_wg_diam) / tan(flare_angle);

    cout << "\n\n     The optimum conical horn for has an aperture diameter = " 
         << setprecision(4) 
         << (con_aperture_dia / metric) << " "
         << units << " \n";        

            cout << "with a flare half-angle = " << setprecision(3) 
                 << (flare_angle*crad) << " degrees\n" ;

	    cout << "and an axial length = " << setprecision(3) 
                 << (axial_length / metric) << " "
                 << units << " \n\n";        
            cout << "The Flare half-angle is measured from the axis to one side.\n";

}


void Conical_horn::simple_gain()
{
    efficiency = 0.52;     //  52% efficiency from Jasik for optimum conical horn
    
    double radius = 0.5 * con_aperture_dia;

    double aperture_area = pi * radius * radius;

    con_gain = efficiency * aperture_area * 4.0 * pi / (wavelength * wavelength);

    con_gain = 10.0 * log10(con_gain);          // dBi

    cout << "Simple (uncorrected aperture) gain for conical horn = " 
           << setprecision(3)
           << con_gain << " dBi at "
           << setprecision(5)
           << freq << " MHz\n" << endl;           
}


double Lc(double s)
{
//    conical horn gain correction from Fig 10-11 of Jasik, 1st edition
//    Matlab fit - 3rd order as accurate by eye as higher order

//    input is Maximum input phase error in wavelengths
//    returns loss due to phase error in dB.

//	Lc(s) = sum(from i=0 to 3) Xle[i] * s^i

    if ( s < 0 || s > 1.0)
    {
        cerr << "ERROR: excessive phase error in Lc\n\n";
        return 999;
    }

    double Xlc[4];

// Xlc[i] = 
    Xlc[0] =    0.80375807;
    Xlc[1] =   -0.98591418;
    Xlc[2] =    19.893228;
    Xlc[3] =   -8.0330824; 

    double Lc = 0;

    for (int i = 0; i < 4; i++)
    {
	Lc += Xlc[i] * pow(s,i);
    }
//debug cout << "Lc = " << Lc << " dB\n";    
    return Lc;
}

void Conical_horn::gain()
{
//  corrected gain from page 10-11 of Jasik, first edition
    // side length to apex
    double l = 0.5 * con_aperture_dia /sin(flare_angle);
    //phase error
    double s = con_aperture_dia * con_aperture_dia / ( 8.0 * wavelength * l);
//debug  cout << "s = " << s << " \n";    

    con_gain = 20.0 * log10(pi * con_aperture_dia / wavelength) - Lc(s); 

    cout << "Gain for conical horn after phase error correction = " 
           << setprecision(3)
           << con_gain << " dBi at "
           << setprecision(5)
           << freq << " MHz" << endl;

    cout << "\n Phase center is unknown!\n\n";

}

void Conical_horn::PS_template()
{                      // PostScript template for a conical horn

    char descriptor[LINESIZE] = " ";
    char outname[LINESIZE];

    cin.ignore(LINESIZE,'\n');
    cout << " Conical Horn description line: ";
    cout.flush();
    cin.get(descriptor,LINESIZE,'\n');

    cout << "File name for Conical horn template (should be .PS ): ";
    cout.flush();
    cin >> outname ;

    ofstream outfil(outname);

    if (!outfil) 
    {
        cerr << "Cannot open output file for output";
    }

// calculate template dimensions
    double inner_radius = 0.5 * circ_wg_diam / sin(flare_angle);
    
    double outer_radius = 0.5 * con_aperture_dia / sin(flare_angle);
    
    double rotation_angle_deg = 360 * sin(flare_angle);
    
// put dimensions on the screen
    cout   << "\n\nDimensions for conical horn template:\n\n";
    cout   << setprecision(3)
           << "Inner radius = "
           << (inner_radius / metric) << " "
           << units << " \n";        
    cout   << setprecision(3)
           << "Outer radius = "
           << (outer_radius / metric) << " "
           << units << " \n";        
    cout   << setprecision(3)
           << "Rotation angle = "
           << (rotation_angle_deg) << " "
           << "degrees \n";        


    Point offset;

    offset =  Point(25+outer_radius,140);
                
//      PostScript header 

    outfil << "%! PostScript \n";
    outfil << "/mm { 2.834646 mul } def\n";
    outfil << "/in { 72 mul } def\n";

    outfil << "%\n";
    outfil << "% 100% scaling factors - change for printer correction\n";
    outfil << "1.0 1.0 scale \n";
    outfil << "%\n";

    outfil << setprecision(3)
           << "% Template for " << con_gain << " dBi conical horn for " 
           << setprecision(5)
           << freq << " MHz" << endl;

    outfil << setprecision(3)
           << "% Circular waveguide diameter = "
           << (circ_wg_diam / metric) << " "
           << units << " \n";        
    outfil << setprecision(3)
           << "% Conical horn aperture diameter = "
           << (con_aperture_dia  / metric) << " "
           << units << " \n";        
    outfil << setprecision(3)
           << "% Axial length = "
           << (axial_length / metric) << " "
           << units << " \n";        
    outfil << setprecision(3)
           << "% Flare half-angle = "
           << (flare_angle * crad) << " degrees "
           << " \n\n";        

    outfil << "% Dimensions for conical horn template:\n";
    outfil << setprecision(3)
           << "% Inner radius = "
           << (inner_radius / metric) << " "
           << units << " \n";        
    outfil << setprecision(3)
           << "% Outer radius = "
           << (outer_radius / metric) << " "
           << units << " \n";        
    outfil << setprecision(3)
           << "% Rotation angle = "
           << (rotation_angle_deg) << " "
           << "degrees \n";        


       
    outfil << "% generated by HDLANT3b by N1BWT 1994,1995,1996,1998 " << endl;
    outfil << "%" << endl;
    outfil << "%" << descriptor;
    outfil << "%" << endl;
    outfil << "% Print on PostScript or Ghostscript printer" << endl;
    outfil << "% stick to flashing copper";
    outfil << "% and cut out pieces." << endl;
    outfil << "% Then roll it up into a funnel and solder the straight edges,";
    outfil << "% then solder it to dircular waveguide." << endl;
    outfil << setprecision(4);
    outfil << "% Waveguide diameter is " << (circ_wg_diam/metric) << " "
           << units << "\n";
    outfil << "%" << endl;
    outfil << "%" << endl;
    
    outfil << "gsave" << endl;
    outfil << "% HORN **********************************************" << endl;
    outfil << "%" << endl;


    
    outfil << offset.x() << " mm " << offset.y() << " mm translate" << endl;
    
    outfil << "%" << endl;
    outfil << "%" << endl;
    outfil << "% HORN" << endl;
    outfil << "%" << endl;

// %===========================================

    outfil << "gsave" << endl;
    outfil << "newpath" << endl;
    outfil << "1 setlinewidth" << endl;

    if (rotation_angle_deg < 269)
        {
        outfil << "0 0 " << inner_radius << " mm 90 "  
               << (rotation_angle_deg + 90) << " arc " << endl; 
        outfil << "0 0 " << outer_radius << " mm "
               << (rotation_angle_deg + 90) << " 90 arcn " << endl; 
        }
    else
        {
        outfil << "0 0 " << inner_radius << " mm 0 "  
               << rotation_angle_deg << " arc " << endl; 
        outfil << "0 0 " << outer_radius << " mm "
               << rotation_angle_deg << " 0 arcn " << endl; 
        }
        
    outfil << "closepath" << endl;
    outfil << "stroke" << endl;
    outfil << "grestore" << endl;

// Text

    outfil << "/Helvetica-Bold findfont" << endl;
    outfil << "14 scalefont" << endl;
    outfil << "setfont" << endl;

    outfil << (-outer_radius) << " mm "
           << (outer_radius + 20) << " mm moveto" << endl;

    outfil << setprecision(3)
           << "(Template for " << con_gain << " dBi conical horn for " 
           << setprecision(5)
           << freq << " MHz) show" << endl;

    outfil <<  (10 - outer_radius) << " mm "
           << (outer_radius + 10) << " mm moveto" << endl;

    outfil << " (N1BWT 1998) show " << endl;

    outfil << "% END HORN ***************************************" << endl;
    outfil << "grestore" << endl;

    outfil << "showpage" << endl;
}

void Conical_horn::W2IMU_feedhorn()
{                               
// input dimensions of a W2IMU feed horn and calculate
            
    char mode = 'n';
    cout << "\nWould you like a suggestion for the aperture diameter [Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

       if (mode == 'Y')
    {
        cout << " \n Enter f/D ratio: ";
	cout.flush();
	cin >> con_aperture_dia;

	con_aperture_dia *= 2.35;

        cout << "\n    Estimated aperture diameter = " << setprecision(3) 
                 << con_aperture_dia << " wavelengths = " << setprecision(3) 
                 << (con_aperture_dia * wavelength/ metric) << " "
                 << units << " \n\n"; 
    }
 
    cout << "\n" << "ENTER DESIRED PHYSICAL DIMENSIONS OF W2IMU Dual-Mode FEEDHORN: \n";

    bad = 1 ;
    while (bad >= 1)
    {    
        cout << "\n" << "Enter input circular waveguide diameter of horn in "
             << units << ": ";
        cout.flush();
        cin >> circ_wg_diam;
        circ_wg_diam *= metric;
    
        cout << "\n" << "Enter aperture diameter of dual-mode horn in "
             << units << ": ";
        cout.flush();
        cin >> con_aperture_dia;
        con_aperture_dia *= metric;
    
	if (wavelength > ( 1.706 * circ_wg_diam ))
            {
            cout << " ERROR - frequency below input waveguide cutoff \n";
            bad++ ;
            if (bad > 3) break;
            }

	else if (wavelength > ( 0.82 * con_aperture_dia ))
            {
            cerr << " ERROR - aperture too small for TM11 mode \n";
            bad++;
            if (bad > 3) break;
            }
            
	else if (wavelength < ( 0.589 * circ_wg_diam ))
            {
            cout << " WARNING - output section can propagate additional modes \n";
            }
        else bad = 0;
    }    


// now calculate the dual-mode horn dimensions ( from Johnson, page 15-25)

// corrected 3/8/2003
//    flare_angle = (44.8 / crad) * wavelength / con_aperture_dia; 
    flare_angle = (44.6 / crad) * wavelength / con_aperture_dia; 

    cout << "\n     Flare half-angle = " << setprecision(3) 
                 << (flare_angle*crad) << " degrees\n" ;

    double guide__TE11_wavelength = wavelength /
             sqrt( 1.0 - pow((wavelength/(1.70646 * con_aperture_dia)), 2.0));
//             sqrt( 1.0 - pow((wavelength/(1.706 * con_aperture_dia)), 2.0));

    double guide__TM11_wavelength = wavelength /
             sqrt( 1.0 - pow((wavelength/(0.81983 * con_aperture_dia)), 2.0));
//             sqrt( 1.0 - pow((wavelength/(0.82 * con_aperture_dia)), 2.0));

    double phasing_section_length = 0.75 
           / ((1.0 / guide__TE11_wavelength) - (1.0 / guide__TM11_wavelength));  


    cout << "\n\n    Output phasing section length = " << setprecision(3) 
                 << (phasing_section_length / metric) << " "
                 << units << " \n\n";        

}



//










//forward declaration
double curve(double , int , double ); 


Lens::Lens() : Antenna()                   //constructor
{
    Lens_diam = 0.0;     
    spacing = 0.0  ;
    width_increase = 0.0;
    N = 0 ;
    BW_E_horn = 0.0 ;
    lens_focal_length = 0.0 ;     
    Gain_lens = 0.0 ;
    index = 0.0 ; 
    compensate = 0;
    step = 0.0;
    lens_to_horn = 0.0;
}    

void Lens::dimension()
//assumes that horn variables are available
{
    int bad = 1;
    while (bad >= 1 )
    {
	cout << "Enter approximate lens diameter in " 
             << units << ": ";
	cout.flush();
	cin >> Lens_diam  ;
        Lens_diam *= metric;
        
	cout << "Enter EXACT lens plate spacing in "
             << units << ": ";
	cout.flush();
	cin >> spacing ;
        spacing *= metric;

	if (spacing < (wavelength/2.0))
        {
	    cout << " ERROR - lens plate spacing below cutoff \n";
            bad++ ;
            if (bad >= 3) break;
        }
        
	else if (spacing >= wavelength)
            {
	      cout << " ERROR - lens plate spacing greater than wavelength \n";
              bad++ ;
              if (bad >= 3) break;
            }
            else bad = 0;
    }
}

void Lens::calculate()
{

//* make lens diameter an even number of spacings */

    N = (int)(Lens_diam /(2.0 * spacing)) ;
    if ( (Lens_diam - (2.0 * N * spacing)) > (spacing * 0.5 ))
        ++N;

    Lens_diam = 2.0 * N * spacing ;
    

    Gain_lens = (Lens_diam / E_aperture) * (Lens_diam / E_aperture) ;
        /* gain over bare horn */    

    Gain_lens =  10.0 * log10( Gain_lens );

    index = sqrt( 1.0 - ( wavelength / (2.0 * spacing)) *
			( wavelength / (2.0 * spacing))) ;
        /* effective index of refraction */

    BW_E_horn = (56.0 / ( E_aperture / wavelength ))/crad ; /* Kraus, p. 380 */
        
    lens_focal_length = Lens_diam / (2.0 * tan(BW_E_horn / 2.0)) ; /* E-plane*/
        
/* NOTE: if the E and H focal planes are different, then we can compensate
         by making the lens have a different focal length in each plane;
         for now, it will be symmetrical using the E-plane focal length.
         The unknown is the distance from the horn to the lens, which is
         the lens focal length minus the horn_focal_point distance. */
        
     
//    cout << " This is an f over "
//         << (lens_focal_length/Lens_diam) << " lens \n";
//    cout << " using " << (2*N+1)
//    	 << " lens plates for an actual diameter of " 
//	 << Lens_diam  << " mm \n\n";
//    cout << "\n";
//    cout << " Estimated gain of lens is " << Gain_lens
//	 << " dB added to horn gain \n\n ":

}

void Lens::phasecheck()
{

/* get the phase centers and decide what to do about them */

//    Horn_E_phase_center = Phase_center('E', Ap_E_horn, guide_E);
//    Horn_H_phase_center = Phase_center('H', Ap_H_horn, guide_H);

    cout << "E-Plane phase center is " << E_phase_center
         << " wavelengths inside horn mouth\n";
    cout << "H-Plane phase center is " << H_phase_center
         << " wavelengths inside horn mouth\n\n";
    

    if (fabs(E_phase_center - H_phase_center)>0.062 /*wavelengths*/)
    {
        compensate = 1 ;
        cout << "     Phase correction may be in order,\n "
             << "     or you might want a different horn\n\n";
    }
    else compensate = 0 ;
}


//void Lens::plates()     // calculate radius of individual plates
//{
//    for (int i = 1 ; i <= N; i++ )
//    {
//        radius[i] = curve(radius[0],i) ;
//        radius_2[i] = curve(radius_2[0],i);
//        width_increase = radius[0] - radius[i] ;
//    }
//}

double curve(double radius, int i, double spacing)
{
    double theta ;       /* angle from axis */
    double radius_N ;    /* radius of plate N */

    theta = asin(( (double)i * spacing) / radius) ;

    radius_N = radius * cos(theta) ;

    return (radius_N) ;
}


void Lens::write_data(ostream& ostrm, int interactive)
{
    int i ;
	 double FGHz = c / (wavelength * 1000000.0);

/* now a nice header */

    ostrm << "      Metal plate lens antenna for microwaves  \n\n";
    ostrm << "        ALL dimensions are in millimeters! \n\n" ;

    ostrm << "           ____________     \n";
    ostrm << "          |     E      |    \n";
    ostrm << "          |     ^ -->H |   waveguide  \n";
    ostrm << "          |     |      |    \n";
    ostrm << "           ------------     \n\n";

    ostrm << "  At a center frequency of "
	  << setprecision(5) << FGHz << " GHz\n\n";

    ostrm << "  For a lens with a diameter of "
	  << setprecision(5) << Lens_diam << " mm."
	  << " and a plate spacing of "
	  << setprecision(4) << spacing << " mm. \n\n";

    ostrm << "  Fed by a horn of axial length = "
	  << setprecision(4) << axial_length << " mm, \n"
	  << "      H-plane aperture = " << H_aperture << " mm \n"
	  << "      E-plane aperture = " << E_aperture << " mm \n "
	  << "      and a Gain of " << horn_gain
	  << " dB over isotropic \n\n";

    ostrm << "   E-Plane phase center is " << setprecision(4)
	  << E_phase_center << " wavelengths inside horn mouth\n";
    ostrm << "   H-Plane phase center is " << setprecision(4)
	  << H_phase_center << " wavelengths inside horn mouth\n";

    lens_to_horn = lens_focal_length - (E_phase_center * wavelength);

    ostrm << "  Calculations for an f/" << setprecision(2)
	  << (lens_focal_length/Lens_diam) ;
    ostrm << setprecision(4)
          << " lens with a focal length of " << lens_focal_length << " mm. \n"
	  << "      providing an estimated gain of " << Gain_lens
	  << " db over the horn\n\n"
	  << "  Distance from horn mouth to center of lens curve is "
	  << lens_to_horn << " mm.\n";

//    ostrm << "\n\n";
      if(interactive)
      {
	    char pause;
	    cout << "\n\nEnter D to display lens design dimensions: ";
	    cout.flush();
	    cin >> pause;
       }
/* design data */

    double radius[25];
    double radius_2[25];
    int SavedN;
/*    radius[0] = (index - 1.0) * lens_focal_length ; */ /* correct form */
    radius[0] = (1.0 - index ) * lens_focal_length ;      /* positive number */

    radius_2[0] = 2.0 * radius[0] ;

    SavedN = N;
    if (N > 24)
    {
	ostrm << "This is a pretty big lens, so only 50 plates calculated\n";
	N = 24;
    }

    for (i = 1 ; i <= N; i++ )
    {
	radius[i] = curve(radius[0],i,spacing) ;
	radius_2[i] = curve(radius_2[0],i,spacing);
    }

    if (!compensate)
    {

    ostrm << "\n  Radius of Curvature of lens plates starting from "
	  << "center plate\n\n" ;
    ostrm << "   Plate  Single radius   double radius   plate width \n";
    ostrm << "   -----    -------         ---------      -------- \n\n";
    ostrm << setprecision(4)
	  << "   ctr     " << radius[0] << " mm.     " << radius_2[0]
	  << " mm.    min \n";

	for (i = 1 ; i <= N; i++ )
	{
	    width_increase = radius[0] - radius[i] ;

	    ostrm << setprecision(4)
	    << "    " << i << "      " << radius[i] << " mm.     " << radius_2[i]
	    << " mm.    min + " << width_increase << "\n";
	}
    }

    else            /* add column for compensation */
    {

    double c_focal_length = lens_focal_length +
		     (H_phase_center - E_phase_center) * wavelength;

    double c_radius[25];
    c_radius[0] = (1.0 - index) * c_focal_length ;

    ostrm << "\n  Radius of Curvature of lens plates starting from "
	  << "center plate\n" ;
    ostrm << "  with H-Plane phase compensation by shifting plate "
	  << "centers\n";
    ostrm << "  of double-curved lens; positive shift is toward horn.\n\n";

    ostrm << "   Plate  Single radius   Double Radius   Plate Width"
	  << "      Shift\n";
    ostrm << "   -----    -------         ---------     -----------"
	  << "      ----- \n\n";

    ostrm << setprecision(4)
	  << "   ctr     " << radius[0] << " mm.     " << radius_2[0]
	  << " mm.       min \n";

    double shift [25];

	for (i = 1 ; i <= N; i++ )
	{
	    width_increase = radius[0] - radius[i] ;
	    c_radius[i] = curve(c_radius[0],i,spacing);
	    shift[i] = radius[0] - radius[i] - (c_radius[0] - c_radius[i]);

    ostrm << setprecision(4)
	  << "    " << i << "      " << radius[i] << " mm.     " << radius_2[i]
	  << " mm.       min + " << width_increase << "   "
	  << (shift[i]/2.0) << "\n";
	}
    }

    step = wavelength / ( 1.0 - index );

    if ( step < width_increase)
    ostrm << setprecision(4) << "\nFor a Zoned lens plate, "
	  << "step distance = " << step <<" mm.\n\n";

    N = SavedN;
}

void Lens::crude_graphics(ostream& ostrm)
{
/* and a picture to help */


ostrm << "\n\n\n       ****** UNBELIEVABLY CRUDE GRAPHICS ******\n\n";
                                                                                
ostrm << "               Single Curve        Double Curve \n\n";   
                                                                             
ostrm << "                       -----------         -------------\n";
ostrm << "                        ----------          ----------- \n";
ostrm << "        __               ---------    ^      --------- \n";
ostrm << "       |  |               --------    |       -------  \n";
ostrm << "       |  |    <          --------   H|       ---+---  \n";
ostrm << "       |  |    horn       --------    |       -------  \n";
ostrm << "        --               ---------           --------- \n";
ostrm << "       waveguide        ----------          -----------\n";
ostrm << "                       -----------         -------------\n";
ostrm << "                                                 +\n";
ostrm << "                                    centerline   + \n";
ostrm << "                                                 +\n";
ostrm << "                       -----------         -------------\n";
ostrm << "                        \\  LENS  |         \\   LENS    /\n";
ostrm << "       waveguide         \\ PLATE |    ^     \\  PLATE  /\n";
ostrm << "        _____             \\      |    |      \\       / \n";
ostrm << "       |     | <           )<--->|   E|       )<-+->(  \n";
ostrm << "        -----  horn       / min. |    |      /  min. \\ \n";
ostrm << "                      -->/ thick.|       -->/  thick. \\ \n";
ostrm << "                     /  /        |      /  /           \\ \n";
ostrm << "                    /  -----------     /   -------------\n";
ostrm << "                   /                  /                 \n";
ostrm << "                   Radius of curvature            \n\n\n";
}
    





// ****** end of ANTENNA.CPP file



// start of HDL_ANT.CPP 





//forward declarations
int KeyEvent(void);
void menu();
void pdish();
void odish();
void mlens();
void range();
void newhorn();
void oldhorn();
void feedhorn();
void nf_corr();
void noise_sky_ground();
void info();
void postinfo();
void english_units();
void conhorn();
void con_opt();
void o_curfit();
void imu_horn();
void imu_horn();

int main()
{

    Antenna start;
    start.banner(cout);

    cout << "\n HDL_ANT v3.0 *BETA* - designs, makes calculations, and draws \n"
	 << "            construction templates for microwave \n"
         << "            horn, lens, and parabolic dish antennas. \n\n";
//	 << " N1BWT 1998 \n\n";
//pause
    char pause;
    cout << "Hit <ENTER> key to continue";
    cout.flush();
    cin.setf(0,ios::skipws);
    cin >> pause;
    cin.setf(1,ios::skipws);

    int k = 0;
    menu();
    
    while ( (k = KeyEvent() ) != CTRL_C)
   {
	if (k)
	{

	   // Mask out the key's scan code.
	   k &= 0x00ff;
	   char mode = (char)k;

	   mode = toupper(mode);
        
	    switch(mode)
            {
                case 'H':   newhorn(); break;    
                case 'E':   oldhorn(); break;
		case 'D':   pdish(); break;
                case 'L':   mlens(); break;
		case 'R':   range(); break;
		case 'M':   nf_corr(); break;
		case 'I':   info(); break;
		case 'P':   postinfo(); break;
                case 'U':   english_units(); break;
                case 'Q':   return 0;
                case 'O':   odish(); break;
                case 'F':   feedhorn(); break;
                case 'N':   noise_sky_ground(); break;
//new
                case 'C':   conhorn(); break;
                case 'G':   con_opt(); break;
                case 'T':   o_curfit(); break;
                case 'W':   imu_horn(); break;
                
                default: cout  << "Huh?"; break;
	    }

            char pause;
            cout << "\n\nEnter C to continue: ";
	    cout.flush();
	    cin >> pause;

	    menu();
        }             
    }
   return 0;
}
                 
void menu()             // just prints a menu to select from
{                

// clearscreen and reset xy
//        textmode(MONO);
	clrscr();
        gotoxy(1,1);


	cout << "\n"
	  << "Enter first letter for selection \n\n"
          << "   Horn antenna design and template\n"
          << "   Existing horn antenna calculations\n"
          << "   Dish antenna calculations and template\n"
          << "   Lens antenna design\n"
          << "   Range design for antenna measurement\n"
//          << "   Corrections for antenna measurements\n"
          << "   Measurement corrections for antennas \n"
          << "   Information about HDL_ANT v3 program\n"
          << "   PostScript printing information\n"
          << "   Offset dish calculations\n"
          << "   Feed horn design  (rectangular - from G3RPE curves)\n"
          << "   Noise Figure from sky and ground noise\n"
          << "   Units: Metric [default] or English\n"
          << "\nNew***\n\n"
          << "   Conical horn antenna calculations and template\n"
          << "   Generate an optimal conical horn design and template\n"
          << "   Trial curve fitting points for offset dish\n"
          << "   W2IMU dual-mode feedhorn calculations\n"
          <<"\n"
          
          << "   Quit\n";
}

int KeyEvent(void)
{
    // Check for key press.
	 unsigned key = bioskey(1);
    
    // Get key if one is  available.
    if (key) key = bioskey(0);
    
    return key;
    
}


void pdish()
{
    cout << "\n\nPARABOLIC DISH ANTENNA CALCULATIONS AND TEMPLATE GENERATION\n\n";
    Dish d;
    d.get_freq();
    d.d_init();
    d.illumination();
    d.calc_gain();   
    char mode = 'n';
    cout << "\nDo you want to make a PostScript template [Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y') d.PS_template();
}


void odish()
{
    cout << "\n\nOFFSET PARABOLIC DISH ANTENNA CALCULATIONS \n\n";
    OffsetDish od;
    od.get_freq();
//    od.offset_init(); // old routine
    od.offset_init2();
    od.three_points();
    od.display_results();
    od.offset_illumination();
    od.offset_calc_gain();
}

void o_curfit()
{
    cout << "\n\nTRIAL CURVE_FITTING FOR OFFSET PARABOLIC DISH ANTENNA \n\n";
    OffsetDish od;
    od.get_freq();
    od.offset_init2();
    od.curve_fit();
    od.display_results();
    od.offset_illumination();
    od.offset_calc_gain();
}



void newhorn()
{
    cout << "\n\nDESIGN A HORN ANTENNA AND GENERATE A CONSTRUCTION TEMPLATE\n\n";
    char mode = 'Y';
    Horn a;
    a.get_freq();
    a.get_wg();
    if (a.bad_input() >= 3) goto end;
    a.lookup();

    while (mode == 'Y')
    {
        a.simple_gain();
        a.horn_angles();
        a.horn_calcgain();
        a.horn_phasecenters();
	a.write_data(cout,1);

        cout << "\nDo you want to change horn dimensions [Yes or No]?  ";
	cout.flush();
	cin >> mode ;
        mode = toupper(mode);

        if (mode == 'Y') a.horn_dimensions();
    }

    mode = 'n';
    cout << "\nDo you want to make a PostScript template [Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
    {
        a.coords();
        a.PS_template();
    }

    end: ;
}


void oldhorn()
{
    cout << "\n\nHORN ANTENNA CALCULATIONS AND CONSTRUCTION TEMPLATE "
         << "GENERATION\n\n";
    char mode = 'n';
    Horn a;
    a.get_freq();
    a.get_wg();
    if (a.bad_input() >= 3) goto end;
    a.horn_dimensions();
    a.check_aperture();
    if (a.bad_input() >= 3) goto end;

    a.simple_gain();
    a.horn_angles();
    a.horn_calcgain();
    a.horn_phasecenters();
    a.write_data(cout,1);

    cout << "\nDo you want to make a PostScript template [Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
    {
        a.coords();
        a.PS_template();
    }

    end: ;
}

void feedhorn()
{
    cout << "\n\nDESIGN A RECTANGULAR FEEDHORN FROM G3RPE CURVES \n"
         << " AND GENERATE A CONSTRUCTION TEMPLATE\n\n";
    char mode = 'Y';
    Horn fh;
    fh.get_freq();
    fh.get_wg();
    if (fh.bad_input() >= 3) goto end;

    double target_f_over_D;    
    cout << "\nEnter f/D to be illuminated: " ;
    cout.flush();
    cin >> target_f_over_D;
    
    fh.G3RPE_approximation(target_f_over_D);
    fh.check_aperture();
    if (fh.bad_input() >= 3) goto end;

    while (mode == 'Y')
    {
        fh.simple_gain();
        fh.horn_angles();
        fh.horn_calcgain();
        fh.horn_phasecenters();
	fh.write_data(cout,1);

        cout << "\nDo you want to change horn dimensions [Yes or No]?  ";
	cout.flush();
	cin >> mode ;
        mode = toupper(mode);

        if (mode == 'Y') fh.horn_dimensions();
    }

    mode = 'n';
    cout << "\nDo you want to make a PostScript template [Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
    {
        fh.coords();
        fh.PS_template();
    }

    end: ;
}


void mlens()
{
    cout << "\n\nMETAL PLATE LENS ANTENNA DESIGN\n\n";
    char mode = 'n';
    Lens m;
    m.get_freq();
    m.dimension();
    if (m.bad_input() >= 3) goto end;
    m.get_wg();
    m.horn_dimensions();
    m.horn_angles();
    m.horn_calcgain();
    m.calculate();
    m.horn_phasecenters();
    m.phasecheck();
    m.write_data(cout,1);

// set up output file if desired;

    cout << " Save this lens design to file (yes or NO) ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
    {
	char  outname[LINESIZE];
        cout << "\nEnter output filename: " ;
	cout.flush();
	cin >> outname ;
    
        ofstream ostrm(outname);

        m.banner(ostrm);
	m.write_data(ostrm,0);
        m.crude_graphics(ostrm);
    }
    end: ;
}

void range()
{
    cout << "\n\nANTENNA RANGE DESIGN CALCULATIONS\n\n";
    Antenna range;
    range.get_freq();
    range.range_calc();
}

void nf_corr()
{
    cout << "\n\n Correction of PANFI readings to Antenna Gain\n\n";
    Antenna c;
    c.get_freq();
    c.PANFI_corr();
}

void noise_sky_ground()
{
    cout << "\nTo calculate Noise Figure by comparing noise received \n"
         << "from cold sky and warm ground:\n";
    Antenna n;
    n.sun_gnd_NF();
}

void conhorn()
{
    cout << "\n\nCONICAL HORN ANTENNA CALCULATIONS AND CONSTRUCTION TEMPLATE "
         << "GENERATION\n\n";
    Conical_horn con;
    con.get_freq();
    con.dimensions();
    con.simple_gain();
    con.gain();
    
    char mode = 'n';
    cout << "\nDo you want to make a PostScript template [Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
        con.PS_template();
}

void con_opt()
{
    cout << "\n\nOPTIMAL CONICAL HORN ANTENNA DESIGN AND CONSTRUCTION TEMPLATE "
         << "GENERATION\n\n";
    Conical_horn con;
    con.get_freq();
    con.optimum_horn();
//    con.simple_gain();
    con.gain();
    
    char mode = 'n';
    cout << "\nDo you want to make a PostScript template [Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
        con.PS_template();
}

void imu_horn()
{
    cout << "\n\nW2IMU Dual-mode FEEDHORN CALCULATIONS AND CONSTRUCTION TEMPLATE "
         << "GENERATION\n\n";
    Conical_horn imu;
    imu.get_freq();
    imu.W2IMU_feedhorn();
    
    char mode = 'n';
    cout << "\nDo you want to make a PostScript template " 
         << "for the flare section[Yes or No]?  ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
        imu.PS_template();
}

void info()
{
    Antenna info;
    info.banner(cout);    
    info.info_listing(cout);

// set up output file if desired;

    char mode;
    cout << " \n\nWrite this information to file (Yes or No) ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
    {
	char outname[LINESIZE];
        cout << "\nEnter output filename: " ;
	cout.flush();
	cin >> outname ;
    
        ofstream ostrm(outname);

        info.banner(ostrm);
        info.info_listing(ostrm);
    }
}

void postinfo()
{
    Antenna pp;
    pp.post_print(cout);

// set up output file if desired;

//    char mode;
//    cout << " \n\nWrite this information to file (Yes or No) ";
//    cout.flush();
//    cin >> mode ;
//    mode = toupper(mode);

//    if (mode == 'Y')
//    {
	char outname[LINESIZE];
        cout << "\nEnter output filename: " ;
	cout.flush();
	cin >> outname ;
    
        ofstream ostrm(outname);

        pp.post_print(ostrm);
//    }
}

void english_units()
{
    char mode;

    cout << " \n\nCurrently using " << unit_type 
         << " units for dimensions\n";
    
    cout << " \n\nChange to alternate units(Yes or No) ";
    cout.flush();
    cin >> mode ;
    mode = toupper(mode);

    if (mode == 'Y')
    {
        if (metric == 1.0)  // change to English
        {
            metric = 25.4;
	    units = " inches ";
	    unit_type = "English";
	}
	else                // change to metric
	{
	    metric = 1.0;
	    units = " mm.  ";
            unit_type = "Metric ";
        }
    }
}
         
    

// end of HDL_ANT.CPP 
