#!/usr/bin/perl #---------------------------------------------------------------------------------------------- # by Joseph A. DiVerdi # Copyright 2006 by XTR Systems, LLC #---------------------------------------------------------------------------------------------- # Includes and other external modules use warnings; use strict; use Math::Trig; use Math::Complex; use Time::Local; use POSIX qw(ceil floor); #---------------------------------------------------------------------------------------------- # Main execution module $| = 1; # locations of important items my $directions_file_name = "directions to use"; my $usable_files_file_name = "files to use"; my $data_files_directory = "data files"; my $processed_data_file_name = "processed_data_scaled"; my $gridded_data_file_name = "gridded_data_scaled"; my $dec_spacing = 1.0; my $ra_spacing = 2.0; # variable definitions my @file_names; my $azimuth_list; my $elevation_list; # create the arrays for gridding the data my $list; for (my $dec = 0; $ dec < 90; $dec += $dec_spacing) { for (my $ra = 0; $ ra < 360; $ra += $ra_spacing) { @{$list->{$ra}{$dec}} = (); } } # set up the names of the data files to process open INPUT, '<', $usable_files_file_name or die "Can't read '$usable_files_file_name': $!\n"; while (my $line = ) { next if $line =~ /^(#|\s*$)/; chomp $line; push @file_names, $line; } close INPUT; # set up the pointing directions open INPUT, '<', $directions_file_name or die "Can't read '$directions_file_name': $!\n"; while (my $line = ) { next if $line =~ /^(#|\s*$)/; chomp $line; my ($azimuth, $elevation, $day, $month, $year, $time, $remainder) = split /,?\s+/, $line; my $epoch_time = convert_time_and_date($day, $month, $year, $time); $azimuth_list->{$epoch_time} = $azimuth; $elevation_list->{$epoch_time} = $elevation; } close INPUT; print "Processing data files"; open PROCESSED, '>', $processed_data_file_name or die "Can't create '$processed_data_file_name': $!\n"; print PROCESSED "epoch_time\tdeclination\tright ascension\tintensity\n"; # iterate over the raw data files print "Processing data files"; foreach (@file_names) { print "|"; } foreach (@file_names) { print "\x08"; } foreach my $input_file_name (sort @file_names) { print "."; $input_file_name = join("/", $data_files_directory, $input_file_name); unless (open INPUT, '<', $input_file_name) { print "Can't process '$input_file_name': $!\n"; next; } # read in the entire contents of a particular data file my $data_record; my $intensity_min = 10; my $intensity_max = 0; while (my $line = ) { next if $line =~ /^(#|\s*$)/; chomp $line; my ($epoch_time, $el, $az, @values) = split /\s+/, $line; # compute elevation and azimuth for this epoch time ($el, $az) = compute_horizontal($epoch_time, $elevation_list, $azimuth_list); my ($dec, $ra) = compute_equatorial($epoch_time, $el, $az); my $integral = 0; foreach my $value (@values) { $integral += $value; } $integral /= scalar @values; # store the values in a suitable structure $data_record->{$epoch_time}{'dec'} = $dec; $data_record->{$epoch_time}{'ra'} = $ra; $data_record->{$epoch_time}{'integral'} = $integral; $data_record->{$epoch_time}{'values'} = [@values]; $intensity_min = $integral if $integral < $intensity_min; $intensity_max = $integral if $integral > $intensity_max; } foreach my $epoch_time (sort keys %$data_record) { my $dec = $data_record->{$epoch_time}{'dec'}; my $ra = $data_record->{$epoch_time}{'ra'}; # my $integral = ($data_record->{$epoch_time}{'integral'} - $intensity_min) / ($intensity_max - $intensity_min); my $integral = ($data_record->{$epoch_time}{'integral'} - $intensity_min); # my $integral = ($data_record->{$epoch_time}{'integral'} - $intensity_max + 1.0); my @values = @{$data_record->{$epoch_time}{'values'}}; printf PROCESSED "%10d\t%+8.3f\t%+8.3f\t%7.5f", $epoch_time, $dec, $ra, $integral; # printf PROCESSED "\t%s", join("\t", @values); printf PROCESSED "\n"; # quantize the pointing direction on the specified grid # put the data value on the list of values for that pointing direction my $dec_quantized = int($dec / $dec_spacing + 0.5) * $dec_spacing; my $ra_quantized = int($ra / $ra_spacing + 0.5) * $ra_spacing; push @{$list->{$ra_quantized}{$dec_quantized}}, $integral; } close INPUT; } close PROCESSED; print "\n"; # form the mean and (sample) std dev and write the gridded data file print "Gridding data"; open GRIDDED, '>', $gridded_data_file_name or die "Can't create '$gridded_data_file_name': $!\n"; print GRIDDED "declination\tright ascension\tcount\tintensity\n"; foreach (my $dec_quantized = 0; $dec_quantized < 90; $dec_quantized += $dec_spacing) { print "|"; } foreach (my $dec_quantized = 0; $dec_quantized < 90; $dec_quantized += $dec_spacing) { print "\x08"; } for (my $dec_quantized = 0; $dec_quantized < 90; $dec_quantized += $dec_spacing) { print "."; for (my $ra_quantized = 0; $ra_quantized < 360; $ra_quantized += $ra_spacing) { my @list = sort @{$list->{$ra_quantized}{$dec_quantized}}; my $median; if (scalar @list == 0) { $median = 0; } elsif ((scalar @list) % 2 == 0) { $median = ($list[floor($#list / 2)] + $list[ceil($#list / 2)]) / 2; } else { $median = $list[$#list / 2]; } printf GRIDDED "%+8.3f\t%+8.3f\t%05d\t%7.5f", $dec_quantized, $ra_quantized, (scalar @list), $median; if (scalar @list > 0 and $list[0] != 0 and $list[$#list] != 0) { foreach my $value (@list) { printf GRIDDED "\t%7.5f", $value; } } printf GRIDDED "\n"; } } close GRIDDED; print "\n"; exit; #---------------------------------------------------------------------------------------------- sub convert_time_and_date { my $day = shift; my $month = shift; my $year = shift; my $hour_minute = shift; if ($month =~ /jan/i) { $month = 0; } elsif ($month =~ /feb/i) { $month = 1; } elsif ($month =~ /mar/i) { $month = 2; } elsif ($month =~ /apr/i) { $month = 3; } elsif ($month =~ /may/i) { $month = 4; } elsif ($month =~ /jun/i) { $month = 5; } elsif ($month =~ /jul/i) { $month = 6; } elsif ($month =~ /aug/i) { $month = 7; } elsif ($month =~ /sep/i) { $month = 8; } elsif ($month =~ /oct/i) { $month = 9; } elsif ($month =~ /nov/i) { $month = 10; } elsif ($month =~ /dec/i) { $month = 11; } else { die "Bad month: '$month'\n"; } my ($hour, $minute) = $hour_minute =~ /(\d{2})(\d{2})/; return timelocal(0, $minute, $hour, $day, $month, $year); } #---------------------------------------------------------------------------------------------- sub compute_horizontal { my $epoch_time = shift; my $elevation_list = shift; my $azimuth_list = shift; my $time; foreach my $test_time (reverse sort keys %{$elevation_list}) { if ($test_time <= $epoch_time) { $time = $test_time; last; } } return ($elevation_list->{$time}, $azimuth_list->{$time}); } #---------------------------------------------------------------------------------------------- sub compute_equatorial { my $time = shift; my $el = shift; my $az = shift; my $lat = +40.14791; # coordinates for Table Mountain Upper Dish my $lon = -105.2324; # coordinates for Table Mountain Upper Dish # The following formulas used for computing sidereal time in this program have been published by # Keith Burnett (kburnett@btinternet.com) on his web page: http://www.btinternet.com/~kburnett/kepler/sidereal.htm # And related material at: http://www.xylem.f2s.com/kepler/mean.html # All the formulas connecting UT with sidereal time depend on the time elapsed from some fundamental epoch. # Older references have used a date in 1900 as the epoch, Meeus and most recent formulas use J2000.0 as the epoch. # The formula below will find the days since J2000.0 for any date after 1900 and before 2099. # The date and time must be in UT. my @times = gmtime($time); my $year = $times[5] + 1900; # four digit year my $month = $times[4] + 1; # 1 <= month <= 12 my $day = $times[3]; # 1 <= day <= 31 my $epoch_days = 367 * $year - int(7 * ($year + int(($month + 9) / 12)) / 4) + int(275 * $month / 9) + $times[3] - 730531.5; $epoch_days += ($times[2] + $times[1] / 60 + $times[0] / 3600) / 24; # The mean sidereal time at zero longitude is often called # Greenwich Mean Sidereal Time or GMST. The formula below is based on # Meeus formula 11.4 with terms in the square and the cube of the time left out. # epoch_days is the number of UT days since J2000.0, including fractional part of a day and GMST is in degrees. # The value may require rotation to get it in the range 0 <= GMST < 360 my $GMST = rotate_into_range(280.46061837 + 360.98564736629 * $epoch_days); # To get the sidereal time at the local longitude, known as Local Mean # Sidereal Time or LMST, add the local longitude in degrees, taking East as Positive. # The value may require rotation to get it in the range 0 <= LMST < 360 my $LMST = rotate_into_range($GMST + $lon); # calculate the declination my $dec = asin_deg(sin_deg($el) * sin_deg($lat) + cos_deg($el) * cos_deg($lat) * cos_deg($az)); # compute the hour angle # take the real part of the potentially complex value (which can occur near singularities) and convert it to degrees my $hour_angle = rad2deg(Re(acos((sin_deg($el) - sin_deg($lat) * sin_deg($dec)) / (cos_deg($lat) * cos_deg($dec))))); # reflect the hour angle depending on which quadrant the azimuth is in then rotate into the principal range $hour_angle = 360 - $hour_angle if 0 <= $az and $az < 180; $hour_angle = rotate_into_range($hour_angle); # The RA is the difference between the LMST and the hour angle rotated into the principal range my $ra = rotate_into_range($LMST - $hour_angle); return ($dec, $ra); } #---------------------------------------------------------------------------------------------- sub rotate_into_range { # rotate the argument into the range 0 <= argument < 360 my $angle = shift; while ($angle >= 360) { $angle -= 360; } while ($angle < 0) { $angle += 360; } return $angle; } #---------------------------------------------------------------------------------------------- sub sin_deg { return sin(deg2rad(shift)); } sub cos_deg { return cos(deg2rad(shift)); } sub asin_deg { return rad2deg(asin(shift)); } sub acos_deg { return rad2deg(acos(shift)); } #----------------------------------------------------------------------------------------------