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 )