Astro-Coord-ECI-TLE-Iridium
view release on metacpan or search on metacpan
lib/Astro/Coord/ECI/TLE/Iridium.pm view on Meta::CPAN
while (abs ($flare_approx[1][1] - $flare_approx[0][1]) > .1) {
# Calculate the next time to try as a weighted average of the
# previous two approximations, with the worse approximation
# having three times the weight of the better one. This prevents
# us from converging so fast we miss the true minimum. Yes, this
# is ad-hocery. I tried weighting the 'wrong' flare twice as
# much, but still missed the maximum sometimes. This was more
# obvious on daytime flares, where if you miss the peak the
# flare is probably not specular.
## my $time = ($flare_approx[1][1] * 2 + $flare_approx[0][1]) / 3;
my $time = ($flare_approx[1][1] * 3 + $flare_approx[0][1]) / 4;
#### my $time = ($flare_approx[1][1] * 6 + $flare_approx[0][1]) / 7;
# Transform the relevant coordinates into a coordinate system
# in which the axis of the satellite is along the Z axis (with
# the Earth in the negative Z direction) and the direction of
# motion (and hence one of the Main Mission Antennae) is along
# the X axis.
my ( $illum_vector, $station_vector ) =
$self->universal( $time )->
_flare_transform_coords_list(
$illum->universal( $time ),
$station->universal( $time ) );
# Calculate the angle between the satellite and the reflection
# of the Sun, as seen by the observer.
my $angle = _flare_calculate_angle_list(
$mma, $illum_vector, $station_vector );
defined $angle or next MMA_LOOP;
# Store the data in our approximation list, in order by angle.
pop @flare_approx;
splice @flare_approx, $angle >= $flare_approx[0][0], 0,
[$angle, $time, $illum_vector, $station_vector];
# End of successive approximation of time of minimum angle.
}
# Pull the (potential) flare data off the approximation list.
my ($angle, $time, $illum_vector, $station_vector) =
@{$flare_approx[0]};
# Skip it if the mirror angle is greater than the max.
next if $angle > $max_mirror_angle;
# All our approximations may have left us with a satellite which
# is not quite lit. This happened with Iridium 32 (OID 24945) on
# Feb 03 2007 at 07:45:19 PM. So we check for illumination one
# last time.
# TODO: this calculation should be performed not on the position
# of the Sun, but on the actual point on the Sun which is
# reflected to the observer. It looks now like it needs to be done
# in _flare_calculate_angle_list().
($self->universal ($time)->azel ($illum->universal ($time)))[1] >=
$self->dip () or next;
# Calculate all the flare data.
my $flare = $self->_flare_char_list ($station, $mma, $angle,
$time, $illum_vector, $station_vector);
# Stash the data.
push @flares, $flare
if !$flare->{status} && $want{$flare->{type}};
# End of iteration over each MMA to calculate its flare.
}
# Compute the next approxiate crossing of the observer's
# latitude.
} continue {
$time += $deltas[$asc];
$asc = 1 - $asc;
}
return @flares;
}
# [$angle, $time, $illum_vector, $station_vector] =
# $self->_flare_entrance ($illum, $station, $mma, $start,
# $end);
# Given that a flare is in progress at the end time and not at
# the start time, computes the start of the flare. Can be used
# for exit by reversing the times.
sub _flare_entrance {
my ($self, $illum, $station, $mma, $start, $end) = @_;
my $output;
# my $time = find_first_true (
find_first_true (
$start, $end,
sub {
$self->universal ($_[0]);
my ( $illum_vector, $station_vector ) =
$self->_flare_transform_coords_list(
$illum->universal( $_[0] ),
$station->universal( $_[0] ) );
if ( defined ( my $angle = _flare_calculate_angle_list(
$mma, $illum_vector, $station_vector ) ) ) {
$output = [$angle, $_[0], $illum_vector, $station_vector];
1;
} else {
0;
}
});
$output ||= do { # Can happen if end is entrance.
lib/Astro/Coord/ECI/TLE/Iridium.pm view on Meta::CPAN
foreach my $mma (0 .. 2) {
# We calculate
# the angle between the satellite and the reflection of the Sun,
# as seen by the observer. We skip to the next antenna if no
# reflection is generated.
my $angle = _flare_calculate_angle_list(
$mma, $illum_vector, $station_vector );
warn <<eod if $debug; ## no critic (RequireCarping)
MMA $mma Angle: @{[defined $angle ? rad2deg ($angle) . ' degrees' :
'undefined']}
eod
push @rslt, defined $angle ?
scalar $self->_flare_char_list ($station, $mma, $angle, $time,
$illum_vector, $station_vector) :
scalar _make_status ('Geometry does not allow reflection',
mma => $mma);
}
return wantarray ? @rslt : \@rslt;
}
=item $tle->set ($name => $value ...)
This method sets the value of the given attribute (or attributes).
Attributes other than 'status' are delegated to the parent.
=cut
sub set {
my ($self, @args) = @_;
while (@args) {
my $name = shift @args;
my $value = shift @args;
if (!$mutator{$name}) {
$self->SUPER::set ($name, $value);
} elsif (ref $self) {
$mutator{$name}->($self, $name, $value);
} else {
$mutator{$name}->(\%statatr, $name, $value);
}
}
return $self;
}
# For use of -am and -pm
{
my $date_time_available = eval {
load_module( 'DateTime' );
load_module( 'DateTime::TimeZone' );
1;
};
sub _time_in_zone {
my ( $self, $time ) = @_;
defined( my $zone = $self->get( 'zone' ) )
or return localtime $time;
looks_like_number( $zone )
and return gmtime( $zone * 3600 + $time );
if ( $date_time_available ) {
my $dt = DateTime->from_epoch(
epoch => $time,
time_zone => $zone,
);
my @localtime = map { $dt->$_() } qw{ second minute hour day
month_0 year day_of_week_0 day_of_year_0 is_dst };
$localtime[5] -= 1900;
return @localtime;
} else {
local $ENV{TZ} = $zone;
return localtime $time;
}
}
}
sub __parse_name {
my ( $self, $name ) = @_;
defined $name
and $name =~ s/ \s* [[] ( \S ) []] \s* \z //smx
and $self->_set_operational_status( status => $1 );
return $self->SUPER::__parse_name( $name );
}
{
my @encode_status;
$encode_status[BODY_STATUS_IS_OPERATIONAL] = '+';
$encode_status[BODY_STATUS_IS_SPARE] = 'S';
$encode_status[BODY_STATUS_IS_TUMBLING] = '-';
$encode_status[BODY_STATUS_IS_DECAYED] = 'D';
sub __encode_operational_status {
## my ( $self, $name, $status ) = @_;
my ( $self, undef, $status ) = @_; # Name unused
defined $status
or $status = $self->get( 'status' );
defined $encode_status[ $status ]
or return BODY_STATUS_IS_TUMBLING;
return $encode_status[ $status ];
}
}
{
my %status_map = (
BODY_STATUS_IS_OPERATIONAL() => BODY_STATUS_IS_OPERATIONAL,
'' => BODY_STATUS_IS_OPERATIONAL,
'+' => BODY_STATUS_IS_OPERATIONAL,
BODY_STATUS_IS_SPARE() => BODY_STATUS_IS_SPARE,
'?' => BODY_STATUS_IS_SPARE,
'S' => BODY_STATUS_IS_SPARE,
's' => BODY_STATUS_IS_SPARE,
'D' => BODY_STATUS_IS_DECAYED,
( run in 3.777 seconds using v1.01-cache-2.11-cpan-364913b4093 )