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
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
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
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)
# 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)')
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
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:
""" # 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')
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
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()
# 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):