ANTENA RASTREÁVEL
Autor: Unknown | Publicado: 2012-02-08T16:16:00-02:00

DIRECIONAMENTO DE ANTENA PARABÓLICA UNIVERSAL


(Estes dados são do Site http://ghiorzi.org/satelite.htm&nbsp;para serem difundidos e usados por Satentusiastas&nbsp;da lingua Portuguesa - De Ghiorzi Telmo, Cláudio Roberto Ghiorzi e o filme foi elaborado por seu filho André Germani Ghiorzi)




OS ÂNGULOS "X" e "Y"
Calcule o direcionamento de uma antena parabólica universal, apta a rastrear todos os satélites geoestacionários existentes no seu campo de visão. Use a rotina abaixo, integralmente desenvolvida pelo autor da página. Você terá como resposta os ângulos "X" e "Y" indicados no desenho abaixo. Consideramos, nesses cálculos, o raio da circunferência da Terra no equador igual a 6.378,16km e a órbita dos satélites acima do equador igual a 35.786km. Levamos em conta também, por óbvio, a excentricidade do eixo de rastreamento, que desaparece nos polos e que só é indiferente na linha do equador. Nas demais situações, há de haver a correção, pelo fato de a antena estar excêntrica ao eixo da Terra. Não se preocupe: Esta correção está contemplada na fórmula.

Introduza a Latitude de sua cidade, com frações decimais. Exemplo: 27.8 (27º48') que produz os resultados X=4.072 e Y=28.3844. O sinal "+" ou "-" é indiferente, seja para latitudes acima ou abaixo da linha do equador. Os resultados "X" e "Y" serão também em graus decimais.



Os valores de "a" e "b" serão úteis mais tarde, se você quiser construir o inclinômetro descrito mais abaixo.











OS LIMITES DE FUNCIONAMENTO
Teoricamente, nos polos (latitude 90 graus) o ângulo X é igual a 8,6019 graus e o ângulo Y é igual a 90 graus, mas, por causa da curvatura da Terra, a antena só "enxergaria" os satélites se estivesse sobre uma torre de altura igual a 74,2507km. No nível do solo, a maior latitude em que os satélites são "visíveis" é igual a 81,2995 graus.

O NORTE VERDADEIRO
Além dos ângulos X e Y (ver o desenho), o terceiro fator importantíssimo é a determinação do Norte verdadeiro (linha do meridiano), a partir da longitude de sua cidade. A forma mais simples, mais eficaz e mais precisa de fazê-lo é obter o horário do "trânsito" do Sol pelo meridiano (o "sol a pino"), na data e local da instalação da antena. Nesse momento (em torno das doze horas), a sombra de um poste aprumado em um lugar plano indicará com absoluta precisão a direção Norte/Sul. Se você estiver na zona tropical e a sombra do poste, no "trânsito", for praticamente nula, use o artifício de marcar dois momentos de sombra, um, por exemplo, três horas antes do "trânsito" e outro três horas depois do "trânsito". A bissetriz do ângulo formado indicará a direção Norte/Sul.

Use a rotina abaixo para calcular o "trânsito" do Sol em sua cidade.

Introduza a Longitude de sua cidade (Graus com sinal "-" se você estiver a Leste de Greenwich), ou selecione na lista prévia. Se for o caso, altere o Fuso Horário (sinal "-" se você estiver a Leste de Greenwich) e mude a data. Atenção: Se a sua cidade não estiver na lista é imprescindível selecionar "A sua cidade →" e sobreescrever os dados que porventura tiverem sido registrados antes.&nbsp;

//*********************************************************************/


 function setLatLong(f, index)
 {
  // Decimal degrees are passed in the array.  Temporarily store these 
  // degs in lat and lon deg and have convLatLong modify them.

  f["latDeg"].value = City[index].lat;
  f["lonDeg"].value = City[index].lng;
 
  // These are needed to prevent iterative adding of min and sec when 
  // set button is clicked.

  f["latMin"].value = 0;
  f["latSec"].value = 0;
  f["lonMin"].value = 0;
  f["lonSec"].value = 0;
  
  //call convLatLong to convert decimal degrees into table form.

  convLatLong(f);

  //Local time zone value set in table

  f["hrsToGMT"].value =  City[index].zoneHr;
 }


//*********************************************************************/

// isLeapYear returns 1 if the 4-digit yr is a leap year, 0 if it is not

 function isLeapYear(yr) 
 {
  return ((yr % 4 == 0 && yr % 100 != 0) || yr % 400 == 0);
 }


//*********************************************************************/

// isPosInteger returns false if the value is not a positive integer, true is
// returned otherwise.  The code is from taken from Danny Goodman's Javascript
// Handbook, p. 372.

 function isPosInteger(inputVal) 
 {
  inputStr = ("" + inputVal);
  for (var i = 0; i < inputStr.length; i++) {
   var oneChar = inputStr.charAt(i);
   if (oneChar < "0" || oneChar > "9")
    return false;
  }
  return true;
 }

//*********************************************************************/

 function isInteger(inputVal) 
 {
  inputStr = "" + inputVal;
  if(inputStr == "NaN") return false;
  if(inputStr == "-NaN") return false;
  for (var i = 0; i < inputStr.length; i++) 
  {
   var oneChar = inputStr.charAt(i);
   if (i == 0 && (oneChar == "-" || oneChar == "+"))
   {
    continue;
   }
   if (oneChar < "0" || oneChar > "9")
   {
    return false;
   }
  }
  return true;
 }


//*********************************************************************/

 function isNumber(inputVal) 
 {
  var oneDecimal = false;
  var inputStr = "" + inputVal;
  for (var i = 0; i < inputStr.length; i++) 
  {
   var oneChar = inputStr.charAt(i);
   if (i == 0 && (oneChar == "-" || oneChar == "+"))
   {
    continue;
   }
   if (oneChar == "." && !oneDecimal) 
   {
    oneDecimal = true;
    continue;
   }
   if (oneChar < "0" || oneChar > "9")
   {
    return false;
   }
  }
  return true;
 }


//*********************************************************************/

// isValidInput makes sure valid input is entered before going ahead to 
// calculate the sunrise and sunset.  False is returned if an invalid entry 
// was made, true is the entry is valid.

 function isValidInput(f, index, latLongForm) 
 {
  if (f["day"].value == "") 
  { // see if the day field is empty
   alert("Você deve introduzir um dia.");
   return false;
  }
  else if (f["year"].value == "") 
  { //  see if the year field is empty
   alert("Você deve introduzir um ano.");
   return false;
  }
  else if (!isPosInteger(f["day"].value) || f["day"].value == 0)
  {
   alert("O dia deve ser um número inteiro, positivo.");
   return false;
  }
  else if (!isInteger(f["year"].value)) 
  {
   alert("O ano deve ser um número inteiro.");
   return false;
  }
  else if ( (f["year"].value < -1000) || (f["year"].value > 3000) )
  {
   alert("A fórmula não é válida para ano menor do que\n -1000 ou maior do que 3000.");

   return false;
  }


  // For the non-February months see if the day entered is greater than
  // the number of days in the selected month

  else if ((index != 1) && (f["day"].value > monthList[index].numdays)) 
  {
   alert("Há apenas " + monthList[index].numdays + " dias em " 
    + monthList[index].name + ".");
   return false;
  }

  // First see if the year entered is a leap year.  If so we have to make sure
  // the days entered is <= 29.  If not a leap year we make sure that the days
  // entered is <= 28.

  else if (index == 1) 
  { //  month selected is February the screwball month
   if (isLeapYear(f["year"].value)) { // year entered is a leap year
    if (f["day"].value > (monthList[index].numdays + 1)) 
    {
     alert("Há apenas " + (monthList[index].numdays + 1) 
      + " dias em " + monthList[index].name + ".");
     return false;
    }
    else
     return true;
   }
   else 
   { // year entered is not a leap year
    if (f["day"].value > monthList[index].numdays) 
    {
     alert("Há apenas " + monthList[index].numdays 
      + " dias em " + monthList[index].name + ".");

     return false;
    }
    else
     return true;
   }
  }
  else 
   return true; 
 }

//*********************************************************************/

//convLatLong converts any type of lat/long input
//into  the table form and then handles bad input
//it is nested in the calcSun function.

 function convLatLong(f)
 {
  if(f["latDeg"].value == "")
  {
   f["latDeg"].value = 0;
  }
  if(f["latMin"].value == "")
  {
   f["latMin"].value = 0;
  }
  if(f["latSec"].value == "")
  {
   f["latSec"].value = 0;
  }
  if(f["lonDeg"].value == "")
  {
   f["lonDeg"].value = 0;
  }
  if(f["lonMin"].value == "")
  {
   f["lonMin"].value = 0;
  }
  if(f["lonSec"].value == "")
  {
   f["lonSec"].value = 0;
  }

  var neg = 0;
  if(f["latDeg"].value.charAt(0) == '-') 
  {
   neg = 1;
  }

  if(neg != 1)
  {
   var latSeconds = (parseFloat(f["latDeg"].value))*3600 
    + parseFloat(f["latMin"].value)*60 
    + parseFloat(f["latSec"].value)*1;

   f["latDeg"].value = Math.floor(latSeconds/3600);
   f["latMin"].value = Math.floor((latSeconds
    - (parseFloat(f["latDeg"].value)*3600))/60);
   f["latSec"].value = Math.floor((latSeconds
    - (parseFloat(f["latDeg"].value)*3600) 
    - (parseFloat(f["latMin"].value)*60)) + 0.5);
  }
  else if(parseFloat(f["latDeg"].value) > -1)
  {
   var latSeconds = parseFloat(f["latDeg"].value)*3600 
    - parseFloat(f["latMin"].value)*60 
    - parseFloat(f["latSec"].value)*1;

   f["latDeg"].value = "-0";
   f["latMin"].value = Math.floor((-latSeconds)/60);
   f["latSec"].value = Math.floor( (-latSeconds 
    - (parseFloat(f["latMin"].value)*60)) + 0.5);

  }
  else
  {
   var latSeconds = parseFloat(f["latDeg"].value)*3600 
    - parseFloat(f["latMin"].value)*60 
    - parseFloat(f["latSec"].value)*1;

   f["latDeg"].value = Math.ceil(latSeconds/3600);
   f["latMin"].value = Math.floor((-latSeconds
    + (parseFloat(f["latDeg"].value)*3600))/60);
   f["latSec"].value = Math.floor((-latSeconds
    + (parseFloat(f["latDeg"].value)*3600) 
    - (parseFloat(f["latMin"].value)*60)) + 0.5);
  }

  neg = 0;
  if(f["lonDeg"].value.charAt(0) == '-') 
  {
   neg = 1;
  }

  if(neg != 1)
  {
   var lonSeconds = parseFloat(f["lonDeg"].value)*3600 
    + parseFloat(f["lonMin"].value)*60 
    + parseFloat(f["lonSec"].value)*1;
   f["lonDeg"].value = Math.floor(lonSeconds/3600);
   f["lonMin"].value = Math.floor((lonSeconds
    - (parseFloat(f["lonDeg"].value)*3600))/60);
   f["lonSec"].value = Math.floor((lonSeconds
    - (parseFloat(f["lonDeg"].value)*3600)
    - (parseFloat(f["lonMin"].value))*60) + 0.5);
  }
  else if(parseFloat(f["lonDeg"].value) > -1)
  {
   var lonSeconds = parseFloat(f["lonDeg"].value)*3600 
    - parseFloat(f["lonMin"].value)*60 
    - parseFloat(f["lonSec"].value)*1;

   f["lonDeg"].value = "-0";
   f["lonMin"].value = Math.floor((-lonSeconds)/60);
   f["lonSec"].value = Math.floor((-lonSeconds
    - (parseFloat(f["lonMin"].value)*60)) + 0.5);
  }
  else
  {
   var lonSeconds = parseFloat(f["lonDeg"].value)*3600 
    - parseFloat(f["lonMin"].value)*60 
    - parseFloat(f["lonSec"].value)*1;
   f["lonDeg"].value = Math.ceil(lonSeconds/3600);
   f["lonMin"].value = Math.floor((-lonSeconds
    + (parseFloat(f["lonDeg"].value)*3600))/60);
   f["lonSec"].value = Math.floor((-lonSeconds
    + (parseFloat(f["lonDeg"].value)*3600)
    - (parseFloat(f["lonMin"].value)*60)) + 0.5);
  }

  //Test for invalid lat/long input

  if(latSeconds > 324000)
  {
   alert("Você introduziu uma latitude inválida.\n  Assumimos 89.8.");
   f["latDeg"].value = 89.8;
   f["latMin"].value = 0;
   f["latSec"].value = 0;
  }
  if(latSeconds < -324000)
  {
   alert("Você introduziu uma latitude inválida.\n  Assumimos -89.8.");
   f["latDeg"].value = -89.8;
   f["latMin"].value = 0;
   f["latSec"].value = 0;
  }
  if(lonSeconds > 648000)
  {
   alert("Você introduziu uma longitude inválida.\n Assumimos 180.");
   f["lonDeg"].value = 180;
   f["lonMin"].value = 0;
   f["lonSec"].value = 0;
  }
  if(lonSeconds < -648000)
  {
   alert("Você introduziu uma longitude inválida.\n Assumimos -180.");

   f["lonDeg"].value = -180;
   f["lonMin"].value = 0;
   f["lonSec"].value =0;
  }

 }



//***********************************************************************/
//***********************************************************************/
//*            */
//*This section contains subroutines used in calculating solar position */
//*            */
//***********************************************************************/
//***********************************************************************/

// Convert radian angle to degrees

 function radToDeg(angleRad) 
 {
  return (180.0 * angleRad / Math.PI);
 }

//*********************************************************************/

// Convert degree angle to radians

 function degToRad(angleDeg) 
 {
  return (Math.PI * angleDeg / 180.0);
 }

//*********************************************************************/


//***********************************************************************/
//* Name:    calcDayOfYear        */
//* Type:    Function         */
//* Purpose: Finds numerical day-of-year from mn, day and lp year info  */
//* Arguments:          */
//*   month: January = 1        */
//*   day  : 1 - 31         */
//*   lpyr : 1 if leap year, 0 if not      */
//* Return value:          */
//*   The numerical day of year       */
//***********************************************************************/

 function calcDayOfYear(mn, dy, lpyr) 
 {
  var k = (lpyr ? 1 : 2);
  var doy = Math.floor((275 * mn)/9) - k * Math.floor((mn + 9)/12) + dy -30;
  return doy;
 }


//***********************************************************************/
//* Name:    calcDayOfWeek        */
//* Type:    Function         */
//* Purpose: Derives weekday from Julian Day     */
//* Arguments:          */
//*   juld : Julian Day         */
//* Return value:          */
//*   String containing name of weekday      */
//***********************************************************************/

 function calcDayOfWeek(juld)
 {
  var A = (juld + 1.5) % 7;
  var DOW = (A==0)?"Sunday":(A==1)?"Monday":(A==2)?"Tuesday":(A==3)?"Wednesday":(A==4)?"Thursday":(A==5)?"Friday":"Saturday";
  return DOW;
 }


//***********************************************************************/
//* Name:    calcJD         */
//* Type:    Function         */
//* Purpose: Julian day from calendar day      */
//* Arguments:          */
//*   year : 4 digit year        */
//*   month: January = 1        */
//*   day  : 1 - 31         */
//* Return value:          */
//*   The Julian day corresponding to the date     */
//* Note:           */
//*   Number is returned for start of day.  Fractional days should be */
//*   added later.         */
//***********************************************************************/

 function calcJD(year, month, day)
 {
  if (month <= 2) {
   year -= 1;
   month += 12;
  }
  var A = Math.floor(year/100);
  var B = 2 - A + Math.floor(A/4);

  var JD = Math.floor(365.25*(year + 4716)) + Math.floor(30.6001*(month+1)) + day + B - 1524.5;
  return JD;
 }



//***********************************************************************/
//* Name:    calcDateFromJD        */
//* Type:    Function         */
//* Purpose: Calendar date from Julian Day     */
//* Arguments:          */
//*   jd   : Julian Day         */
//* Return value:          */
//*   String date in the form DD-MONTHNAME-YYYY     */
//* Note:           */
//***********************************************************************/

 function calcDateFromJD(jd)
 {
  var z = Math.floor(jd + 0.5);
  var f = (jd + 0.5) - z;

  if (z < 2299161) {
   var A = z;
  } else {
   alpha = Math.floor((z - 1867216.25)/36524.25);
   var A = z + 1 + alpha - Math.floor(alpha/4);
  }

  var B = A + 1524;
  var C = Math.floor((B - 122.1)/365.25);
  var D = Math.floor(365.25 * C);
  var E = Math.floor((B - D)/30.6001);

  var day = B - D - Math.floor(30.6001 * E) + f;
  var month = (E < 14) ? E - 1 : E - 13;
  var year = (month > 2) ? C - 4716 : C - 4715;

  // alert ("date: " + day + "-" + monthList[month-1].name + "-" + year);
  return (day + "-" + monthList[month-1].name + "-" + year);
 }


//***********************************************************************/
//* Name:    calcDayFromJD        */
//* Type:    Function         */
//* Purpose: Calendar day (minus year) from Julian Day   */
//* Arguments:          */
//*   jd   : Julian Day         */
//* Return value:          */
//*   String date in the form DD-MONTH      */
//***********************************************************************/

 function calcDayFromJD(jd)
 {
  var z = Math.floor(jd + 0.5);
  var f = (jd + 0.5) - z;

  if (z < 2299161) {
   var A = z;
  } else {
   alpha = Math.floor((z - 1867216.25)/36524.25);
   var A = z + 1 + alpha - Math.floor(alpha/4);
  }

  var B = A + 1524;
  var C = Math.floor((B - 122.1)/365.25);
  var D = Math.floor(365.25 * C);
  var E = Math.floor((B - D)/30.6001);

  var day = B - D - Math.floor(30.6001 * E) + f;
  var month = (E < 14) ? E - 1 : E - 13;
  var year = (month > 2) ? C - 4716 : C - 4715;

  return ((day<10 ? "0" : "") + day + monthList[month-1].abbr);
 }


//***********************************************************************/
//* Name:    calcTimeJulianCent       */
//* Type:    Function         */
//* Purpose: convert Julian Day to centuries since J2000.0.   */
//* Arguments:          */
//*   jd : the Julian Day to convert      */
//* Return value:          */
//*   the T value corresponding to the Julian Day    */
//***********************************************************************/

 function calcTimeJulianCent(jd)
 {
  var T = (jd - 2451545.0)/36525.0;
  return T;
 }


//***********************************************************************/
//* Name:    calcJDFromJulianCent       */
//* Type:    Function         */
//* Purpose: convert centuries since J2000.0 to Julian Day.   */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   the Julian Day corresponding to the t value    */
//***********************************************************************/

 function calcJDFromJulianCent(t)
 {
  var JD = t * 36525.0 + 2451545.0;
  return JD;
 }


//***********************************************************************/
//* Name:    calGeomMeanLongSun       */
//* Type:    Function         */
//* Purpose: calculate the Geometric Mean Longitude of the Sun  */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   the Geometric Mean Longitude of the Sun in degrees   */
//***********************************************************************/

 function calcGeomMeanLongSun(t)
 {
  var L0 = 280.46646 + t * (36000.76983 + 0.0003032 * t);
  while(L0 > 360.0)
  {
   L0 -= 360.0;
  }
  while(L0 < 0.0)
  {
   L0 += 360.0;
  }
  return L0;  // in degrees
 }


//***********************************************************************/
//* Name:    calGeomAnomalySun       */
//* Type:    Function         */
//* Purpose: calculate the Geometric Mean Anomaly of the Sun  */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   the Geometric Mean Anomaly of the Sun in degrees   */
//***********************************************************************/

 function calcGeomMeanAnomalySun(t)
 {
  var M = 357.52911 + t * (35999.05029 - 0.0001537 * t);
  return M;  // in degrees
 }

//***********************************************************************/
//* Name:    calcEccentricityEarthOrbit      */
//* Type:    Function         */
//* Purpose: calculate the eccentricity of earth's orbit   */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   the unitless eccentricity       */
//***********************************************************************/


 function calcEccentricityEarthOrbit(t)
 {
  var e = 0.016708634 - t * (0.000042037 + 0.0000001267 * t);
  return e;  // unitless
 }

//***********************************************************************/
//* Name:    calcSunEqOfCenter       */
//* Type:    Function         */
//* Purpose: calculate the equation of center for the sun   */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   in degrees          */
//***********************************************************************/


 function calcSunEqOfCenter(t)
 {
  var m = calcGeomMeanAnomalySun(t);

  var mrad = degToRad(m);
  var sinm = Math.sin(mrad);
  var sin2m = Math.sin(mrad+mrad);
  var sin3m = Math.sin(mrad+mrad+mrad);

  var C = sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) + sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289;
  return C;  // in degrees
 }

//***********************************************************************/
//* Name:    calcSunTrueLong        */
//* Type:    Function         */
//* Purpose: calculate the true longitude of the sun    */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   sun's true longitude in degrees      */
//***********************************************************************/


 function calcSunTrueLong(t)
 {
  var l0 = calcGeomMeanLongSun(t);
  var c = calcSunEqOfCenter(t);

  var O = l0 + c;
  return O;  // in degrees
 }

//***********************************************************************/
//* Name:    calcSunTrueAnomaly       */
//* Type:    Function         */
//* Purpose: calculate the true anomaly of the sun    */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   sun's true anamoly in degrees       */
//***********************************************************************/

 function calcSunTrueAnomaly(t)
 {
  var m = calcGeomMeanAnomalySun(t);
  var c = calcSunEqOfCenter(t);

  var v = m + c;
  return v;  // in degrees
 }

//***********************************************************************/
//* Name:    calcSunRadVector        */
//* Type:    Function         */
//* Purpose: calculate the distance to the sun in AU    */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   sun radius vector in AUs       */
//***********************************************************************/

 function calcSunRadVector(t)
 {
  var v = calcSunTrueAnomaly(t);
  var e = calcEccentricityEarthOrbit(t);
 
  var R = (1.000001018 * (1 - e * e)) / (1 + e * Math.cos(degToRad(v)));
  return R;  // in AUs
 }

//***********************************************************************/
//* Name:    calcSunApparentLong       */
//* Type:    Function         */
//* Purpose: calculate the apparent longitude of the sun   */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   sun's apparent longitude in degrees      */
//***********************************************************************/

 function calcSunApparentLong(t)
 {
  var o = calcSunTrueLong(t);

  var omega = 125.04 - 1934.136 * t;
  var lambda = o - 0.00569 - 0.00478 * Math.sin(degToRad(omega));
  return lambda;  // in degrees
 }

//***********************************************************************/
//* Name:    calcMeanObliquityOfEcliptic      */
//* Type:    Function         */
//* Purpose: calculate the mean obliquity of the ecliptic   */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   mean obliquity in degrees       */
//***********************************************************************/

 function calcMeanObliquityOfEcliptic(t)
 {
  var seconds = 21.448 - t*(46.8150 + t*(0.00059 - t*(0.001813)));
  var e0 = 23.0 + (26.0 + (seconds/60.0))/60.0;
  return e0;  // in degrees
 }

//***********************************************************************/
//* Name:    calcObliquityCorrection      */
//* Type:    Function         */
//* Purpose: calculate the corrected obliquity of the ecliptic  */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   corrected obliquity in degrees      */
//***********************************************************************/

 function calcObliquityCorrection(t)
 {
  var e0 = calcMeanObliquityOfEcliptic(t);

  var omega = 125.04 - 1934.136 * t;
  var e = e0 + 0.00256 * Math.cos(degToRad(omega));
  return e;  // in degrees
 }

//***********************************************************************/
//* Name:    calcSunRtAscension       */
//* Type:    Function         */
//* Purpose: calculate the right ascension of the sun    */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   sun's right ascension in degrees      */
//***********************************************************************/

 function calcSunRtAscension(t)
 {
  var e = calcObliquityCorrection(t);
  var lambda = calcSunApparentLong(t);
 
  var tananum = (Math.cos(degToRad(e)) * Math.sin(degToRad(lambda)));
  var tanadenom = (Math.cos(degToRad(lambda)));
  var alpha = radToDeg(Math.atan2(tananum, tanadenom));
  return alpha;  // in degrees
 }

//***********************************************************************/
//* Name:    calcSunDeclination       */
//* Type:    Function         */
//* Purpose: calculate the declination of the sun    */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   sun's declination in degrees       */
//***********************************************************************/

 function calcSunDeclination(t)
 {
  var e = calcObliquityCorrection(t);
  var lambda = calcSunApparentLong(t);

  var sint = Math.sin(degToRad(e)) * Math.sin(degToRad(lambda));
  var theta = radToDeg(Math.asin(sint));
  return theta;  // in degrees
 }

//***********************************************************************/
//* Name:    calcEquationOfTime       */
//* Type:    Function         */
//* Purpose: calculate the difference between true solar time and mean */
//*  solar time         */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//* Return value:          */
//*   equation of time in minutes of time      */
//***********************************************************************/

 function calcEquationOfTime(t)
 {
  var epsilon = calcObliquityCorrection(t);
  var l0 = calcGeomMeanLongSun(t);
  var e = calcEccentricityEarthOrbit(t);
  var m = calcGeomMeanAnomalySun(t);

  var y = Math.tan(degToRad(epsilon)/2.0);
  y *= y;

  var sin2l0 = Math.sin(2.0 * degToRad(l0));
  var sinm   = Math.sin(degToRad(m));
  var cos2l0 = Math.cos(2.0 * degToRad(l0));
  var sin4l0 = Math.sin(4.0 * degToRad(l0));
  var sin2m  = Math.sin(2.0 * degToRad(m));

  var Etime = y * sin2l0 - 2.0 * e * sinm + 4.0 * e * y * sinm * cos2l0
    - 0.5 * y * y * sin4l0 - 1.25 * e * e * sin2m;

  return radToDeg(Etime)*4.0; // in minutes of time
 }

//***********************************************************************/
//* Name:    calcHourAngleSunrise       */
//* Type:    Function         */
//* Purpose: calculate the hour angle of the sun at sunrise for the */
//*   latitude        */
//* Arguments:          */
//*   lat : latitude of observer in degrees     */
//* solarDec : declination angle of sun in degrees    */
//* Return value:          */
//*   hour angle of sunrise in radians      */
//***********************************************************************/

 function calcHourAngleSunrise(lat, solarDec)
 {
  var latRad = degToRad(lat);
  var sdRad  = degToRad(solarDec)

  var HAarg = (Math.cos(degToRad(90.833))/(Math.cos(latRad)*Math.cos(sdRad))-Math.tan(latRad) * Math.tan(sdRad));

  var HA = (Math.acos(Math.cos(degToRad(90.833))/(Math.cos(latRad)*Math.cos(sdRad))-Math.tan(latRad) * Math.tan(sdRad)));

  return HA;  // in radians
 }

//***********************************************************************/
//* Name:    calcHourAngleSunset       */
//* Type:    Function         */
//* Purpose: calculate the hour angle of the sun at sunset for the */
//*   latitude        */
//* Arguments:          */
//*   lat : latitude of observer in degrees     */
//* solarDec : declination angle of sun in degrees    */
//* Return value:          */
//*   hour angle of sunset in radians      */
//***********************************************************************/

 function calcHourAngleSunset(lat, solarDec)
 {
  var latRad = degToRad(lat);
  var sdRad  = degToRad(solarDec)

  var HAarg = (Math.cos(degToRad(90.833))/(Math.cos(latRad)*Math.cos(sdRad))-Math.tan(latRad) * Math.tan(sdRad));

  var HA = (Math.acos(Math.cos(degToRad(90.833))/(Math.cos(latRad)*Math.cos(sdRad))-Math.tan(latRad) * Math.tan(sdRad)));

  return -HA;  // in radians
 }


//***********************************************************************/
//* Name:    calcSunriseUTC        */
//* Type:    Function         */
//* Purpose: calculate the Universal Coordinated Time (UTC) of sunrise */
//*   for the given day at the given location on earth */
//* Arguments:          */
//*   JD  : julian day         */
//*   latitude : latitude of observer in degrees    */
//*   longitude : longitude of observer in degrees    */
//* Return value:          */
//*   time in minutes from zero Z       */
//***********************************************************************/

 function calcSunriseUTC(JD, latitude, longitude)
 {
  var t = calcTimeJulianCent(JD);

  // *** First pass to approximate sunrise

  var eqTime = calcEquationOfTime(t);
  var solarDec = calcSunDeclination(t);
  var hourAngle = calcHourAngleSunrise(latitude, solarDec);

  var delta = longitude - radToDeg(hourAngle);
  var timeDiff = 4 * delta; // in minutes of time
  var timeUTC = 720 + timeDiff - eqTime; // in minutes

  // alert("eqTime = " + eqTime + "\nsolarDec = " + solarDec + "\ntimeUTC = " + timeUTC);

  // *** Second pass includes fractional jday in gamma calc

  var newt = calcTimeJulianCent(calcJDFromJulianCent(t) + timeUTC/1440.0); 
  eqTime = calcEquationOfTime(newt);
  solarDec = calcSunDeclination(newt);
  hourAngle = calcHourAngleSunrise(latitude, solarDec);
  delta = longitude - radToDeg(hourAngle);
  timeDiff = 4 * delta;
  timeUTC = 720 + timeDiff - eqTime; // in minutes

  // alert("eqTime = " + eqTime + "\nsolarDec = " + solarDec + "\ntimeUTC = " + timeUTC);

  return timeUTC;
 }

//***********************************************************************/
//* Name:    calcSolNoonUTC        */
//* Type:    Function         */
//* Purpose: calculate the Universal Coordinated Time (UTC) of solar */
//*  noon for the given day at the given location on earth  */
//* Arguments:          */
//*   t : number of Julian centuries since J2000.0    */
//*   longitude : longitude of observer in degrees    */
//* Return value:          */
//*   time in minutes from zero Z       */
//***********************************************************************/

 function calcSolNoonUTC(t, longitude)
 {
  var newt = calcTimeJulianCent(calcJDFromJulianCent(t) + 0.5 + longitude/360.0); 

  var eqTime = calcEquationOfTime(newt);
  var solarNoonDec = calcSunDeclination(newt);
  var solNoonUTC = 720 + (longitude * 4) - eqTime; // min
  
  return solNoonUTC;
 }

//***********************************************************************/
//* Name:    calcSunsetUTC        */
//* Type:    Function         */
//* Purpose: calculate the Universal Coordinated Time (UTC) of sunset */
//*   for the given day at the given location on earth */
//* Arguments:          */
//*   JD  : julian day         */
//*   latitude : latitude of observer in degrees    */
//*   longitude : longitude of observer in degrees    */
//* Return value:          */
//*   time in minutes from zero Z       */
//***********************************************************************/

 function calcSunsetUTC(JD, latitude, longitude)
 {
  var t = calcTimeJulianCent(JD);

  // First calculates sunrise and approx length of day

  var eqTime = calcEquationOfTime(t);
  var solarDec = calcSunDeclination(t);
  var hourAngle = calcHourAngleSunset(latitude, solarDec);

  var delta = longitude - radToDeg(hourAngle);
  var timeDiff = 4 * delta;
  var timeUTC = 720 + timeDiff - eqTime;

  // first pass used to include fractional day in gamma calc

  var newt = calcTimeJulianCent(calcJDFromJulianCent(t) + timeUTC/1440.0); 
  eqTime = calcEquationOfTime(newt);
  solarDec = calcSunDeclination(newt);
  hourAngle = calcHourAngleSunset(latitude, solarDec);

  delta = longitude - radToDeg(hourAngle);
  timeDiff = 4 * delta;
  timeUTC = 720 + timeDiff - eqTime; // in minutes

  return timeUTC;
 }


//*********************************************************************/

// Returns the decimal latitude from the degrees, minutes and seconds entered 
// into the form 

 function getLatitude(latLongForm)
 {
  var neg = 0;
  var degs = parseFloat(latLongForm["latDeg"].value);
  if (latLongForm["latDeg"].value.charAt(0) == '-') 
  {
   neg = 1;
  }

  if(latLongForm["latMin"].value == "")
  {
   latLongForm["latMin"].value = 0;
  }
  if(latLongForm["latSec"].value == "")
  {
   latLongForm["latSec"].value = 0;
  }

  var mins = parseFloat(latLongForm["latMin"].value);

  var secs = parseFloat(latLongForm["latSec"].value);

  if(neg != 1)
  {
   var decLat = degs + (mins / 60) + (secs / 3600);
  } else if(neg == 1)
  {
   var decLat = degs - (mins / 60) - (secs / 3600);
  } else 
  {
   return -9999;
  }
  return decLat;
 } 


//*********************************************************************/

// Returns the decimal longitude from the degrees, minutes and seconds entered 
// into the form 

 function getLongitude(latLongForm)
 {
  var neg = 0;
  var degs = parseFloat(latLongForm["lonDeg"].value);
  if (latLongForm["lonDeg"].value.charAt(0) == '-') 
  {
   neg = 1;
  }

  if(latLongForm["lonMin"].value == "")
  {
   latLongForm["lonMin"].value = 0;
  }
  if(latLongForm["lonSec"].value == "")
  {
   latLongForm["lonSec"].value = 0;
  }

  var mins = parseFloat(latLongForm["lonMin"].value);
  var secs = parseFloat(latLongForm["lonSec"].value);
  var decLon = degs + (mins / 60) + (secs / 3600);

  if(neg != 1)
  {
   var decLon = degs + (mins / 60) + (secs / 3600);
  } else if(neg == 1)
  {
   var decLon = degs - (mins / 60) - (secs / 3600);
  } else 
  {
   return -9999;
  }
  return decLon;
 } 


//***********************************************************************/
//* Name:    findRecentSunrise       */
//* Type:    Function         */
//* Purpose: calculate the julian day of the most recent sunrise  */
//*  starting from the given day at the given location on earth */
//* Arguments:          */
//*   JD  : julian day         */
//*   latitude : latitude of observer in degrees    */
//*   longitude : longitude of observer in degrees    */
//* Return value:          */
//*   julian day of the most recent sunrise     */
//***********************************************************************/

 function findRecentSunrise(jd, latitude, longitude)
 {
  var julianday = jd;

  var time = calcSunriseUTC(julianday, latitude, longitude);
  while(!isNumber(time)){
   julianday -= 1.0;
   time = calcSunriseUTC(julianday, latitude, longitude);
  }

  return julianday;
 }


//***********************************************************************/
//* Name:    findRecentSunset        */
//* Type:    Function         */
//* Purpose: calculate the julian day of the most recent sunset  */
//*  starting from the given day at the given location on earth */
//* Arguments:          */
//*   JD  : julian day         */
//*   latitude : latitude of observer in degrees    */
//*   longitude : longitude of observer in degrees    */
//* Return value:          */
//*   julian day of the most recent sunset     */
//***********************************************************************/

 function findRecentSunset(jd, latitude, longitude)
 {
  var julianday = jd;

  var time = calcSunsetUTC(julianday, latitude, longitude);
  while(!isNumber(time)){
   julianday -= 1.0;
   time = calcSunsetUTC(julianday, latitude, longitude);
  }

  return julianday;
 }


//***********************************************************************/
//* Name:    findNextSunrise        */
//* Type:    Function         */
//* Purpose: calculate the julian day of the next sunrise   */
//*  starting from the given day at the given location on earth */
//* Arguments:          */
//*   JD  : julian day         */
//*   latitude : latitude of observer in degrees    */
//*   longitude : longitude of observer in degrees    */
//* Return value:          */
//*   julian day of the next sunrise      */
//***********************************************************************/

 function findNextSunrise(jd, latitude, longitude)
 {
  var julianday = jd;

  var time = calcSunriseUTC(julianday, latitude, longitude);
  while(!isNumber(time)){
   julianday += 1.0;
   time = calcSunriseUTC(julianday, latitude, longitude);
  }

  return julianday;
 }


//***********************************************************************/
//* Name:    findNextSunset        */
//* Type:    Function         */
//* Purpose: calculate the julian day of the next sunset   */
//*  starting from the given day at the given location on earth */
//* Arguments:          */
//*   JD  : julian day         */
//*   latitude : latitude of observer in degrees    */
//*   longitude : longitude of observer in degrees    */
//* Return value:          */
//*   julian day of the next sunset       */
//***********************************************************************/

 function findNextSunset(jd, latitude, longitude)
 {
  var julianday = jd;

  var time = calcSunsetUTC(julianday, latitude, longitude);
  while(!isNumber(time)){
   julianday += 1.0;
   time = calcSunsetUTC(julianday, latitude, longitude);
  }

  return julianday;
 }

//***********************************************************************/
//* Name:    timeString         */
//* Type:    Function         */
//* Purpose: convert time of day in minutes to a zero-padded string */
//*  suitable for printing to the form text fields   */
//* Arguments:          */
//*   minutes : time of day in minutes      */
//* Return value:          */
//*   string of the format HH:MM:SS, minutes and seconds are zero padded*/
//***********************************************************************/

 function timeString(minutes)
 // timeString returns a zero-padded string (HH:MM:SS) given time in minutes
 {
  var floatHour = minutes / 60;
  var hour = Math.floor(floatHour);
  var floatMinute = 60 * (floatHour - Math.floor(floatHour));
  var minute = Math.floor(floatMinute);
  var floatSec = 60 * (floatMinute - Math.floor(floatMinute));
  var second = Math.floor(floatSec);

  var timeStr = hour + ":";
  if (minute < 10) // i.e. only one digit
   timeStr += "0" + minute + ":";
  else
   timeStr += minute + ":";
  if (second < 10) // i.e. only one digit
   timeStr += "0" + second;
  else
   timeStr += second;

  return timeStr;
 }


//***********************************************************************/
//* Name:    timeStringShortAMPM       */
//* Type:    Function         */
//* Purpose: convert time of day in minutes to a zero-padded string */
//*  suitable for printing to the form text fields.  If time */
//*  crosses a day boundary, date is appended.    */
//* Arguments:          */
//*   minutes : time of day in minutes      */
//*   JD  : julian day         */
//* Return value:          */
//*   string of the format HH:MM[AM/PM] (DDMon)     */
//***********************************************************************/

// timeStringShortAMPM returns a zero-padded string (HH:MM *M) given time in 
// minutes and appends short date if time is > 24 or < 0, resp.

 function timeStringShortAMPM(minutes, JD)
 {
  var julianday = JD;
  var floatHour = minutes / 60;
  var hour = Math.floor(floatHour);
  var floatMinute = 60 * (floatHour - Math.floor(floatHour));
  var minute = Math.floor(floatMinute);
  var floatSec = 60 * (floatMinute - Math.floor(floatMinute));
  var second = Math.floor(floatSec);
  var PM = false;

  minute += (second >= 30)? 1 : 0;

  if (minute >= 60) 
  {
   minute -= 60;
   hour ++;
  }

  var daychange = false;
  if (hour > 23) 
  {
   hour -= 24;
   daychange = true;
   julianday += 1.0;
  }

  if (hour < 0)
  {
   hour += 24;
   daychange = true;
   julianday -= 1.0;
  }

  if (hour > 11)
  {
   hour -= 12;
   PM = true;
  }

  if (hour == 0)
  {
   PM = false;
   hour = 12;
  }

  var timeStr = hour + ":";
  if (minute < 10) // i.e. only one digit
   timeStr += "0" + minute + ((PM)?"PM":"AM");
  else
   timeStr += "" + minute + ((PM)?"PM":"AM");

  if (daychange) return timeStr + " " + calcDayFromJD(julianday);
  return timeStr;
 }


//***********************************************************************/
//* Name:    timeStringAMPMDate       */
//* Type:    Function         */
//* Purpose: convert time of day in minutes to a zero-padded string */
//*  suitable for printing to the form text fields, and appends */
//*  the date.         */
//* Arguments:          */
//*   minutes : time of day in minutes      */
//*   JD  : julian day         */
//* Return value:          */
//*   string of the format HH:MM[AM/PM] DDMon     */
//***********************************************************************/

// timeStringAMPMDate returns a zero-padded string (HH:MM[AM/PM]) given time 
// in minutes and julian day, and appends the short date

 function timeStringAMPMDate(minutes, JD)
 {
  var julianday = JD;
  var floatHour = minutes / 60;
  var hour = Math.floor(floatHour);
  var floatMinute = 60 * (floatHour - Math.floor(floatHour));
  var minute = Math.floor(floatMinute);
  var floatSec = 60 * (floatMinute - Math.floor(floatMinute));
  var second = Math.floor(floatSec);

  minute += (second >= 30)? 1 : 0;

  if (minute >= 60) 
  {
   minute -= 60;
   hour ++;
  }

  if (hour > 23) 
  {
   hour -= 24;
   julianday += 1.0;
  }

  if (hour < 0)
  {
   hour += 24;
   julianday -= 1.0;
  }

  var PM = false;
  if (hour > 11)
  {
   hour -= 12;
   PM = true;
  }

  if (hour == 0)
  {
   PM = false;
   hour = 12;
  }

  var timeStr = hour + ":";
  if (minute < 10) // i.e. only one digit
   timeStr += "0" + minute + ((PM)?"PM":"AM");
  else
   timeStr += minute + ((PM)?"PM":"AM");

  return timeStr + " " + calcDayFromJD(julianday);
 }


//***********************************************************************/
//* Name:    timeStringDate        */
//* Type:    Function         */
//* Purpose: convert time of day in minutes to a zero-padded 24hr time */
//*  suitable for printing to the form text fields.  If time */
//*  crosses a day boundary, date is appended.    */
//* Arguments:          */
//*   minutes : time of day in minutes      */
//*   JD  : julian day         */
//* Return value:          */
//*   string of the format HH:MM (DDMon)      */
//***********************************************************************/

// timeStringDate returns a zero-padded string (HH:MM) given time in minutes
// and julian day, and appends the short date if time crosses a day boundary

 function timeStringDate(minutes, JD)
 {
  var julianday = JD;
  var floatHour = minutes / 60;
  var hour = Math.floor(floatHour);
  var floatMinute = 60 * (floatHour - Math.floor(floatHour));
  var minute = Math.floor(floatMinute);
  var floatSec = 60 * (floatMinute - Math.floor(floatMinute));
  var second = Math.floor(floatSec);

  minute += (second >= 30)? 1 : 0;

  if (minute >= 60) 
  {
   minute -= 60;
   hour ++;
  }

  var daychange = false;
  if (hour > 23) 
  {
   hour -= 24;
   julianday += 1.0;
   daychange = true;
  }

  if (hour < 0)
  {
   hour += 24;
   julianday -= 1.0;
   daychange = true;
  }

  var timeStr = hour + ":";
  if (minute < 10) // i.e. only one digit
   timeStr += "0" + minute;
  else
   timeStr += minute;

  if (daychange) return timeStr + " " + calcDayFromJD(julianday);
  return timeStr;
 }

 
//***********************************************************************/
//* Name:    calcSun         */
//* Type:    Main Function called by form controls    */
//* Purpose: calculate time of sunrise and sunset for the entered date */
//*  and location.  In the special cases near earth's poles,  */
//*  the date of nearest sunrise and set are reported.  */
//* Arguments:          */
//*   riseSetForm : for displaying results     */
//*   latLongForm : for reading latitude and longitude data   */
//*   index : daylight saving yes/no select     */
//*   index2 : city select index       */
//* Return value:          */
//*   none           */
//* (fills riseSetForm text fields with results of calculations) */
//***********************************************************************/

 function calcSun(riseSetForm, latLongForm, index, index2) 
 {
  if(index2 != 0)
  {
   setLatLong(latLongForm, index2);
  }

  var latitude = getLatitude(latLongForm);
  var longitude = getLongitude(latLongForm);
  var indexRS = riseSetForm.mos.selectedIndex
  if (isValidInput(riseSetForm, indexRS, latLongForm)) 
  {
   if((latitude >= -90) && (latitude < -89.8))
   {
    alert("Todas as latitudes entre 89.8 e 90 S\n serão corrigidas para -89.8.");
    latLongForm["latDeg"].value = -89.8;
    latitude = -89.8;
   }
   if ((latitude <= 90) && (latitude > 89.8))
   {
    alert("Todas as latitudes entre 89.8 e 90 N\n serão corrigidas para 89.8.");
    latLongForm["latDeg"].value = 89.8;
    latitude = 89.8;
   }
   
   //***** Calculate the time of sunrise   

//*********************************************************************/
//****************   NEW STUFF   ******   January, 2001   ****************
//*********************************************************************/

   var JD = (calcJD(parseFloat(riseSetForm["year"].value), indexRS + 1, parseFloat(riseSetForm["day"].value)));
   var dow = calcDayOfWeek(JD);
   var doy = calcDayOfYear(indexRS + 1, parseFloat(riseSetForm["day"].value), isLeapYear(riseSetForm["year"].value));
   var T = calcTimeJulianCent(JD);
   //var L0 = calcGeomMeanLongSun(T);
   //var M = calcGeomMeanAnomalySun(T);
   //var e = calcEccentricityEarthOrbit(T);
   //var C = calcSunEqOfCenter(T);
   //var O = calcSunTrueLong(T);
   //var v = calcSunTrueAnomaly(T);
   //var R = calcSunRadVector(T);
   //var lambda = calcSunApparentLong(T);
   //var epsilon0 = calcMeanObliquityOfEcliptic(T);
   //var epsilon = calcObliquityCorrection(T);
   var alpha = calcSunRtAscension(T);
   var theta = calcSunDeclination(T);
   var Etime = calcEquationOfTime(T);

   //riseSetForm["dbug"].value = doy;

//*********************************************************************/

   var eqTime = Etime;
   var solarDec = theta;

   riseSetForm["eqTime"].value = (Math.floor(100*eqTime))/100;
   riseSetForm["solarDec"].value = (Math.floor(100*(solarDec)))/100;

   // Calculate sunrise for this date
   // if no sunrise is found, set flag nosunrise

   var nosunrise = false;

   var riseTimeGMT = calcSunriseUTC(JD, latitude, longitude);
   if (!isNumber(riseTimeGMT))
   {
    nosunrise = true;
   }

   // Calculate sunset for this date
   // if no sunset is found, set flag nosunset

   var nosunset = false;
   var setTimeGMT = calcSunsetUTC(JD, latitude, longitude);
   if (!isNumber(setTimeGMT))
   {
    nosunset = true;
   }

   var daySavings = YesNo[index].value;  // = 0 (no) or 60 (yes)
   var zone = latLongForm["hrsToGMT"].value;
   if(zone > 12 || zone < -12.5)
   {
    alert("O ajuste deve estar entre -12.5 e 12.  \n Assumimos 0.");
    zone = "0";
    latLongForm["hrsToGMT"].value = zone;
   }

   if (!nosunrise)  // Sunrise was found
   {
    var riseTimeLST = riseTimeGMT - (60 * zone) + daySavings; 
     // in minutes
    var riseStr = timeStringShortAMPM(riseTimeLST, JD);
    var utcRiseStr = timeStringDate(riseTimeGMT, JD);

    riseSetForm["sunrise"].value = riseStr;
    riseSetForm["utcsunrise"].value = utcRiseStr;
   }

   if (!nosunset)  // Sunset was found
   {
    var setTimeLST = setTimeGMT - (60 * zone) + daySavings;
    var setStr = timeStringShortAMPM(setTimeLST, JD);
    var utcSetStr = timeStringDate(setTimeGMT, JD);

    riseSetForm["sunset"].value = setStr;
    riseSetForm["utcsunset"].value = utcSetStr;
   }

   // Calculate solar noon for this date

   var solNoonGMT = calcSolNoonUTC(T, longitude);
   var solNoonLST = solNoonGMT - (60 * zone) + daySavings;

   var solnStr = timeString(solNoonLST);
   var utcSolnStr = timeString(solNoonGMT);

   riseSetForm["solnoon"].value = solnStr;
   riseSetForm["utcsolnoon"].value = utcSolnStr;
   
   //***********Convert lat and long to standard format
   convLatLong(latLongForm);

   // report special cases of no sunrise

   if(nosunrise)
   { 
    riseSetForm["utcsunrise"].value = "";
    // if Northern hemisphere and spring or summer, OR  
    // if Southern hemisphere and fall or winter, use 
    // previous sunrise and next sunset

    if ( ((latitude > 66.4) && (doy > 79) && (doy < 267)) ||
       ((latitude < -66.4) && ((doy < 83) || (doy > 263))) )
    {
     newjd = findRecentSunrise(JD, latitude, longitude);
     newtime = calcSunriseUTC(newjd, latitude, longitude)
       - (60 * zone) + daySavings;
     if (newtime > 1440)
     {
      newtime -= 1440;
      newjd += 1.0;
     }
     if (newtime < 0)
     {
      newtime += 1440;
      newjd -= 1.0;
     }
     riseSetForm["sunrise"].value = 
      timeStringAMPMDate(newtime, newjd);
     riseSetForm["utcsunrise"].value = "Anterior ^";
    }

    // if Northern hemisphere and fall or winter, OR 
    // if Southern hemisphere and spring or summer, use 
    // next sunrise and previous sunset

    else if ( ((latitude > 66.4) && ((doy < 83) || (doy > 263))) ||
     ((latitude < -66.4) && (doy > 79) && (doy < 267)) )
    {
     newjd = findNextSunrise(JD, latitude, longitude);
     newtime = calcSunriseUTC(newjd, latitude, longitude)
       - (60 * zone) + daySavings;
     if (newtime > 1440)
     {
      newtime -= 1440;
      newjd += 1.0;
     }
     if (newtime < 0)
     {
      newtime += 1440;
      newjd -= 1.0;
     }
     riseSetForm["sunrise"].value = 
      timeStringAMPMDate(newtime, newjd);
//     riseSetForm["sunrise"].value = calcDayFromJD(newjd)
//      + " " + timeStringDate(newtime, newjd);
     riseSetForm["utcsunrise"].value = "Próximo ^";
    }
    else 
    {
     alert("Nascer do Sol inexistente!");
    }

    // alert("Último nascer do Sol foi no dia " + findRecentSunrise(JD, latitude, longitude));
    // alert("Próximo nascer do Sol será no dia " + findNextSunrise(JD, latitude, longitude));

   }

   if(nosunset)
   { 
    riseSetForm["utcsunset"].value = "";
    // if Northern hemisphere and spring or summer, OR
    // if Southern hemisphere and fall or winter, use 
    // previous sunrise and next sunset

    if ( ((latitude > 66.4) && (doy > 79) && (doy < 267)) ||
       ((latitude < -66.4) && ((doy < 83) || (doy > 263))) )
    {
     newjd = findNextSunset(JD, latitude, longitude);
     newtime = calcSunsetUTC(newjd, latitude, longitude)
       - (60 * zone) + daySavings;
     if (newtime > 1440)
     {
      newtime -= 1440;
      newjd += 1.0;
     }
     if (newtime < 0)
     {
      newtime += 1440;
      newjd -= 1.0;
     }
     riseSetForm["sunset"].value = 
      timeStringAMPMDate(newtime, newjd);
     riseSetForm["utcsunset"].value = "Próximo ^";
     riseSetForm["utcsolnoon"].value = "";
    }

    // if Northern hemisphere and fall or winter, OR
    // if Southern hemisphere and spring or summer, use 
    // next sunrise and last sunset

    else if ( ((latitude > 66.4) && ((doy < 83) || (doy > 263))) ||
     ((latitude < -66.4) && (doy > 79) && (doy < 267)) )
    {
     newjd = findRecentSunset(JD, latitude, longitude);
     newtime = calcSunsetUTC(newjd, latitude, longitude)
       - (60 * zone) + daySavings;
     if (newtime > 1440)
     {
      newtime -= 1440;
      newjd += 1.0;
     }
     if (newtime < 0)
     {
      newtime += 1440;
      newjd -= 1.0;
     }
     riseSetForm["sunset"].value = 
      timeStringAMPMDate(newtime, newjd);
     riseSetForm["utcsunset"].value = "Anterior ^";
     riseSetForm["solnoon"].value = "Não existe";
     riseSetForm["utcsolnoon"].value = "";
    }

    else 
    {
     alert ("Pôr do Sol inexistente!");
    }
   }
  }
 }



//*********************************************************************/







 

 

  
Cidade
  
  






Graus
  

  
Minutos
  

  
Segundos
  

  
Fuso H.
  

  
H. Verão
  





 
  
 
  
  

  
 


 


 


    
Mês







Dia
  


  




  
Ano
  




  






"Trânsito" do Sol
  



  

  


  


  


  
  


  

 
  
  
  


  


  


  








(Script adaptado de uma publicação da U.S.NOAA - National Oceanic and Atmospheric Administration)
























OS AJUSTES - O INCLINÔMETRO
Você pode construir o mancal e o eixo da antena com seus ângulos fixos, previamente calculados para sua cidade (como nos desenhos logo abaixo), ou instalar mancal e eixo ajustáveis para qualquer latitude (como nos desenhos iniciais da página). O mancal deverá permitir ajuste de 0 a 8,5 graus e o eixo de 0 a 81,5 graus. Para aferir os ângulos, o mais indicado é construir um inclinômetro, simples artefato de madeira em forma de "T", provido de um fio de prumo, que será utilizado para aferir em "a" o ângulo do eixo (Y) e depois, em "b", o ângulo total resultante na face da antena (X + Y), conforme croqui abaixo:
(Obtenha os valores de "a" e "b" no início da página, ao lado dos valores do Âng."X" e do Âng."Y") 























O MOVIMENTO PENDULAR DA ANTENA
O mecanismo de controle do movimento pendular da antena dependerá do gênio e dos recursos de cada usuário, que optará por acionamento manual, motorizado, com controle remoto etc.

Se os ângulos e o Norte da antena estiverem corretos, esse movimento pendular rastreará todos os satélites geoestacionários do hemisfério, restando saber para quais satélites se quer apontá-la e em que "altura" eles se encontram no céu, mediante consulta às revistas ou aos "sites" especializados, como o da TeleSatélite.

Se você preferir montar um semidisco graduado, solidário ao eixo da antena, para facilitar o direcionamento, tenha em conta que a antena na posição horizontal (nivelada) aponta exatamente para os graus de Longitude da sua cidade. Assim, se sua cidade está a 51°W, por exemplo, a marca central do semidisco corresponderá a 51. Se o semidisco estiver dividido em 180 graus, para o Oeste você terá 52, 53, 54, 55... 141°W e para o Leste você terá 50, 49, 48, 47°W... 39°E.











AS FÓRMULAS MATEMÁTICAS
A rotina do início da página dá o valor dos ângulos "X" e "Y" e das distâncias "a" e "b" automaticamente. Todavia, aos que tenham a curiosidade de conhecer as fórmulas matemáticas que desenvolvemos para chegar aos resultados, vejam-nas abaixo. Isso facilitará, inclusive, àqueles que quiserem programar a rotina em linguagem diferente da que utilizamos na página (JavaScript). É o caso de quem deseje programá-la, por exemplo, em máquina calculadora de bolso ou em palmtop: 


A = Latitude do local onde a antena será instalada
B = 6.378,16
C = 35.786
D = 180-90-A
E = B x cosseno de A
F = B + C - E
G = B x seno de A
H = arco-tangente de (F ÷ G)
I = D + H
J = 180 - I
K = 90 - H
L = B + C
M = raiz quadrada de (L² - E²)
N = arco-tangente de (G ÷ M)
O = K - N
P = A + O
Q = raiz quadrada de (5000 - (5000 x cosseno de (P + 90)))
R = raiz quadrada de (5000 - (5000 x cosseno de (N + P + 90))) [em graus decimais]
[raio da circunferência da Terra - em km]
[altura da órbita dos satélites - em km]






[tombamento total da antena]



[ângulo "X"]
[correção da excentricidade do eixo de rastreamento]
[ângulo "Y"]
[distância "a" do inclinômetro - em cm]
[distância "b" do inclinômetro - em cm] 



APÊNDICE
Alguns leitores indagam-me sobre o caminho que eu adotei para chegar a esse complicado cálculo de direcionamento de antenas parabólicas universais. Eu lhes respondo que foi um simples trabalho de trigonometria. Eu o fiz para responder à necessidade de alguém que queria transformar sua antena fixa em antena universal, apta a rastrear todos os satélites geoestacionários do hemisfério. E, depois de concluída a tarefa, resolvi compartilhá-la com aqueles que tivessem idêntico propósito. Tento satisfazer à curiosidade daqueles que não se limitam a aplicar a rotina pronta, no início da página, e querem entender a lógica dos cálculos elaborados:

Assumimos que todos os satélites geoestacionários orbitam a Terra à altura de 35.786km, exatamente acima da linha do equador. E que, como eles acompanham o giro da Terra, parecem estar parados no céu. A órbita deles forma um anel imaginário ao redor da Terra, denominado "Anel de Clarke". Assumimos, também, que o círculo do equador tem o raio de 6.378,16km.

Assim, para apontarmos a antena para o Anel de Clarke, nós a direcionamos para o zênite (ponto mais alto do céu) e a tombamos na direção Norte (se estamos no hemisfério Sul) ou na direção Sul (se estamos no hemisfério Norte), em um ângulo determinado pela latitude da nossa cidade. Se a nossa cidade se situa na latitude zero (na linha do equador), a antena direcionada para o zênite já aponta para o Anel de Clarke.

Depois é só direcioná-la para o satélite desejado, sabendo sua longitude. Para tanto será necessário estabelecer um eixo que possibilite criar um movimento pendular da antena.

Se estamos na linha do equador (latitude zero), tudo fica mais fácil: o eixo estará paralelo ao eixo da Terra e do Anel de Clarke e bastará realizar o movimento pendular da antena, para Leste ou para Oeste, procurando o satélite desejado, em sua longitude.

Se estamos no Polo Norte ou no Polo Sul (latitude 90º), a equação também é fácil: o eixo estará perpendicular ao eixo da Terra e do Anel de Clarke e bastará tombar a antena num ângulo de 8,6019º e girar o pedestal à procura da longitude do satélite desejado.

Por que 8,6019º? Porque é a solução do triângulo-retângulo abaixo ilustrado (resolva-o utilizando a rotina da minha página "Soluções Matemáticas" - os valores conhecidos estão em vermelho): 











O desenho acima é teórico. Já dissemos que uma antena situada num dos polos, no nível do chão, não "enxergará" os satélites geoestacionários, por causa da curvatura da Terra. Só os "enxergaria" de estivesse sobre uma torre com a altura impraticável de 74,2507km. No nível do chão, a maior latitude em que uma antena "enxerga" os satélites está em 81,2995º. Por que 74,2507km e 81,2995º? Porque é a solução dos dois triângulos-retângulos abaixo ilustrados (resolva-os utilizando a rotina da minha página "Soluções Matemáticas" - os valores conhecidos estão em vermelho), que têm como um dos catetos uma linha que parte dos satélites e tangencia a Terra:











Todavia, se estamos numa latitude intermediária, maior do que zero e menor do que 90º, o cálculo se torna mais complicado. É preciso determinar o ângulo do eixo do rastreamento pendular e é preciso compensar a excentricidade da curva imaginária traçada pela antena no céu, uma vez que ela estará fora do eixo da Terra e do eixo do Anel de Clarke.

Trabalhemos com a latitude hipotética de 27,8º S (27º48') e vejamos no desenho que isso significaria tombar uma antena apontada para o zênite 32,4564º em direção ao Norte. Use minha página "Soluções Matemáticas" para resolver os triângulos a seguir. Os valores previamente conhecidos estão apresentados em vermelho. Resolva os dois triângulos-retângulos abaixo:











O ângulo total de tombamento da antena (32,4564º) a aponta para o plano do Anel de Clarke (o plano do equador). Todavia, o movimento pendular da antena a afastaria do plano do equador, uma vez que o eixo do movimento pendular não está paralelo ao eixo da Terra:











Faz-se necessário verticalizar o eixo do movimento pendular da antena, para que ele fique paralelo ao eixo da Terra. O eixo deverá ser destombado 4,6564º (32,4564 - 27,8) e, para compensar, a antena deverá ser tombada idênticos 4,6564º, ficando portanto o ângulo "X" com 4,6564º e o ângulo "Y" com 27,8º:











Acontece que, conquanto agora a antena focalize o Anel de Clarke, se apontada para o zênite, ela não o alcançaria quando apontada para o horizonte. Veja no 1º desenho abaixo que o Anel de Clarke, no horizonte, está mais longe do que no zênite, no ponto de vista da antena. Faz-se necessário corrigir isso, diminuindo o tombamento da antena, pelos 0,5844º encontrados no 2º desenho, para que ela alcance o Anel de Clarke, quando apontada para o horizonte. Ao mesmo tempo, faz-se necessário aumentar o tombamento do eixo do movimento pendular da antena, pelos mesmos 0,5844º, para reconduzi-la ao foco do Anel, quando apontada para o zênite. O que conduz o ângulo "X" a 4,072º (4,6564 - 0,5844) e o ângulo "Y" a 28,3844 (27,8 + 0,5844):











Depois é só direcionar a antena para o satélite desejado, sabendo sua longitude. A antena posicionada na linha do equador rastreará os satélites do hemisfério mediante movimento pendular:











A antena posicionada em um dos polos rastrearia os satélites do mundo inteiro (se a curvatura da Terra não impedisse a visualização) mediante o giro do pedestal no eixo Norte-Sul:










A antena posicionada em qualquer outra latitude rastreará os satélites do hemisfério mediante movimento pendular:











Veja o interessante vídeo feito para confirmar que as fórmulas acima estão corretas e conduzem ao perfeito rastreamento da antena em cima do Anel de Clarke. O filme foi feito sob critérios técnicos, com base em desenho tridimensional no AutoCad, e traz uma câmara fotográfica que acompanha a trajetória apontada pela antena. O desenho no AutoCad foi desenvolvido por meu irmão Cláudio Roberto Ghiorzi e o filme foi elaborado por seu filho André Germani Ghiorzi:















Se quiser saber mais a respeito da recepção de sinais de satélites, veja uma profusão de informações importantes, na página em inglês Satellite Signals, de Eric Johnston. 



------------------------------------------------------------------------------------------------------------------------------------------------



Ligação com Chave DiSEqC Motor da Banda KU:



O próprio Motor é um DiSEqC 1.2 ou compatível Usals (= DiSEqC 1.3) 
Via Usals mais fácil de configurar.
Poderá usar uma DiSEqC 1.0/2.0 4x1 ou mais em cascata para ligar outros LNBF's.


Os motores DiSEQc 1.2 são instalados directamente na antena, alimentados através do cabo coaxial entre a antena e o receptor.

Aconselhamos a instalação destes motores em antenas inferiores a 1,00 metro e por técnicos qualificados.


Motores DiSEQc 1.2 Para antenas até 1,10m

Principais características:60 satélites de memória, função GOTO X Azimute +75º -75º Limites de Software e Hardware, controlo manual, alimentação 13/17V DC.

















Configuração de Antena Banda Ku em uma Chave de Comutação - Alimentação diretamente do Receptor Digital. Exemplo acima.
















Motor DiSEqC 1.2/Usals Ku adaptado numa antena OffSet de 90 cm.



O ESQUEMA ABIXO PODERÁ USAR PARA BANDA C E KU MOTORIZADAS!





Abaixo Antena Rastreável Plana para Banda Ku com Motor HH Ku:

Aqui mais detalhes:
KIT ANTENA E MOTOR BANDA KU SELFSAT PLANA [~60 CM]











Abraços e BOA PONTARIA NOS SATÉLITES.




Visite a Loja do E-SHOP SATELITE:




Loja Virtual E-SHOP SATELITE:&nbsp;http://www.eshopsatelite.com.br/



Francisco Crispim