File Coverage

blib/lib/Astro/Coord/ECI/Star.pm
Criterion Covered Total %
statement 79 80 98.7
branch 8 12 66.6
condition 8 10 80.0
subroutine 14 14 100.0
pod 3 3 100.0
total 112 119 94.1


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