Пример #1
0
    def makePlateParEntry(self, statid):
        imgdt = self.getDateTime()
        _, cx, cy, _ = self.getCameraDetails()
        az, ev, _, fovh, yx, _, _, _ = self.getProfDetails()
        _, lid, sid, lat, lng, alt = self.getStationDetails()

        ff_name = 'FF_' + statid + '_'
        ff_name = ff_name + imgdt.strftime('%Y%m%d_%H%M%S_')
        ff_name = ff_name + '{:.0f}'.format(
            imgdt.microsecond / 1000) + '_0000000.fits'

        fovv = fovh * (cx * yx / cy)

        ref_jd = datetime2JD(imgdt)
        ra_d, dec_d = altAz2RADec(numpy.radians(az), numpy.radians(ev), ref_jd,
                                  numpy.radians(lat), numpy.radians(lng))

        pp = '"' + ff_name + '": {\n'
        pp = pp + '    "lat": {:f},\n'.format(lat)
        pp = pp + '    "lon": {:f},\n'.format(lng)
        pp = pp + '    "elev": {:f},\n'.format(alt)
        pp = pp + '    "X_res": {:d},\n'.format(int(cx))
        pp = pp + '    "Y_res": {:d},\n'.format(int(cy))
        pp = pp + '    "JD": {:.8f},\n'.format(ref_jd)
        pp = pp + '    "RA_d": {:.8f},\n'.format(numpy.degrees(ra_d))
        pp = pp + '    "dec_d": {:.8f},\n'.format(numpy.degrees(dec_d))
        pp = pp + '    "fov_h": {:f},\n'.format(fovh)
        pp = pp + '    "fov_v": {:f},\n'.format(fovv)
        pp = pp + '    "station_code": "{:s}",\n'.format(statid)
        pp = pp + '    "version": 2\n'
        pp = pp + '}'

        return pp
Пример #2
0
    def initObservationsObject(self, met, pp, ref_dt=None):
        """ Init the observations object which will be fed into the trajectory solver. """

        # If the reference datetime is given, apply a time offset
        if ref_dt is not None:
            # Compute the time offset that will have to be added to the relative time
            time_offset = (met.reference_dt - ref_dt).total_seconds()
        else:
            ref_dt = met.reference_dt
            time_offset = 0

        ra_data = np.array([np.radians(entry.ra) for entry in met.data])
        dec_data = np.array([np.radians(entry.dec) for entry in met.data])
        time_data = np.array(
            [entry.time_rel + time_offset for entry in met.data])
        mag_data = np.array([entry.mag for entry in met.data])

        # If the data is in J2000, precess it to the epoch of date
        if self.data_in_j2000:
            jdt_ref_vect = np.zeros_like(ra_data) + datetime2JD(ref_dt)
            ra_data, dec_data = equatorialCoordPrecession_vect(
                J2000_JD.days, jdt_ref_vect, ra_data, dec_data)

        # If the two begin and end points are fainter by N magnitudes from the median, ignore them
        ignore_list = np.zeros_like(mag_data)
        if len(mag_data) > 5:

            median_mag = np.median(mag_data)
            indices = [0, 1, -1, -2]

            for ind in indices:
                if mag_data[ind] > (
                        median_mag +
                        self.traj_constraints.mag_filter_endpoints):
                    ignore_list[ind] = 1

        # Init the observation object
        obs = ObservedPoints(datetime2JD(ref_dt), ra_data, dec_data, time_data, np.radians(pp.lat), \
            np.radians(pp.lon), pp.elev, meastype=1, station_id=pp.station_code, magnitudes=mag_data, \
            ignore_list=ignore_list, fov_beg=met.fov_beg, fov_end=met.fov_end)

        return obs
Пример #3
0
    def initTrajectory(self, ref_dt, mc_runs):
        """ Initialize the Trajectory solver. 
        
        Arguments:
            ref_dt: [datetime] Reference datetime.
            mc_runs: [int] Number of Monte Carlo runs.

        Return:
            traj: [Trajectory]
        """

        traj = Trajectory(datetime2JD(ref_dt), \
            max_toffset=self.traj_constraints.max_toffset, meastype=1, \
            v_init_part=self.v_init_part, monte_carlo=self.traj_constraints.run_mc, \
            mc_runs=mc_runs, show_plots=False, verbose=False, save_results=False, \
            reject_n_sigma_outliers=2, mc_cores=self.traj_constraints.mc_cores)

        return traj
