File Coverage

blib/lib/Astro/Coord/ECI/Star.pm
Criterion Covered Total %
statement 77 86 89.5
branch 5 12 41.6
condition 6 10 60.0
subroutine 14 16 87.5
pod 3 3 100.0
total 105 127 82.6


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Astro::Coord::ECI::Star - Compute the position of a star.
4              
5             =head1 SYNOPSIS
6              
7             use Astro::Coord::ECI;
8             use Astro::Coord::ECI::Star;
9             use Astro::Coord::ECI::Utils qw{deg2rad};
10            
11             # 1600 Pennsylvania Ave, Washington DC USA
12             # latitude 38.899 N, longitude 77.038 W,
13             # altitude 16.68 meters above sea level
14             my $lat = deg2rad (38.899); # Radians
15             my $long = deg2rad (-77.038); # Radians
16             my $alt = 16.68 / 1000; # Kilometers
17            
18             my $star = Astro::Coord::ECI::Star->new (
19             name => 'Spica')->position(
20             3.51331869544372, # Right ascension, radians
21             -0.194802985206623, # Declination, radians
22             );
23             my $sta = Astro::Coord::ECI->
24             universal (time ())->
25             geodetic ($lat, $long, $alt);
26             my ($time, $rise) = $sta->next_elevation ($star);
27             print "Star @{[$rise ? 'rise' : 'set']} is ",
28             scalar localtime $time, "\n";
29              
30             =head1 DESCRIPTION
31              
32             This module implements the position of a star (or any other object
33             which can be regarded as fixed on the celestial sphere) as a function
34             of time, as described in Jean Meeus' "Astronomical Algorithms," second
35             edition. It is a subclass of L,
36             with a position() method to set the catalog position (and optionally
37             proper motion as well), and the time_set() method overridden to compute
38             the position of the star at the given time.
39              
40             =head2 Methods
41              
42             The following methods should be considered public:
43              
44             =over
45              
46             =cut
47              
48             package Astro::Coord::ECI::Star;
49              
50 4     4   3038 use strict;
  4         10  
  4         121  
51 4     4   21 use warnings;
  4         8  
  4         228  
52              
53             our $VERSION = '0.129';
54              
55 4     4   27 use base qw{Astro::Coord::ECI};
  4         22  
  4         419  
56              
57 4     4   27 use Astro::Coord::ECI::Utils qw{ @CARP_NOT :mainstream };
  4         10  
  4         1639  
58 4     4   39 use Carp;
  4         9  
  4         245  
59 4     4   1228 use Data::Dumper;
  4         13707  
  4         246  
60 4     4   28 use POSIX qw{floor strftime};
  4         9  
  4         39  
61              
62             =item $star = Astro::Coord::ECI::Star->new();
63              
64             This method instantiates an object to represent the coordinates of a
65             star, or some other object which may be regarded as fixed on the
66             celestial sphere. This is a subclass of B, with the
67             angularvelocity attribute initialized to zero.
68              
69             Truth in advertising: The positions produced by this model are about
70             four arc seconds off Dr. Meeus' worked example for the position of
71             Theta Persei for Dynamical time November 13.19, 2028. This seems
72             excessive, but it's difficult to check intermediate results because
73             this calculation goes through ecliptic coordinates, whereas Dr. Meeus'
74             worked example is in equatorial coordinates.
75              
76             =cut
77              
78             sub new {
79 2     2 1 111 my ($class, @args) = @_;
80 2 50       10 ref $class and $class = ref $class;
81 2         20 return $class->SUPER::new (angularvelocity => 0,
82             @args);
83             }
84              
85             =item @almanac = $star->almanac($station, $start, $end);
86              
87             This method produces almanac data for the star for the given observing
88             station, between the given start and end times. The station is assumed
89             to be Earth-Fixed - that is, you can not do this for something in orbit.
90              
91             The C<$station> argument may be omitted if the C attribute has
92             been set. That is, this method can also be called as
93              
94             @almanac = $star->almanac( $start, $end )
95              
96             The start time defaults to the current time setting of the $star
97             object, and the end time defaults to a day after the start time.
98              
99             The almanac data consists of a list of list references. Each list
100             reference points to a list containing the following elements:
101              
102             [0] => time
103             [1] => event (string)
104             [2] => detail (integer)
105             [3] => description (string)
106              
107             The @almanac list is returned sorted by time.
108              
109             The following events, details, and descriptions are at least
110             potentially returned:
111              
112             horizon: 0 = star sets, 1 = star rises;
113             transit: 1 = star transits meridian;
114              
115             =cut
116              
117             sub __almanac_event_type_iterator {
118 0     0   0 my ( $self, $station ) = @_;
119              
120 0         0 my $inx = 0;
121              
122 0         0 my $horizon = $station->__get_almanac_horizon();
123              
124 0         0 my @events = (
125             [ $station, next_elevation => [ $self, $horizon, 1 ],
126             horizon => '__horizon_name' ],
127             [ $station, next_meridian => [ $self ],
128             transit => '__transit_name' ],
129             );
130              
131             return sub {
132             $inx < @events
133 0 0   0   0 and return @{ $events[$inx++] };
  0         0  
134 0         0 return;
135 0         0 };
136             }
137              
138 4     4   1426 use Astro::Coord::ECI::Mixin qw{ almanac };
  4         9  
  4         219  
139              
140             =item @almanac = $star->almanac_hash($station, $start, $end);
141              
142             This convenience method wraps $star->almanac(), but returns a list of
143             hash references, sort of like Astro::Coord::ECI::TLE->pass()
144             does. The hashes contain the following keys:
145              
146             {almanac} => {
147             {event} => the event type;
148             {detail} => the event detail (typically 0 or 1);
149             {description} => the event description;
150             }
151             {body} => the original object ($star);
152             {station} => the observing station;
153             {time} => the time the quarter occurred.
154              
155             The {time}, {event}, {detail}, and {description} keys correspond to
156             elements 0 through 3 of the list returned by almanac().
157              
158             =cut
159              
160 4     4   26 use Astro::Coord::ECI::Mixin qw{ almanac_hash };
  4         9  
  4         181  
161              
162 4     4   23 use constant NEVER_PASS_ELEV => 2 * __PACKAGE__->SECSPERDAY;
  4         8  
  4         869  
163              
164             =item $star = $star->position($ra, $dec, $range, $mra, $mdc, $mrg, $time);
165              
166             This method sets the position and proper motion of the star in
167             equatorial coordinates. Right ascension and declination are
168             specified in radians, and range in kilometers. Proper motion in
169             range and declination is specified in radians B (an
170             B small number!), and the proper motion in recession
171             in kilometers per second.
172              
173             The range defaults to 1 parsec, which is too close but probably good
174             enough since we do not take parallax into account when computing
175             position, and since you can override it with a range (in km!) if you so
176             desire. The proper motions default to 0. The time defaults to J2000.0,
177             and is used to set not only the current time of the object but also the
178             equinox_dynamical. If you are not interested in proper motion but are
179             interested in time, omit the proper motion arguments completely and
180             specify time as the fourth argument.
181              
182             If you call this as a class method, a new Astro::Coord::ECI::Star
183             object will be constructed. If you call it without arguments, the
184             position of the star is returned.
185              
186             Note that this is B simply a synonym for the equatorial() method.
187             The equatorial() method returns the position of the star corrected for
188             precession and nutation. This method is used to set the catalog
189             position of the star in question.
190              
191             =cut
192              
193             sub position {
194 2     2 1 10 my ($self, @args) = @_;
195 2 50       15 return @{$self->{_star_position}} unless @args;
  0         0  
196 2   50     7 $args[2] ||= PARSEC;
197 2 50       9 @args < 5 and splice @args, 3, 0, 0, 0, 0;
198 2   50     7 $args[3] ||= 0;
199 2   50     7 $args[4] ||= 0;
200 2   100     8 $args[5] ||= 0;
201 2   50     13 $args[6] ||= PERL2000;
202 2 50       5 $self = $self->new () unless ref $self;
203 2         8 $self->{_star_position} = [@args];
204             # CAVEAT: time_set() picks the equinox directly out of the above
205             # hash.
206 2         18 $self->dynamical ($args[6]);
207 2         7 return $self;
208             }
209              
210             =item $star->time_set()
211              
212             This method sets coordinates of the object to the coordinates of the
213             star at the object's currently-set universal time. Proper motion is
214             taken into account if this was specified.
215              
216             Although there's no reason this method can't be called directly, it
217             exists to take advantage of the hook in the B
218             object, to allow the position of the star to be computed when the
219             time is set.
220              
221             The computation comes from Jean Meeus' "Astronomical Algorithms", 2nd
222             Edition, Chapter 23, pages 149ff.
223              
224             B, however, that for consistency with the
225             L and
226             L classes, the position
227             is precessed to the current time setting.
228              
229             =cut
230              
231 4     4   31 use constant CONSTANT_OF_ABERRATION => deg2rad (20.49552 / 3600);
  4         8  
  4         19  
