I recently had need to calculate the transit time of the sun to aid in aligning the pier for a new telescope in our observatory. The result was a complete success with alignment within 1/4 of a degree achieved.
Following a request by another astronomical society member who wanted to use the same technique for lining up a telescope I wrapped the calculation code in an object and put it in a package. Provided with a very thin Tk GUI interface the result is given below. Clear skies.
use strict; use warnings; package SunEvents; use Math::Trig; use constant kTransit => 0.0; use constant kOffical => 90.833333; use constant kCivil => 96.0; use constant kNautical => 102.0; use constant kAstronomical => 108.0; sub new { my $class = shift; my $self = bless {}, $class; $self->{zenith} = kOffical; $self->{localOffset} = 12.0; return $self; } sub setYMD { my ($self, $year, $month, $day) = @_; @{$self}{'year', 'month', 'day'} = ($year, $month, $day); } sub setLatDMS { my ($self, $deg, $minute, $second) = @_; @{$self->{lat}}{'deg', 'minute', 'second'} = ($deg, $minute, $seco +nd); ($minute, $second) = (-$minute, -$second) if $deg < 0; $self->{latitude} = $deg + ($second / 60.0 + $minute) / 60.0; } sub setLongDMS { my ($self, $deg, $minute, $second) = @_; @{$self->{long}}{'deg', 'minute', 'second'} = ($deg, $minute, $sec +ond); $self->{longitude} = $deg + ($second / 60.0 + $minute) / 60.0; } sub asHS { my $time = shift; my $hour = int $time; my $min = int ($time * 60 % 60); my $sec = int ($time * 3600 % 60); return sprintf "%02d:%02d:%02d", $hour, $min, $sec; } sub calcRiseTime { return shift->DoCalc (1); } sub calcSetTime { return shift->DoCalc (); } sub calcTransitTime { my $self = shift; return ($self->DoCalc () + $self->DoCalc (1)) / 2.0; } sub DoCalc { my ($self, $rising) = @_; my $N1 = int (275 * $self->{month} / 9); my $N2 = int (($self->{month} + 9) / 12); my $N3 = (1 + int (($self->{year} - 4 * int ($self->{year} / +4) + 2) / 3)); my $yearDay = $N1 - ($N2 * $N3) + $self->{day} - 30; my $longHour = $self->{longitude} / 15.0; # Convert the long +itude to hour value my $approxTime = $yearDay + ((($rising ? 6.0 : 18.0) - $longHour) +/ 24.0); my $sunAnomaly = (0.9856 * $approxTime) - 3.289; my $sunLong = adjRange ($sunAnomaly + (1.916 * sinD ($sunAnomaly)) + (0.020 * sinD (2 * $sunAnomaly)) + 282.634); my $RA = adjRange (atanD (0.91764 * tanD ($sunLong))); # Adjust RA quadrant to match $sunLong and convert to hours my $sunLongQuad = (int ($sunLong / 90)) * 90; my $RAquad = (int ($RA / 90)) * 90; $RA = ($RA + ($sunLongQuad - $RAquad)) / 15.0; my $sunDecSin = 0.39782 * sinD ($sunLong); my $sunHACos = (cosD ($self->{zenith}) - ($sunDecSin * sinD ($self->{latitude}) +)) / (cosD (asinD ($sunDecSin)) * cosD ($self->{latitude})); if ($sunHACos > 1) { print "No sunrise\n"; return; } elsif ($sunHACos < -1) { print "No sunset\n"; return; } my $sunHA = ($rising ? 360.0 - acosD ($sunHACos) : acosD ($sunHACo +s)) / 15.0; my $localMeanTime = $sunHA + $RA - (0.06571 * $approxTime) - 6.622 +; my $UT = adjRange ($localMeanTime - $longHour, 24.0); return adjRange ($UT + $self->{localOffset} + 1 / 120.0, 24.0); } sub adjRange { my ($value, $limit) = @_; $limit ||= 360.0; $value -= $limit while $value >= $limit; $value += $limit while $value < 0; return $value; } sub sinD { return sin (deg2rad (shift)); } sub cosD { return cos (deg2rad (shift)); } sub tanD { return tan (deg2rad (shift)); } sub asinD { return rad2deg (asin (shift)); } sub acosD { return rad2deg (acos (shift)); } sub atanD { return rad2deg (atan (shift)); } package main; use Tk; my $main = MainWindow->new (-title => "Sun times calculator"); # Date controls my ($day, $month, $year) = (22, 5, 2008); my %common = (-padx => 5, -pady => 2, -top => '%0'); my $dayLbl = $main->Label (-text => 'Day:')-> form (-l => '%0', -r => '%30', %common); my $dayEnt = $common{-top} = $main->Entry (-textvariable => \$day)->fo +rm (-l => $dayLbl, %common); my $monthLbl = $main->Label (-text => 'Month num:')->form (-l => '%0', + -r => '%30', %common); my $monthEnt = $common{-top} = $main->Entry (-textvariable => \$month) +->form (-l => $monthLbl, %common); my $yearLbl = $main->Label (-text => 'Year:')->form (-l => '%0', -r => + '%30', %common); my $yearEnt = $common{-top} = $main->Entry (-textvariable => \$year)-> +form (-l => $yearLbl, %common); # Latitude controls my ($latDeg, $latMin, $latSec) = (-44, 42, 5.92); # 44°42'5.92"S my $latLbl = $main->Label (-text => 'lat (DMS):')->form (-l => '%0', - +r => '%30', %common); my $latDegEnt = $main->Entry (-textvariable => \$latDeg)-> form (-l => $latLbl, -r => ['&', $latLbl, 40], %common); my $latMinEnt = $main->Entry (-textvariable => \$latMin)-> form (-l => $latDegEnt, -r => ['&', $latDegEnt, 40], %common); my $latSecEnt = $common{-top} = $main->Entry (-textvariable => \$latSe +c)-> form (-l => $latMinEnt, -r => ['&', $latMinEnt, 56], %common); # Longitude controls my ($longDeg, $longMin, $longSec) = (169, 7, 57.13);#169° 7'57.13"E my $longLbl = $main->Label (-text => 'long (DMS):')->form (-l => '%0', + -r => '%30', %common); my $longDegEnt = $main->Entry (-textvariable => \$longDeg)-> form (-l => $longLbl, -r => ['&', $longLbl, 40], %common); my $longMinEnt = $main->Entry (-textvariable => \$longMin)-> form (-l => $longDegEnt, -r => ['&', $longDegEnt, 40], %common); my $longSecEnt = $common{-top} = $main->Entry (-textvariable => \$long +Sec)-> form (-l => $longMinEnt, -r => ['&', $longMinEnt, 56], %common); # Calculate controls my $calc = $main->Button (-text => 'Calculate', -command => \&calculat +e)-> form (-l => '%10', %common); my $result = $main->Label (-relief => 'sunken')->form (-l => $calc, -r + => ['&', $calc, 72], %common); MainLoop (); sub calculate { my $calculator = SunEvents->new (); $calculator->setYMD ($year, $month, $day); $calculator->setLatDMS ($latDeg, $latMin, $latSec); $calculator->setLongDMS ($longDeg, $longMin, $longSec); $result->configure (-text => SunEvents::asHS ($calculator->calcTra +nsitTime ())); }
In reply to Sun rise, set and transit calculations by GrandFather
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |