def test_plt_colormaps(): spec, spec_r = spectral() ja, ja_r = jade() plt_colormaps(spec, spec_r, ja, ja_r, ".") png = Path("colormaps.png") assert png.is_file() is True if png.is_file() is True: png.unlink()
---------- """ import argparse from pathlib import Path import healpy as hp import matplotlib import numpy as np from embers.rf_tools.colormaps import spectral from matplotlib import pyplot as plt from numpy.polynomial import polynomial as poly from scipy.stats import median_absolute_deviation as mad matplotlib.use("Agg") _spec, _ = spectral() colors = _spec([0.72, 0.30, 0.18]) parser = argparse.ArgumentParser(description=""" Null Sats paper plot """) parser.add_argument( "--out_dir", metavar="\b", default="../embers_out/paper_plots", help="Output directory. Default=../embers_out/paper_plots", ) parser.add_argument( "--map_dir", metavar="\b",
def good_chans( ali_file, chrono_file, sat_id, sat_thresh, noi_thresh, pow_thresh, occ_thresh, timestamp, out_dir, plots=None, ): """Determine the channels a satellite could occupy, in a 30 minute observation Ephemeris from :samp:`chrono_file` is used to select a temporal :samp:`window` of the rf power array, within which the satellite is above the horizon. Looping through the frequency channels, a :samp:`noi_thresh`, :samp:`pow_thresh`, :samp:`occ_thresh` are used to identify possible channels occupied by the :samp:`sat_id`. If more than one channel passes the three thresholds, the channel with the highest window occupancy is selected. .. code-block:: python from embers.sat_utils.sat_channels import good_chans ali_file = "~/embers_out/rf0XX_S06XX_2019-10-10-02:30_aligned.npz" chrono_file = "~/embers_out/2019-10-10-02:30.json" sat_id = "44387" sat_thresh = 1 noi_thresh = 3 pow_thresh = 20 occ_thresh = 0.80 timestamp = "2019-10-10-02:30" out_dir = "./embers_out" plots = True good_chan = good_chans( ali_file, chrono_file, sat_id, sat_thresh, noi_thresh, pow_thresh, occ_thresh, timestamp, out_dir, plots=plots) print(good_chan) >>> 59 :param ali_file: Path to a :samp:`npz` aligned file from :func:`~embers.rf_tools.align_data.save_aligned` :class:`~str` :param chrono_file: Path to chrono ephem json file from :func:`~embers.sat_utils.chrono_ephem.save_chrono_ephem` :class:`~str` :param sat_id: Norad catalogue ID :class:`~str` :param sat_thresh: Satellite threshold from :func:`~embers.sat_utils.sat_channels.noise_floor` :class:`~int` :param noi_thresh: Noise threshold from :func:`~embers.sat_utils.sat_channels.noise_floor` :class:`~int` :param pow_thresh: Minimum power threshold in :samp:`dBm` :class:`~float` :param occ_thresh: Window occupation threshold. Minimum fractional signal above the noise floor in window :class:`~float` :param timestamp: Time at start of observation in format :samp:`YYYY-MM-DD-HH:MM` :class:`~str` :param out_dir: Path to output directory to save plots :class:`~str` :param plots: If :samp:`True`, disagnostic plots are generated and saved to :samp:`out_dir` :returns: - good_chan: The channel number of most probable channel for :samp:`sat_id` - good_chan may be :samp:`None`, if no possible channels were identified """ spec, _ = spectral() power, _, times = read_aligned(ali_file=ali_file) p_med = np.median(power) # Determine noise threshold noise_threshold = noise_floor(sat_thresh, noi_thresh, power) with open(chrono_file) as chrono: chrono_ephem = json.load(chrono) # All satellites in chrono ephem json file norad_list = [ chrono_ephem[s]["sat_id"][0] for s in range(len(chrono_ephem)) ] # Index of sat_id in chrono ephem json file norad_index = norad_list.index(sat_id) # Extract ephemeris for sat_id norad_ephem = chrono_ephem[norad_index] rise_ephem = norad_ephem["time_array"][0] set_ephem = norad_ephem["time_array"][-1] # indices of times, when sat rose and set intvl = time_filter(rise_ephem, set_ephem, np.asarray(times)) # Window start, stop w_start, w_stop = intvl window_len = w_stop - w_start + 1 # Slice the power/times arrays to the times of sat pass power_c = power[w_start:w_stop + 1, :] times_c = times[w_start:w_stop + 1] # possible identified channels possible_chans = [] # window occupancy of possible channels occu_list = [] # Loop over every channel for s_chan in range(len(power_c[0])): channel_power = power_c[:, s_chan] # Percentage of signal occupancy above noise threshold window_occupancy = (np.where( channel_power >= noise_threshold))[0].size / window_len # Power threshold below which satellites aren't counted # Only continue if there is signal for more than 80% of satellite pass if (max(channel_power) >= p_med + pow_thresh and occ_thresh <= window_occupancy < 1.00): # If satellite window begins from the start of the observation if times[0] == times_c[0]: # last 10 data points (10 seconds) are below the noise threshold if (all(p < noise_threshold for p in channel_power[-11:-1])) is True: occu_list.append(window_occupancy) possible_chans.append(s_chan) if plots is True: plt = plt_channel( times_c, channel_power, p_med, s_chan, [ np.amin(channel_power) - 1, np.amax(channel_power) + 1, ], noise_threshold, pow_thresh + p_med, ) date = re.search(r"\d{4}.\d{2}.\d{2}", timestamp)[0] plt_dir = Path( f"{out_dir}/window_plots/{date}/{timestamp}") plt_dir.mkdir(parents=True, exist_ok=True) plt.savefig( f"{plt_dir}/{sat_id}_channel_{s_chan}_{window_occupancy:.2f}.png" ) plt.close() # if the satellite window ends and the end of the observation elif times[-1] == times_c[-1]: # first 10 data points (10 seconds) are below the noise threshold if (all(p < noise_threshold for p in channel_power[:10])) is True: occu_list.append(window_occupancy) possible_chans.append(s_chan) if plots is True: plt = plt_channel( times_c, channel_power, p_med, s_chan, [ np.amin(channel_power) - 1, np.amax(channel_power) + 1, ], noise_threshold, pow_thresh + p_med, ) date = re.search(r"\d{4}.\d{2}.\d{2}", timestamp)[0] plt_dir = Path( f"{out_dir}/window_plots/{date}/{timestamp}") plt_dir.mkdir(parents=True, exist_ok=True) plt.savefig( f"{plt_dir}/{sat_id}_channel_{s_chan}_{window_occupancy:.2f}.png" ) plt.close() # satellite window completely within the observation else: # first and last 10 data points (10 seconds) are below the noise threshold if (all(p < noise_threshold for p in channel_power[:10]) and all(p < noise_threshold for p in channel_power[-11:-1])) is True: occu_list.append(window_occupancy) possible_chans.append(s_chan) if plots is True: plt = plt_channel( times_c, channel_power, p_med, s_chan, [ np.amin(channel_power) - 1, np.amax(channel_power) + 1, ], noise_threshold, pow_thresh + p_med, ) date = re.search(r"\d{4}.\d{2}.\d{2}", timestamp)[0] plt_dir = Path( f"{out_dir}/window_plots/{date}/{timestamp}") plt_dir.mkdir(parents=True, exist_ok=True) plt.savefig( f"{plt_dir}/{sat_id}_channel_{s_chan}_{window_occupancy:.2f}.png" ) plt.close() # If channels are identified in the 30 min obs n_chans = len(possible_chans) if n_chans > 0: # The most probable channel is one with the highest occupation good_chan = possible_chans[occu_list.index(max(occu_list))] if plots is True: plt = plt_window_chans( power, sat_id, w_start, w_stop, spec, chs=possible_chans, good_ch=good_chan, ) date = re.search(r"\d{4}.\d{2}.\d{2}", timestamp)[0] plt_dir = Path(f"{out_dir}/window_plots/{date}/{timestamp}") plt_dir.mkdir(parents=True, exist_ok=True) plt.savefig(f"{plt_dir}/{sat_id}_waterfall_{good_chan}.png") plt.close() return good_chan else: if plots is True: plt = plt_window_chans(power, sat_id, w_start, w_stop, spec) date = re.search(r"\d{4}.\d{2}.\d{2}", timestamp)[0] plt_dir = Path(f"{out_dir}/window_plots/{date}/{timestamp}") plt_dir.mkdir(parents=True, exist_ok=True) plt.savefig(f"{plt_dir}/{sat_id}_waterfall_window.png") plt.close() return None
# Code developed by Jack Line and adapted here # https://github.com/JLBLine/MWA_ORBCOMM from pathlib import Path import healpy as hp import matplotlib import numpy as np import pkg_resources from embers.rf_tools.colormaps import spectral from embers.tile_maps.beam_utils import plot_healpix from matplotlib import pyplot as plt from scipy.interpolate import RectSphereBivariateSpline matplotlib.use("Agg") cmap, _ = spectral() def create_model(nside, file_name=None): """Takes feko .ffe reference model, converts into healpix and smooths the response :param nside: Healpix nside :param file_name: Path to :samp:`.ffe` feko model of reference tiles :returns: - :class:`tuple` of (beam_response, theta_mesh, phi_mesh, power, theta) """ # Make an empty array for healpix projection len_empty_healpix = hp.nside2npix(nside)
def test_spectral(): spec, _ = spectral() assert type(spec).__name__ == "ListedColormap"
def test_spectral_r(): _, spec_r = spectral() assert type(spec_r).__name__ == "ListedColormap"
""" Colormaps ========= Visualise custom colormaps used by embers. Creates sample plot of ember colormaps saved to :samp:`./embers_out/rf_tools/colormaps.png` """ import argparse from pathlib import Path from embers.rf_tools.colormaps import jade, plt_colormaps, spectral _spec, _spec_r = spectral() _jade, _jade_r = jade() def main(): """ Preview *EMBERS* two beautiful custom colormaps - :func:`~embers.rf_tools.colormaps.spectral` & :func:`~embers.rf_tools.colormaps.jade`. The :samp:`spectral` colormap is non-linear and is just used to visualise raw data and maximize dynamic range, while :samp:`jade` is perceptually uniform and sequential and is suitable for science. To get a preview of how amazing they are .. code-block:: console $ colormaps --help """ _parser = argparse.ArgumentParser(description="""