// shadow1 - HP Prime

// shadow conditions of Earth satellites in circular orbits

// Kozai j2 orbit propagation

//////////////////////////////

// support routines

sun1();

julian();

r2r();

round();

atan3();

EXPORT shadow1()

BEGIN

LOCAL dtr := pi / 180.0;

LOCAL rtd := 180.0 / pi;

// earth gravitational constant (kilometers^3/second^2)

LOCAL mu := 398600.436233;

// earth equatorial radius (kilometers)

LOCAL req := 6378.1363;

// earth oblateness gravity coefficient (non-dimensional)

LOCAL j2 := 0.00108263;

LOCAL month, day, year, alt, sma, ecc, period;

LOCAL inc, orbinc, raan, raan0, raani, raan_dot;

LOCAL ndays, dstep, sinc, cinc, sraan, craan, mm, pmm;

LOCAL slr, b, c, d, e;

LOCAL rtmp, rratio, stim, npts, teclipse;

LOCAL beta, bmin, bmax, tmin, tmax, tsum, jdate;

LOCAL usun := [0, 0, 0];

// circular orbits - zero eccentricity

ecc := 0.0;

// request initial calend;ar date

INPUT({month, day, year}, "input month, day, year");

// request initial circular orbit altitude (kilometers)

INPUT(alt, "input circular orbit altitude (km)");

// semimajor axis (kilometers)

sma := req + alt;

// orbital period (minutes)

period := 2.0 * pi * sma * sqrt(sma / mu) / 60.0;

// request orbital inclination (degrees)

INPUT(inc, "input orbital inclination (degrees)");

orbinc := inc * dtr;

// request initial RAAN (degrees)

INPUT(raan, "input initial RAAN (degrees)");

raan0 := raan;

raani := raan * dtr;

// request simulation duration (days)

INPUT(ndays, "input simulation duration (days)");

// simulation step size (minutes)

INPUT(dstep, "input simulation step size (minutes)");

print();

print("PROGRAM SHADOW1");

// calculate initial julian day

jdatei := julian(month, day, year);

// perform satellite initialization

sinc := sin(orbinc);

cinc := cos(orbinc);

// mean motion and semiparameter

mm := sqrt(mu / (sma * sma * sma));

slr := sma * (1.0 - ecc * ecc);

b := sqrt(1.0 - ecc * ecc);

c := req / slr;

d := c * c;

e := sinc * sinc;

// perturbed mean motion (radians/second)

pmm := mm * (1 + 1.5 * j2 * d * b * (1 - 1.5 * e));

// raan perturbation (radians/second)

raan_dot := -1.5 * j2 * pmm * d * cinc;

// convert raan_dot to radians/minute

raan_dot := 60.0 * raan_dot;

// increase the Earth's equatorial radius by 2 percent
// to account for the thickness of the atmosphere

rtmp := 1.02 * req;

rratio := rtmp / (req + alt);

// initialization

stim := -dstep;

bmin := 1.0e99;
bmax := -1.0e99;
tmin := 1.0e99;
tmax := -1.0e99;

tsum := 0;

// begin main simulation

npts := 0;

REPEAT

    npts := npts + 1;
    
    stim := stim + dstep;

    jdate := jdatei + stim / 1440.0;

    // compute solar unit position vector

    usun := sun1(jdate);

    // update raan

    raan := (raani + raan_dot * stim) mod (2.0 * pi);

    craan := cos(raan);
    
    sraan := sin(raan);

    // compute beta angle and eclipse duration

    beta := (asin(sraan * sinc * usun(1) - craan * sinc * usun(2) + cinc * usun(3)));

    teclipse := (acos(sqrt(1.0 - rratio ^ 2) / cos(beta))) * period / pi;

    // find min and max beta and duration conditions

    if (beta > bmax) then
    
        bmax := beta;
        
    end;

    if (beta < bmin) then
    
        bmin := beta;
        
    end;

    if (teclipse > tmax) then
    
        tmax := teclipse;
        
    end;

    if (teclipse < tmin) then
    
        tmin := teclipse;
        
    end;

    tsum := tsum + teclipse;

    // check for end of simulation

UNTIL (stim >= 1440.0 * ndays);

print();

print("SHADOW CONDITIONS OF EARTH SATELLITES IN CIRCULAR ORBITS");

print(" ");

print("circular orbit altitude  " + round(alt, 4) + " kilometers");

print(" ");

print("orbital inclination      "  + round(inc, 4) + " degrees");

print(" ");

print("initial RAAN             " + round(raan0, 4) + " degrees");

print(" ");

print("Keplerian period         " + round(period, 4) + " minutes");

print(" ");

print("minimum beta angle       " + round(rtd * bmin, 4) + " degrees");

print(" ");

print("maximum beta angle       " + round(rtd * bmax, 4) + " degrees");

print(" ");

print("minimum shadow duration  " + round(tmin, 4) + " minutes");

print(" ");

print("maximum shadow duration  " + round(tmax, 4) + " minutes");

print(" ");

print("average shadow duration  " + round(tsum / npts, 4) + " minutes");

END;

///////////
///////////

sun1(jdate)

// solar ephemeris

// input
    
//  jdate = julian day

// output

//  usun = eci unit position vector of the sun (kilometers)

// note

//  coordinates are inertial, geocentric,
//  equatorial and true-of-date

///////////////////////////////

BEGIN

// arc seconds-to-radians conversion factor

LOCAL atr := pi / 648000.0;

LOCAL rsun := [0, 0, 0];

LOCAL usun := [0, 0, 0];

LOCAL djd, t, gs, lm, ls, g2, g4, g5;

LOCAL rm, a, b, plon, rsm, obliq;

LOCAL rasc, decl;

// time arguments

djd := jdate - 2451545.0;

t := (djd / 36525.0) + 1.0;

// fundamental arguments (radians)

gs := r2r(0.993126 + 0.00273777850 * djd);
lm := r2r(0.606434 + 0.03660110129 * djd);
ls := r2r(0.779072 + 0.00273790931 * djd);
g2 := r2r(0.140023 + 0.00445036173 * djd);
g4 := r2r(0.053856 + 0.00145561327 * djd);
g5 := r2r(0.056531 + 0.00023080893 * djd);
rm := r2r(0.347343 - 0.00014709391 * djd);

// geocentric, ecliptic longitude of the sun (radians)

plon := 6910 * sin(gs) + 72 * sin(2 * gs) - 17 * t * sin(gs);
plon := plon - 7 * cos(gs - g5) + 6 * sin(lm - ls) + 5 * sin(4 * gs - 8 * g4 + 3 * g5);
plon := plon - 5 * cos(2 * (gs - g2)) - 4 * (sin(gs - g2) - cos(4 * gs - 8 * g4 + 3 * g5));
plon := plon + 3 * (sin(2 * (gs - g2)) - sin(g5) - sin(2 * (gs - g5)));
plon := ls + atr * (plon - 17 * sin(rm));

// geocentric distance of the sun (kilometers)

rsm := 149597870.691 * (1.00014 - 0.01675 * cos(gs) - 0.00014 * cos(2.0 * gs));

// obliquity of the ecliptic (radians)

obliq := atr * (84428.0 - 47.0 * t + 9.0 * cos(rm));

// geocentric, equatorial right ascension and declination (radians)

a := sin(plon) * cos(obliq);
b := cos(plon);
   
rasc := atan3(a, b);

decl := asin(sin(obliq) * sin(plon));

// geocentric unit position vector of the sun (kilometers)

usun(1) := cos(rasc) * cos(decl);
usun(2) := sin(rasc) * cos(decl);
usun(3) := sin(decl);

return usun;

END;

//////////////////
//////////////////

atan3(a, b)

// four quadrant inverse tangent

// input

//  a = sine of angle
//  b = cosine of angle

// output

//  0 =< angle <= 2p

////////////////////

BEGIN

LOCAL epsilon := 0.0000000001;

LOCAL pidiv2 := 0.5 * pi;

LOCAL c;

if (abs(a) < epsilon) then

    return (1.0 - sign(b)) * pidiv2;

else

    c := (2.0 - sign(a)) * pidiv2;

end;

if (abs(b) < epsilon) then

    return c;

else

    return c + sign(a) * sign(b) * (abs(atan(a / b)) - pidiv2);

end;

END;

//////
//////

r2r(x)

// revolutions to radians function
   
// input

//  x = argument (revolutions; 0 <= x <= 1)

// output

//  y = equivalent x (radians; 0 <= y <= 2 pi)

BEGIN

return 2.0 * pi * (x - IP(x));

END;

////////////////////////
////////////////////////

julian(month, day, year)

// Julian date

// input

//  month = calendar month [1 - 12]
//  day   = calendar day [1 - 31]
//  year  = calendar year [yyyy]

// output

//  julian date

// special notes

//  (1) calendar year must include all digits

//  (2) calendar day may include fractional part

//  (3) will report October 5, 1582 to October 14, 1582
//      as invalid calendar date and return

////////////////////////////////////////////

BEGIN

LOCAL y := year, m := month, a := 0, b := 0, c := 0, jd;

// check for valid calendar date

if (year == 1582 and month == 10) then

   if (day >= 5 and day <= 14) then

      MSGBOX("invalid calendar date!");

      return;

   end;

end;

if (m <= 2) then

   y := y - 1.0;

   m := m + 12.0;

end;

if (y < 0) then

   c := -0.75;

end;

if (year > 1582) then

   a := floor(y / 100);

   b := 2.0 - a + floor(a / 4);

end;

if (month > 10) then

   a := floor(y / 100);

   b := 2 - a + floor(a / 4);

end;

if (day > 14) then

   a := floor(y / 100);

   b := 2 - a + floor(a / 4);

end;

jd := floor(365.25 * y + c) + floor(30.6001 * (m + 1));
    
return jd + day + b + 1720994.5;

END;

///////////
///////////

round(x, n)

// round number function

// input

//  x = real, floating point number
//  n = number of decimal places

// output

// round = x rounded to n decimal places

////////////////////////////////////////

BEGIN

LOCAL a;

a := 10.0 ^ (-n);

return floor(x / a + 0.5) * a;

END;