Пример #4
0
def loadECSVs(ecsv_paths):

    # Init meteor objects
    meteor_list = []
    for ecsv_file in ecsv_paths:

        station_lat = None
        station_lon = None
        station_ele = None
        station_id = None

        # Load the station information from the ECSV file
        with open(ecsv_file) as f:

            for line in f:
                if line.startswith("#"):
                    line = line.replace('\n', '').replace('\r', '').replace(
                        '{', '').replace('}', '')
                    line = line.split(':')
                    if len(line) > 1:

                        if "obs_latitude" in line[0]:
                            station_lat = float(line[1])

                        if "obs_longitude" in line[0]:
                            station_lon = float(line[1])

                        if "obs_elevation" in line[0]:
                            station_ele = float(line[1])

                        if "camera_id" in line[0]:
                            station_id = line[1].strip().strip("'")

                        if (station_id is None) and ("dfn_camera_codename"
                                                     in line[0]):
                            station_id = line[1].strip().strip("'")


            if (station_lat is None) or (station_lon is None) or (station_ele is None) \
                or (station_id is None):

                print("Station info could not be read from file:", ecsv_file,
                      ", skipping...")
                continue

            # Load meteor measurements
            delimiter = ','
            data = np.loadtxt(ecsv_file,
                              comments='#',
                              delimiter=delimiter,
                              dtype=str)

            # Determine the column indices from the header
            header = data[0].tolist()
            dt_indx = header.index('datetime')
            azim_indx = header.index('azimuth')
            alt_indx = header.index('altitude')
            x_indx = header.index('x_image')
            y_indx = header.index('y_image')

            if 'mag_data' in header:
                mag_indx = header.index('mag_data')
            else:
                mag_indx = None

            # Skip the header
            data = data[1:]

            # Unpack data
            dt_data, azim_data, alt_data, x_data, y_data = data[:, dt_indx], data[:, azim_indx], \
                data[:, alt_indx], data[:, x_indx], data[:, y_indx]

            azim_data = azim_data.astype(np.float64)
            alt_data = alt_data.astype(np.float64)
            x_data = x_data.astype(np.float64)
            y_data = y_data.astype(np.float64)

            # Get magnitude data, if any
            if mag_indx is not None:
                mag_data = data[:, mag_indx].astype(np.float64)
            else:
                mag_data = np.zeros_like(azim_data) + 10.0

            # Convert time to JD
            jd_data = []
            for date in dt_data:
                dt = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%f")
                jd_data.append(datetime2JD(dt))

            jd_data = np.array(jd_data)

            # Take the first time as reference time
            jdt_ref = jd_data[0]

            # Compute relative time
            time_data = (jd_data - jdt_ref) * 86400

            # Compute RA/Dec
            ra_data, dec_data = altAz2RADec_vect(np.radians(azim_data), np.radians(alt_data), jd_data, \
                np.radians(station_lat), np.radians(station_lon))

            # Precess to J2000
            ra_data, dec_data = equatorialCoordPrecession_vect(
                jdt_ref, J2000_JD.days, ra_data, dec_data)

            # Init the meteor object
            meteor = MeteorObservation(jdt_ref, station_id, np.radians(station_lat), \
                np.radians(station_lon), station_ele, FPS)

            # Add data to meteor object
            for t_rel, x_centroid, y_centroid, ra, dec, azim, alt, mag in zip(time_data, x_data, y_data, \
                np.degrees(ra_data), np.degrees(dec_data), azim_data, alt_data, mag_data):

                meteor.addPoint(t_rel * FPS, x_centroid, y_centroid, azim, alt,
                                ra, dec, mag)

            meteor.finish()

            meteor_list.append(meteor)

    # Normalize all observations to the same JD and precess from J2000 to the epoch of date
    return prepareObservations(meteor_list)
Пример #5
0
    # Get the total mass density
    atm_density = out.d[5]

    return atm_density


getAtmDensity_vect = np.vectorize(getAtmDensity, excluded=['jd'])