232              
233             sub time_set {
234 1124     1124 1 1595 my $self = shift;
235              
236 1124 50       2341 $self->{_star_position} or croak <
237             Error - The position of the star has not been set.
238             eod
239              
240             my ($ra, $dec, $range, $mra, $mdc, $mrg, $epoch) = @{
241 1124         1526 $self->{_star_position}};
  1124         2821  
242              
243 1124         2886 my $time = $self->universal;
244 1124         2508 my $end = $self->dynamical;
245              
246             # Account for the proper motion of the star, and set our
247             # equatorial coordinates to the result.
248              
249 1124         2154 my $deltat = $end - $epoch;
250             #### $ra += $mra * $deltat;
251 1124         2788 $ra = mod2pi($ra + $mra * $deltat);
252 1124         1831 $dec += $mdc * $deltat;
253 1124         1608 $range += $mrg * $deltat;
254             ##!! $self->set (equinox => $epoch);
255 1124         3426 $self->equatorial ($ra, $dec, $range);
256              
257             # NOTE: The call to precess() used to be here. I have no idea why,
258             # other than that I thought I could go back and forth between
259             # coordinates less (since I implemented in terms equatorial
260             # coordinates). It seems to me at this point (version 0.003_04,
261             # 25-Oct-2007) that since precessing to a different equinox is
262             # actually just a coordinate transform that it should come last.
263             # Meeus actually gives the algorithm in ecliptic coordinates also;
264             # if the transform could be smart, I could skip a couple
265             # coordinate transforms.
266              
267             # Get ecliptic coordinates, and correct for nutation.
268              
269 1124         3022 my ($beta, $lambda) = $self->ecliptic ();
270 1124         3027 my ( $delta_psi ) = $self->nutation();
271 1124         1856 $lambda += $delta_psi;
272              
273             # Calculate and add in the aberration terms (Meeus 23.2);
274              
275 1124         2122 my $T = jcent2000 ($time); # Meeus (22.1)
276 1124         1941 my $e = (-0.0000001267 * $T - 0.000042037) * $T + 0.016708634;# Meeus (25.4)
277 1124         2219 my $pi = deg2rad ((0.00046 * $T + 1.71946) * $T + 102.93735);
278 1124         2852 my $sun = $self->get( 'sun' );
279 1124         3564 $sun->universal ($time);
280              
281 1124         2951 my $geoterm = $sun->geometric_longitude () - $lambda;
282 1124         1788 my $periterm = $pi - $lambda;
283 1124         2900 my $deltalamda = ($e * cos ($periterm) - cos ($geoterm)) *
284             CONSTANT_OF_ABERRATION / cos ($beta);
285 1124         2265 my $deltabeta = - (sin ($geoterm) - $e * sin ($periterm)) * sin ($beta) *
286             CONSTANT_OF_ABERRATION;
287 1124         2072 $lambda += $deltalamda;
288 1124         1748 $beta += $deltabeta;
289              
290 1124         3347 $self->ecliptic ($beta, $lambda, $range);
291              
292             # Set the equinox to that implied when our position was set.
293              
294             ## $self->set (equinox_dynamical => $epoch);
295 1124         3389 $self->equinox_dynamical ($epoch);
296              
297             # Precess ourselves to the current equinox.
298              
299 1124         3555 $self->precess_dynamical ($end);
300              
301 1124         2672 return $self;
302             }
303              
304             1;
305              
306             =back
307              
308             =head1 ACKNOWLEDGMENTS
309              
310             The author wishes to acknowledge Jean Meeus, whose book "Astronomical
311             Algorithms" (second edition) formed the basis for this module.
312              
313             =head1 SEE ALSO
314              
315             The L
316             documentation for a discussion of how the pieces/parts of this
317             distribution go together and how to use them.
318              
319             L by Alasdair Allan, which accommodates a
320             much more fulsome description of a star. The star's coordinates are
321             represented by an B object.
322              
323             L by Tim Jenness can also be used to find
324             the position of a star at a given time given a catalog entry for the
325             star. A wide variety of coordinate representations is accommodated.
326             This package requires B, which in its turn requires the
327             SLALIB library.
328              
329             =head1 SUPPORT
330              
331             Support is by the author. Please file bug reports at
332             L,
333             L, or in
334             electronic mail to the author.
335              
336             =head1 AUTHOR
337              
338             Thomas R. Wyant, III (F)
339              
340             =head1 COPYRIGHT AND LICENSE
341              
342             Copyright (C) 2005-2023 by Thomas R. Wyant, III
343              
344             This program is free software; you can redistribute it and/or modify it
345             under the same terms as Perl 5.10.0. For more details, see the full text
346             of the licenses in the directory LICENSES.
347              
348             This program is distributed in the hope that it will be useful, but
349             without any warranty; without even the implied warranty of
350             merchantability or fitness for a particular purpose.
351              
352             =cut
353              
354             # ex: set textwidth=72 :