if __name__ == "__main__":

    import datetime
    from wmpl.Utils.TrajConversions import datetime2JD

    lat = 44.327234
    lon = -81.372350
    jd = datetime2JD(datetime.datetime.now())

    # Density evaluation heights (m)
    heights = np.linspace(70, 120, 100) * 1000

    atm_densities = []
    for height in heights:
        atm_density = getAtmDensity(np.radians(lat), np.radians(lon), height,
                                    jd)
        atm_densities.append(atm_density)

    plt.semilogx(atm_densities, heights / 1000, zorder=3)

    plt.xlabel('Density (kg/m^3)')
    plt.ylabel('Height (km)')
Пример #6
0
    def __repr__(self, uncertainties=None, v_init_ht=None):
        """ String to be printed out when the Orbit object is printed. """
        def _uncer(str_format, std_name, multi=1.0, deg=False):
            """ Internal function. Returns the formatted uncertanty, if the uncertanty is given. If not,
                it returns nothing. 

            Arguments:
                str_format: [str] String format for the unceertanty.
                std_name: [str] Name of the uncertanty attribute, e.g. if it is 'x', then the uncertanty is 
                    stored in uncertainties.x.
        
            Keyword arguments:
                multi: [float] Uncertanty multiplier. 1.0 by default. This is used to scale the uncertanty to
                    different units (e.g. from m/s to km/s).
                deg: [bool] Converet radians to degrees if True. False by defualt.
                """

            if deg:
                multi *= np.degrees(1.0)

            if uncertainties is not None:
                if hasattr(uncertainties, std_name):
                    return " +/- " + str_format.format(
                        getattr(uncertainties, std_name) * multi)

            return ''

        out_str = ""
        #out_str +=  "--------------------\n"

        # Check if the orbit was calculated
        if self.ra_g is not None:
            out_str += "  JD dynamic   = {:20.12f} \n".format(self.jd_dyn)
            out_str += "  LST apparent = {:.10f} deg\n".format(
                np.degrees(self.lst_ref))

        ### Apparent radiant in ECI ###

        out_str += "Radiant (apparent in ECI which includes Earth's rotation, epoch of date):\n"
        out_str += "  R.A.      = {:>9.5f}{:s} deg\n".format(
            np.degrees(self.ra), _uncer('{:.4f}', 'ra', deg=True))
        out_str += "  Dec       = {:>+9.5f}{:s} deg\n".format(
            np.degrees(self.dec), _uncer('{:.4f}', 'dec', deg=True))
        out_str += "  Azimuth   = {:>9.5f}{:s} deg\n".format(np.degrees(self.azimuth_apparent), \
            _uncer('{:.4f}', 'azimuth_apparent', deg=True))
        out_str += "  Elevation = {:>+9.5f}{:s} deg\n".format(np.degrees(self.elevation_apparent), \
            _uncer('{:.4f}', 'elevation_apparent', deg=True))
        out_str += "  Vavg      = {:>9.5f}{:s} km/s\n".format(
            self.v_avg / 1000, _uncer('{:.4f}', 'v_avg', multi=1.0 / 1000))

        if v_init_ht is not None:
            v_init_ht_str = ' (average above {:.2f} km)'.format(v_init_ht)
        else:
            v_init_ht_str = ''

        out_str += "  Vinit     = {:>9.5f}{:s} km/s{:s}\n".format(
            self.v_init / 1000, _uncer('{:.4f}', 'v_init', multi=1.0 / 1000),
            v_init_ht_str)

        ### ###

        ### Apparent radiant in ECEF (no rotation included) ###

        out_str += "Radiant (apparent ground-fixed, epoch of date):\n"
        out_str += "  R.A.      = {:>9.5f}{:s} deg\n".format(np.degrees(self.ra_norot), _uncer('{:.4f}', \
            'ra', deg=True))
        out_str += "  Dec       = {:>+9.5f}{:s} deg\n".format(np.degrees(self.dec_norot), _uncer('{:.4f}', \
            'dec', deg=True))
        out_str += "  Azimuth   = {:>9.5f}{:s} deg\n".format(np.degrees(self.azimuth_apparent_norot), \
            _uncer('{:.4f}', 'azimuth_apparent', deg=True))
        out_str += "  Elevation = {:>+9.5f}{:s} deg\n".format(np.degrees(self.elevation_apparent_norot), \
            _uncer('{:.4f}', 'elevation_apparent', deg=True))
        out_str += "  Vavg      = {:>9.5f}{:s} km/s\n".format(self.v_avg_norot/1000, _uncer('{:.4f}', \
            'v_avg', multi=1.0/1000))
        out_str += "  Vinit     = {:>9.5f}{:s} km/s{:s}\n".format(self.v_init_norot/1000, _uncer('{:.4f}', \
            'v_init', multi=1.0/1000), v_init_ht_str)

        ### ###

        # Check if the orbital elements could be calculated, and write them out
        if self.ra_g is not None:

            out_str += "Radiant (geocentric, J2000):\n"
            out_str += "  R.A.   = {:>9.5f}{:s} deg\n".format(
                np.degrees(self.ra_g), _uncer('{:.4f}', 'ra_g', deg=True))
            out_str += "  Dec    = {:>+9.5f}{:s} deg\n".format(
                np.degrees(self.dec_g), _uncer('{:.4f}', 'dec_g', deg=True))
            out_str += "  Vg     = {:>9.5f}{:s} km/s\n".format(
                self.v_g / 1000, _uncer('{:.4f}', 'v_g', multi=1.0 / 1000))
            out_str += "  Vinf   = {:>9.5f}{:s} km/s\n".format(
                self.v_inf / 1000, _uncer('{:.4f}', 'v_inf', multi=1.0 / 1000))
            out_str += "  Zc     = {:>9.5f}{:s} deg\n".format(
                np.degrees(self.zc), _uncer('{:.4f}', 'zc', deg=True))
            out_str += "  Zg     = {:>9.5f}{:s} deg\n".format(
                np.degrees(self.zg), _uncer('{:.4f}', 'zg', deg=True))
            out_str += "Radiant (ecliptic geocentric, J2000):\n"
            out_str += "  Lg     = {:>9.5f}{:s} deg\n".format(
                np.degrees(self.L_g), _uncer('{:.4f}', 'L_g', deg=True))
            out_str += "  Bg     = {:>+9.5f}{:s} deg\n".format(
                np.degrees(self.B_g), _uncer('{:.4f}', 'B_g', deg=True))
            out_str += "  Vh     = {:>9.5f}{:s} km/s\n".format(
                self.v_h / 1000, _uncer('{:.4f}', 'v_h', multi=1 / 1000.0))
            out_str += "Radiant (ecliptic heliocentric, J2000):\n"
            out_str += "  Lh     = {:>9.5f}{:s} deg\n".format(
                np.degrees(self.L_h), _uncer('{:.4f}', 'L_h', deg=True))
            out_str += "  Bh     = {:>+9.5f}{:s} deg\n".format(
                np.degrees(self.B_h), _uncer('{:.4f}', 'B_h', deg=True))
            out_str += "  Vh_x   = {:>9.5f}{:s} km/s\n".format(
                self.v_h_x, _uncer('{:.4f}', 'v_h_x'))
            out_str += "  Vh_y   = {:>9.5f}{:s} km/s\n".format(
                self.v_h_y, _uncer('{:.4f}', 'v_h_y'))
            out_str += "  Vh_z   = {:>9.5f}{:s} km/s\n".format(
                self.v_h_z, _uncer('{:.4f}', 'v_h_z'))
            out_str += "Orbit:\n"
            out_str += "  La Sun = {:>10.6f}{:s} deg\n".format(
                np.degrees(self.la_sun), _uncer('{:.4f}', 'la_sun', deg=True))
            out_str += "  a      = {:>10.6f}{:s} AU\n".format(
                self.a, _uncer('{:.4f}', 'a'))
            out_str += "  e      = {:>10.6f}{:s}\n".format(
                self.e, _uncer('{:.4f}', 'e'))
            out_str += "  i      = {:>10.6f}{:s} deg\n".format(
                np.degrees(self.i), _uncer('{:.4f}', 'i', deg=True))
            out_str += "  peri   = {:>10.6f}{:s} deg\n".format(
                np.degrees(self.peri), _uncer('{:.4f}', 'peri', deg=True))
            out_str += "  node   = {:>10.6f}{:s} deg\n".format(
                np.degrees(self.node), _uncer('{:.4f}', 'node', deg=True))
            out_str += "  Pi     = {:>10.6f}{:s} deg\n".format(
                np.degrees(self.pi), _uncer('{:.4f}', 'pi', deg=True))
            out_str += "  q      = {:>10.6f}{:s} AU\n".format(
                self.q, _uncer('{:.4f}', 'q'))
            out_str += "  f      = {:>10.6f}{:s} deg\n".format(
                np.degrees(self.true_anomaly),
                _uncer('{:.4f}', 'true_anomaly', deg=True))
            out_str += "  M      = {:>10.6f}{:s} deg\n".format(
                np.degrees(self.mean_anomaly),
                _uncer('{:.4f}', 'mean_anomaly', deg=True))
            out_str += "  Q      = {:>10.6f}{:s} AU\n".format(
                self.Q, _uncer('{:.4f}', 'Q'))
            out_str += "  n      = {:>10.6f}{:s} deg/day\n".format(
                np.degrees(self.n), _uncer('{:.4f}', 'n', deg=True))
            out_str += "  T      = {:>10.6f}{:s} years\n".format(
                self.T, _uncer('{:.4f}', 'T'))

            if self.last_perihelion is not None:
                out_str += "  Last perihelion JD = {:.6f} ".format(datetime2JD(self.last_perihelion)) \
                    + "(" + str(self.last_perihelion) + ")" + _uncer('{:.4f} days', 'last_perihelion') \
                    + "\n"
            else:
                out_str += "  Last perihelion JD = NaN \n"

            out_str += "  Tj     = {:>10.6f}{:s}\n".format(
                self.Tj, _uncer('{:.4f}', 'Tj'))

            out_str += "Shower association:\n"

            # Perform shower association
            shower_obj = associateShower(self.la_sun, self.L_g, self.B_g,
                                         self.v_g)
            if shower_obj is None:
                shower_no = -1
                shower_code = '...'
            else:
                shower_no = shower_obj.IAU_no
                shower_code = shower_obj.IAU_code

            out_str += "  IAU No.  = {:>4d}\n".format(shower_no)
            out_str += "  IAU code = {:>4s}\n".format(shower_code)

        return out_str
Пример #7
0
        print(parameter_missing_message.format('initial velocity'))
        sys.exit()

    if cml_args.vavg is not None:
        v_avg = 1000 * cml_args.vavg
    elif traj is not None:
        v_avg = traj.orbit.v_avg
    elif v_init is not None:
        v_avg = v_init
    else:
        print(parameter_missing_message.format('average velocity'))
        sys.exit()

    if cml_args.time is not None:
        dt_ref = datetime.datetime.strptime(cml_args.time, "%Y%m%d-%H%M%S.%f")
        jd_ref = datetime2JD(dt_ref)
    elif traj is not None:
        jd_ref = traj.orbit.jd_ref
    else:
        print(parameter_missing_message.format('reference time'))
        sys.exit()

    # Parse reference location
    if (cml_args.lat is None) and (cml_args.lon is None) and (cml_args.ele is
                                                              None):

        # Reuse the ECI coordinates from the given trajectory file
        if traj is not None:
            eci_ref = traj.state_vect_mini

        else:
Пример #8
0
    """

    # Theory:
    # I = P_0m*10^(-0.4*M_abs)
    # M = (2/tau)*integral(I/v^2 dt)

    # Compute the radiated energy
    intens_int = calcRadiatedEnergy(time, mag_abs, P_0m=P_0m)

    # Calculate the mass
    mass = (2.0 / (tau * velocity**2)) * intens_int

    return mass


if __name__ == "__main__":

    import datetime

    from wmpl.Utils.TrajConversions import datetime2JD

    # Test the dynamic pressure function
    lat = np.radians(43)
    lon = np.radians(-81)
    height = 97000.0  # m
    jd = datetime2JD(datetime.datetime(2018, 6, 15, 7, 15, 0))
    velocity = 41500  #m/s

    print('Dynamic pressure:', dynamicPressure(lat, lon, height, jd, velocity),
          'Pa')
Пример #9
0
    def checkFOVOverlap(self, rp, tp):
        """ Check if two stations have overlapping fields of view between heights of 50 to 115 km.
        
        Arguments:
            rp: [Platepar] Reference platepar.
            tp: [Platepar] Test platepar.

        Return:
            [bool] True if FOVs overlap, False otherwise.
        """

        # Compute the FOV diagonals of both stations
        reference_fov = np.radians(np.sqrt(rp.fov_v**2 + rp.fov_h**2))
        test_fov = np.radians(np.sqrt(tp.fov_v**2 + tp.fov_h**2))

        lat1, lon1, elev1 = np.radians(rp.lat), np.radians(rp.lon), rp.elev
        lat2, lon2, elev2 = np.radians(tp.lat), np.radians(tp.lon), tp.elev

        # Compute alt/az of the FOV centre
        azim1, alt1 = raDec2AltAz(np.radians(rp.RA_d), np.radians(rp.dec_d),
                                  rp.JD, lat1, lon1)
        azim2, alt2 = raDec2AltAz(np.radians(tp.RA_d), np.radians(tp.dec_d),
                                  tp.JD, lat2, lon2)

        # Use now as a reference time for FOV overlap check
        ref_jd = datetime2JD(datetime.datetime.utcnow())

        # Compute ECI coordinates of both stations
        reference_stat_eci = np.array(
            geo2Cartesian(lat1, lon1, rp.elev, ref_jd))
        test_stat_eci = np.array(geo2Cartesian(lat2, lon2, tp.elev, ref_jd))

        # Compute ECI vectors of the FOV centre
        ra1, dec1 = altAz2RADec(azim1, alt1, ref_jd, lat1, lon1)
        reference_fov_eci = vectNorm(np.array(raDec2ECI(ra1, dec1)))
        ra2, dec2 = altAz2RADec(azim2, alt2, ref_jd, lat2, lon2)
        test_fov_eci = vectNorm(np.array(raDec2ECI(ra2, dec2)))

        # Compute ECI coordinates at different heights along the FOV line and check for FOV overlap
        # The checked heights are 50, 70, 95, and 115 km (ordered by overlap probability for faster
        # execution)
        for height_above_ground in [95000, 70000, 115000, 50000]:

            # Compute points in the middle of FOVs of both stations at given heights
            reference_fov_point = reference_stat_eci + reference_fov_eci*(height_above_ground \
                - elev1)/np.sin(alt1)
            test_fov_point = test_stat_eci + test_fov_eci * (
                height_above_ground - elev2) / np.sin(alt2)

            # Check if the middles of the FOV are in the other camera's FOV
            if (angleBetweenVectors(reference_fov_eci, test_fov_point - reference_stat_eci) <= reference_fov/2) \
                or (angleBetweenVectors(test_fov_eci, reference_fov_point - test_stat_eci) <= test_fov/2):

                return True

            # Compute vectors pointing from one station's point on the FOV line to the other
            reference_to_test = vectNorm(test_fov_point - reference_fov_point)
            test_to_reference = -reference_to_test

            # Compute vectors from the ground to those points
            reference_fov_gnd = reference_fov_point - reference_stat_eci
            test_fov_gnd = test_fov_point - test_stat_eci

            # Compute vectors moved towards the other station by half the FOV diameter
            reference_moved = reference_stat_eci + vectorFromPointDirectionAndAngle(reference_fov_gnd, \
                reference_to_test, reference_fov/2)
            test_moved = test_stat_eci + vectorFromPointDirectionAndAngle(test_fov_gnd, test_to_reference, \
                test_fov/2)

            # Compute the vector pointing from one station to the moved point of the other station
            reference_to_test_moved = vectNorm(test_moved - reference_stat_eci)
            test_to_reference_moved = vectNorm(reference_moved - test_stat_eci)

            # Check if the FOVs overlap
            if (angleBetweenVectors(reference_fov_eci, reference_to_test_moved) <= reference_fov/2) \
                or (angleBetweenVectors(test_fov_eci, test_to_reference_moved) <= test_fov/2):

                return True

        return False
Пример #10
0
def explorePointings(station_list, fixed_cameras, min_height, max_height,
                     moving_ranges, steps):
    """ Given the list of cameras, a range of heights and a range of possible movements for the camera,
        construct a map of volume overlaps for each camera position. The map will be saves as an image.

    Arguments:
        station_list: [list] A list of SimStation objects.
        fixed_cameras: [list] A list of bools indiciating if the camera is fixed or it can be moved to
            optimize the overlap.
        min_height: [float] Minimum height of the FOV polyhedron (meters).
        max_height: [float] Maximum height of the FOV polyhedron (meters).
        moving_ranges: [list] A list of possible movement for each non-fixed camera (degrees).
        steps: [int] Steps to take inside the moving range. The map will thus have a resolution of
            range/steps.

    Return:
        None
    """

    station_list = copy.deepcopy(station_list)

    k = 0

    # Use the current Julian date as the reference time (this is just used to convert the coordinated to ECI,
    # it has no operational importance whatsoever).
    jd = datetime2JD(datetime.datetime.now())

    # Go through all moving cameras
    for i, stat_moving in enumerate(station_list):

        if not fixed_cameras[i]:

            # Original centre pointing
            azim_centre_orig = stat_moving.azim_centre
            elev_centre_orig = stat_moving.elev_centre

            # Get the range of movements for this camera
            mv_range = np.radians(moving_ranges[k])
            k += 1

            volume_results = []

            d_range = np.linspace(-mv_range / 2.0, +mv_range / 2, steps)

            # Make a grid of movements
            total_runs = 1
            for elev_ind, d_elev in enumerate(d_range):
                for azim_ind, d_azim in enumerate(d_range):

                    # Calculate the azimuth of centre
                    azim = (azim_centre_orig + d_azim) % (2 * np.pi)

                    # Calculate the elevation of the centre
                    elev = elev_centre_orig + d_elev

                    if elev > np.pi / 2:
                        elev = (np.pi / 2 - elev) % (np.pi / 2)

                    if elev < 0:
                        elev = np.abs(elev)

                    # Set the new centre to the station
                    stat_moving.azim_centre = azim
                    stat_moving.elev_centre = elev

                    # Assign the changed parameter to the moving camera
                    station_list[i] = stat_moving

                    # Estimate the volume only for this moving camera
                    fix_cam = [True] * len(station_list)
                    fix_cam[i] = False

                    # Estimate the intersection volume
                    vol = stationsCommonVolume(station_list, fix_cam, jd,
                                               max_height, min_height)

                    volume_results.append([azim, elev, vol])

                    # Print status messages
                    print()
                    print('Azim: {:d}/{:d}, elev: {:d}/{:d}, total runs: {:d}/{:d}'.format(azim_ind + 1, \
                     len(d_range), elev_ind + 1, len(d_range), total_runs, \
                     len(d_range)**2))
                    print('Azim {:.2f} elev {:.2f} vol {:e}'.format(
                        np.degrees(azim), np.degrees(elev), vol))

                    total_runs += 1

            volume_results = np.array(volume_results)

            azims = volume_results[:, 0].reshape(len(d_range), len(d_range))
            elevs = volume_results[:, 1].reshape(len(d_range), len(d_range))

            # Select only the volumes
            vols = volume_results[:, 2].reshape(len(d_range), len(d_range))

            # Find the index of the largest volume
            vol_max = np.unravel_index(vols.argmax(), vols.shape)

            # Print the largest overlapping volume
            print('MAX OVERLAP:')
            print('Azim {:.2f} elev {:.2f} vol {:e}'.format(
                np.degrees(azims[vol_max]), np.degrees(elevs[vol_max]),
                vols[vol_max]))

            plt.figure()

            plt.imshow(vols/1e9, extent=np.degrees([azim_centre_orig + np.min(d_range), azim_centre_orig + np.max(d_range), elev_centre_orig + np.max(d_range), \
                elev_centre_orig + np.min(d_range)]))

            plt.gca().invert_yaxis()

            plt.xlabel('Azimuth (deg)')
            plt.ylabel('Elevation (deg)')

            plt.colorbar(label='Common volume (km^3)')

            plt.savefig('fov_map_' + stat_moving.station_id + '_ht_range_' +
                        str(min_height) + '_' + str(max_height) + '.png',
                        dpi=300)

            #plt.show()

            plt.clf()
            plt.close()
Пример #11
0
    # Steps of movement to explore
    steps = 21

    ##########################################################################################################

    # Calculate heights in meters
    min_height *= 1000
    max_height *= 1000

    # Init stations data to SimStation objects
    station_list = initStationList(stations_geo, azim_fovs, elev_fovs,
                                   fov_widths, fov_heights)

    # Show current FOV overlap
    plotStationFovs(station_list, datetime2JD(datetime.datetime.now()),
                    min_height, max_height)

    # Do an assessment for the whole range of given rights
    explorePointings(station_list, fixed_cameras, min_height, max_height,
                     moving_ranges, steps)

    # # Do the anaysis for ranges of heights

    # # Height step in kilometers
    # height_step = 5

    # height_step *= 1000

    # for ht_min in range(min_height, max_height - height_step + 1, height_step):