mirror of
https://gitlab.science.ru.nl/mthesis-edeboone/m-thesis-introduction.git
synced 2025-05-17 05:19:24 +02:00
ZH: move airshower beacon simulation to top folder
This commit is contained in:
parent
7a7647f231
commit
dbb0352229
37 changed files with 2 additions and 2 deletions
|
@ -1,3 +0,0 @@
|
|||
config.mk
|
||||
figures
|
||||
data
|
|
@ -1,82 +0,0 @@
|
|||
.PHONY: all
|
||||
|
||||
FIG_DIR ?= ./figures
|
||||
|
||||
-include config.mk
|
||||
|
||||
MAX_K ?= 3
|
||||
CLK_DEV ?= 20
|
||||
TRACE_N ?= 4096
|
||||
TRACE_PRE ?= 500
|
||||
NOISE_SIGMA ?= 1e4
|
||||
|
||||
BEAC_AMP ?= 1e3 0 0
|
||||
BEAC_F ?= 51.53e-3
|
||||
BEAC_DECAY ?= 0
|
||||
|
||||
PB_LOW ?= 0.03
|
||||
PB_HIGH ?= 0.08
|
||||
|
||||
REF_ANTS ?=
|
||||
|
||||
N_MASK ?= 500
|
||||
|
||||
DATA_DIR ?= ./data
|
||||
INPUT_DIR ?= ./ZH_airshower/
|
||||
SEED ?= 12345
|
||||
|
||||
all: beacon clocks phases findks vary-fixes reconstruct
|
||||
|
||||
beacon: generate-beacon signal-to-noise
|
||||
phases: beacon-phase clock-phase baseline-phase antenna-phase
|
||||
|
||||
######
|
||||
|
||||
generate-beacon:
|
||||
./aa_generate_beacon.py -N ${TRACE_N} -P ${TRACE_PRE} -n ${NOISE_SIGMA} -a ${BEAC_AMP} -f ${BEAC_F} -l ${PB_LOW} -u ${PB_HIGH} -d ${BEAC_DECAY} --data-dir ${DATA_DIR} --input-fname ${INPUT_DIR} | tee ${FIG_DIR}/aa.log
|
||||
./ab_modify_clocks.py 0 --no-save-clocks --data-dir ${DATA_DIR} | tee ${FIG_DIR}/ab.log
|
||||
|
||||
signal-to-noise:
|
||||
./ac_show_signal_to_noise.py --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR}
|
||||
./view_beaconed_antenna.py 72 -p x -p y -p z -p n -p b --ft --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR}
|
||||
|
||||
#
|
||||
new-clocks:
|
||||
./ab_modify_clocks.py ${CLK_DEV} --seed ${SEED} --gaussian --data-dir ${DATA_DIR}
|
||||
|
||||
clocks:
|
||||
./ab_modify_clocks.py ${CLK_DEV} --read-clocks-file --seed ${SEED} --gaussian --data-dir ${DATA_DIR}
|
||||
|
||||
reset-clocks:
|
||||
./ab_modify_clocks.py 0 --data-dir ${DATA_DIR}
|
||||
|
||||
#
|
||||
beacon-phase:
|
||||
./ba_measure_beacon_phase.py --N-mask ${N_MASK} --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR}
|
||||
|
||||
clock-phase:
|
||||
./bb_measure_clock_phase.py --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR}
|
||||
|
||||
baseline-phase:
|
||||
./bc_baseline_phase_deltas.py ${REF_ANTS} --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR}
|
||||
|
||||
antenna-phase:
|
||||
./bd_antenna_phase_deltas.py --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR}
|
||||
|
||||
#
|
||||
findks:
|
||||
./ca_period_from_shower.py --input-fname ${INPUT_DIR} --max-k ${MAX_K} --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR} -l ${PB_LOW} -u ${PB_HIGH}
|
||||
./cb_report_measured_antenna_time_offsets.py --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR}
|
||||
|
||||
#
|
||||
vary-fixes:
|
||||
./dc_grid_power_time_fixes.py --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR} --input-fname ${INPUT_DIR}
|
||||
|
||||
#
|
||||
reconstruct:
|
||||
./da_reconstruction.py --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR} --input-fname ${INPUT_DIR}
|
||||
./db_longitudinal_figure.py --no-show-plots --fig-dir=${FIG_DIR} --data-dir ${DATA_DIR}
|
||||
|
||||
dist-clean:
|
||||
rm -vf ${DATA_DIR}/
|
||||
rm -vf ${FIG_DIR}/
|
|
@ -1,33 +0,0 @@
|
|||
# Airshower + Beacon simulation
|
||||
|
||||
Simulate receiving an airshower and beacon in an array.
|
||||
Using the beacon, the clocks can be calibrated.
|
||||
|
||||
The ZHaires simulated airshower is stored in [./ZH_airshower](./ZH_airshower).
|
||||
The produced files can be read using [./earsim](./earsim).
|
||||
|
||||
All quantities are stored in HDF5 files with the airshower data.
|
||||
|
||||
Steps:
|
||||
1. Setup
|
||||
1. Beacon ([./aa_generate_beacon.py])
|
||||
1. Define tx position
|
||||
2. Read in antennas
|
||||
3. Sample beacon at each antenna
|
||||
4. Add to relevant polarisation
|
||||
5. Save antenna traces
|
||||
|
||||
2. Timeoffset ([./ab_modify_clocks.py])
|
||||
1. Generate timeoffsets for each antenna
|
||||
2. Modify time samples
|
||||
|
||||
2. Beacon analysis
|
||||
1. Find beacon frequency and phase in antenna traces ([./ba_measure_beacon_phase.py])
|
||||
2. Remove phase due to distances
|
||||
3. Analyse the sigma between antenna pairs
|
||||
4. Remove 0j part and take the mean of (:,j)
|
||||
5. Assign mean as clock shift phase of antenna
|
||||
|
||||
3. Find k\*2\\pi phase offsets (periods) ([./ca_periods_from_showers.py])
|
||||
|
||||
4. Rewrite clocks and do interferometric reconstruction ([./da_reconstruction.py])
|
|
@ -1,2 +0,0 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -1,440 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=marker ts=4
|
||||
|
||||
"""
|
||||
Add a beacon measurement on top of the
|
||||
simulated airshower.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import json
|
||||
import h5py
|
||||
import os.path as path
|
||||
from copy import deepcopy
|
||||
|
||||
from earsim import REvent, Antenna, block_filter
|
||||
import lib
|
||||
|
||||
# {{{ vim marker
|
||||
tx_fname = 'tx.json'
|
||||
antennas_fname = 'antennas.hdf5'
|
||||
snr_fname = 'snr.json'
|
||||
c_light = lib.c_light
|
||||
|
||||
def read_antenna_clock_repair_offsets(antennas, mode='all', freq_name=None):
|
||||
valid_modes = ['orig', 'ks', 'phases', 'all']
|
||||
|
||||
time_offsets = []
|
||||
for i, ant in enumerate(antennas):
|
||||
_clock_delta = 0
|
||||
|
||||
# original timing
|
||||
if mode == 'orig':
|
||||
_clock_delta = -1*ant.attrs['clock_offset']
|
||||
|
||||
# phase
|
||||
if mode in ['all', 'phases']:
|
||||
clock_phase = ant.beacon_info[freq_name]['clock_phase_mean']
|
||||
f_beacon = ant.beacon_info[freq_name]['freq']
|
||||
clock_phase_time = clock_phase/(2*np.pi*f_beacon)
|
||||
|
||||
_clock_delta += clock_phase_time
|
||||
|
||||
# ks
|
||||
if mode in ['all', 'ks']:
|
||||
best_k_time = ant.beacon_info[freq_name]['best_k_time']
|
||||
|
||||
_clock_delta += best_k_time
|
||||
|
||||
time_offsets.append(_clock_delta)
|
||||
|
||||
return time_offsets
|
||||
|
||||
def write_snr_file(fname, snrs):
|
||||
with open(fname, 'w') as fp:
|
||||
return json.dump(
|
||||
{'mean': np.mean(snrs), 'std': np.std(snrs), 'values': snrs},
|
||||
fp
|
||||
)
|
||||
|
||||
def read_snr_file(fname):
|
||||
with open(fname, 'r') as fp:
|
||||
return json.load(fp)
|
||||
|
||||
def write_tx_file(fname, tx, f_beacon, **kwargs):
|
||||
with open(fname, 'w') as fp:
|
||||
return json.dump(
|
||||
{
|
||||
**kwargs,
|
||||
**dict(
|
||||
f_beacon=f_beacon,
|
||||
tx=dict(
|
||||
x=tx.x,
|
||||
y=tx.y,
|
||||
z=tx.z,
|
||||
name=tx.name
|
||||
)
|
||||
)
|
||||
},
|
||||
fp
|
||||
)
|
||||
|
||||
def read_tx_file(fname):
|
||||
with open(fname, 'r') as fp:
|
||||
data = json.load(fp)
|
||||
|
||||
f_beacon = data['f_beacon']
|
||||
tx = Antenna(**data['tx'])
|
||||
|
||||
del data['f_beacon']
|
||||
del data['tx']
|
||||
|
||||
return tx, f_beacon, data
|
||||
|
||||
def read_beacon_hdf5(fname, **h5ant_kwargs):
|
||||
with h5py.File(fname, 'r') as h5:
|
||||
tx = Antenna_from_h5ant(h5['tx'], traces_key=None)
|
||||
f_beacon = tx.attrs['f_beacon']
|
||||
|
||||
antennas = []
|
||||
for k, h5ant in h5['antennas'].items():
|
||||
ant = Antenna_from_h5ant(h5ant, **h5ant_kwargs)
|
||||
|
||||
antennas.append(ant)
|
||||
|
||||
return f_beacon, tx, antennas
|
||||
|
||||
def Antenna_from_h5ant(h5ant, traces_key='filtered_traces', raise_exception=True, read_AxB=True, read_beacon_info=True):
|
||||
mydict = { k:h5ant.attrs.get(k) for k in ['x', 'y', 'z', 'name'] }
|
||||
ant = Antenna(**mydict)
|
||||
if h5ant.attrs:
|
||||
ant.attrs = {**h5ant.attrs}
|
||||
|
||||
# Traces
|
||||
if traces_key is None:
|
||||
pass
|
||||
elif traces_key not in h5ant:
|
||||
if raise_exception:
|
||||
raise ValueError("Traces_key not in file")
|
||||
else:
|
||||
ant.t = deepcopy(h5ant[traces_key][0])
|
||||
ant.Ex = deepcopy(h5ant[traces_key][1])
|
||||
ant.Ey = deepcopy(h5ant[traces_key][2])
|
||||
ant.Ez = deepcopy(h5ant[traces_key][3])
|
||||
if len(h5ant[traces_key]) > 4:
|
||||
ant.beacon = deepcopy(h5ant[traces_key][4])
|
||||
if len(h5ant[traces_key]) > 5:
|
||||
ant.noise = deepcopy(h5ant[traces_key][5])
|
||||
|
||||
# E_AxB
|
||||
if read_AxB and 'E_AxB' in h5ant:
|
||||
ant.t_AxB = deepcopy(h5ant['E_AxB'][0])
|
||||
ant.E_AxB = deepcopy(h5ant['E_AxB'][1])
|
||||
|
||||
# Beacons
|
||||
if read_beacon_info and 'beacon_info' in h5ant:
|
||||
h5beacon = h5ant['beacon_info']
|
||||
|
||||
beacon_info = {}
|
||||
for name in h5beacon.keys():
|
||||
beacon_info[name] = dict(h5beacon[name].attrs)
|
||||
|
||||
ant.beacon_info = beacon_info
|
||||
|
||||
return ant
|
||||
|
||||
|
||||
def init_antenna_hdf5(fname, tx = None, f_beacon = None):
|
||||
with h5py.File(fname, 'w') as fp:
|
||||
if tx is not None or f_beacon is not None:
|
||||
tx_group = fp.create_group('tx')
|
||||
tx_attrs = tx_group.attrs
|
||||
|
||||
if f_beacon is not None:
|
||||
tx_attrs['f_beacon'] = f_beacon
|
||||
|
||||
if tx is not None:
|
||||
tx_attrs['x'] = tx.x
|
||||
tx_attrs['y'] = tx.y
|
||||
tx_attrs['z'] = tx.z
|
||||
tx_attrs['name'] = tx.name
|
||||
|
||||
return fname
|
||||
|
||||
def append_antenna_hdf5(fname, antenna, columns = [], name='traces', prepend_time=True, overwrite=True, attrs_dict={}):
|
||||
if not overwrite:
|
||||
raise NotImplementedError
|
||||
|
||||
with h5py.File(fname, 'a') as fp:
|
||||
if 'antennas' in fp.keys():
|
||||
if not overwrite:
|
||||
raise NotImplementedError
|
||||
group = fp['antennas']
|
||||
else:
|
||||
group = fp.create_group('antennas')
|
||||
|
||||
|
||||
if antenna.name in group:
|
||||
if not overwrite:
|
||||
raise NotImplementedError
|
||||
h5ant = group[antenna.name]
|
||||
else:
|
||||
h5ant = group.create_group(antenna.name)
|
||||
|
||||
h5ant_attrs = h5ant.attrs
|
||||
h5ant_attrs['x'] = antenna.x
|
||||
h5ant_attrs['y'] = antenna.y
|
||||
h5ant_attrs['z'] = antenna.z
|
||||
h5ant_attrs['name'] = antenna.name
|
||||
|
||||
for k,v in attrs_dict.items():
|
||||
h5ant_attrs[k] = v
|
||||
|
||||
if name in h5ant:
|
||||
if not overwrite:
|
||||
raise NotImplementedError
|
||||
del h5ant[name]
|
||||
|
||||
dset = h5ant.create_dataset(name, (len(columns) + 1*prepend_time, len(columns[0])), dtype='f')
|
||||
|
||||
if prepend_time:
|
||||
dset[0] = antenna.t
|
||||
|
||||
for i, col in enumerate(columns, 1*prepend_time):
|
||||
dset[i] = col
|
||||
|
||||
|
||||
def read_baseline_time_diffs_hdf5(fname):
|
||||
"""
|
||||
Read Baseline Time Diff information from HDF5 storage.
|
||||
"""
|
||||
with h5py.File(fname, 'r') as fp:
|
||||
group_name = 'baseline_time_diffs'
|
||||
base_dset_name = 'baselines'
|
||||
dset_name = 'time_diffs'
|
||||
|
||||
group = fp[group_name]
|
||||
|
||||
names = group[base_dset_name][:].astype(str)
|
||||
|
||||
dset = group[dset_name]
|
||||
time_diffs = dset[:,0]
|
||||
f_beacon = dset[:,1]
|
||||
clock_phase_diffs = dset[:,2]
|
||||
k_periods = dset[:,3]
|
||||
|
||||
return names, time_diffs, f_beacon, clock_phase_diffs, k_periods
|
||||
|
||||
|
||||
def write_baseline_time_diffs_hdf5(fname, baselines, clock_phase_diffs, k_periods, f_beacon, time_diffs=None, overwrite=True):
|
||||
"""
|
||||
Write a combination of baselines, phase_diff, k_period and f_beacon to file.
|
||||
|
||||
Note that f_beacon is allowed to broadcast, but the others are not.
|
||||
"""
|
||||
|
||||
if not hasattr(baselines[0], '__len__'):
|
||||
# this is a single baseline
|
||||
N_baselines = 1
|
||||
baselines = [baselines]
|
||||
clock_phase_diffs = [clock_phase_diffs]
|
||||
k_periods = [k_periods]
|
||||
f_beacon = np.array([f_beacon])
|
||||
|
||||
else:
|
||||
N_baselines = len(baselines)
|
||||
|
||||
# Expand the f_beacon list
|
||||
if not hasattr(f_beacon, '__len__'):
|
||||
f_beacon = np.array([f_beacon]*N_baselines)
|
||||
|
||||
if time_diffs is None:
|
||||
time_diffs = k_periods/f_beacon + clock_phase_diffs/(2*np.pi*f_beacon)
|
||||
|
||||
assert len(baselines) == len(clock_phase_diffs) == len(k_periods) == len(f_beacon)
|
||||
|
||||
with h5py.File(fname, 'a') as fp:
|
||||
group_name = 'baseline_time_diffs'
|
||||
base_dset_name = 'baselines'
|
||||
dset_name = 'time_diffs'
|
||||
|
||||
group = fp.require_group(group_name)
|
||||
|
||||
if base_dset_name in group:
|
||||
if not overwrite:
|
||||
raise NotImplementedError
|
||||
del group[base_dset_name]
|
||||
|
||||
if dset_name in group:
|
||||
if not overwrite:
|
||||
raise NotImplementedError
|
||||
del group[dset_name]
|
||||
|
||||
# save baselines list
|
||||
basenames = np.array([ [b[0].name, b[1].name] for b in baselines ], dtype='S')
|
||||
|
||||
base_dset = group.create_dataset(base_dset_name, data=basenames)
|
||||
|
||||
data = np.vstack( (time_diffs, f_beacon, clock_phase_diffs, k_periods) ).T
|
||||
dset = group.create_dataset(dset_name, data=data)
|
||||
|
||||
# }}} vim marker
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
from argparse import ArgumentParser
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('-n', '--noise-sigma', type=float, default=1e3, help='in [muV/m] (Default: %(default)d)')
|
||||
parser.add_argument('-f', '--beacon-frequency', type=float, default=51.53e-3, help='The beacon\'s frequency [GHz] (Default: %(default)d)')
|
||||
|
||||
# Beacon Properties
|
||||
parser.add_argument('-a', '--beacon-amplitudes', type=float, nargs=3, default=[1e3, 0, 0], help='in [muV/m] (Default: %(default)s)')
|
||||
parser.add_argument('-d', '--beacon-rsq-decay', type=bool, default=True, help='Let the beacon amplitude fall of with distance. Uses Beacon amplitudes at 0,0,0 (Default: %(default)d)')
|
||||
|
||||
# Bandpass
|
||||
parser.add_argument('-p', '--use-passband', type=bool, default=True, help='(Default: %(default)d)')
|
||||
parser.add_argument('-l', '--passband-low', type=float, default=30e-3, help='Lower frequency [GHz] of the passband filter. (set -1 for np.inf) (Default: %(default)g)')
|
||||
parser.add_argument('-u', '--passband-high', type=float, default=80e-3, help='Upper frequency [GHz] of the passband filter. (set -1 for np.inf) (Default: %(default)g)')
|
||||
|
||||
# Trace length modification
|
||||
parser.add_argument('-N', '--new-trace-length', type=float, help='resize airshower trace (Default: %(default)d)', default=1e4)
|
||||
parser.add_argument('-P', '--pre-trace-length', type=float, help='amount of trace to prepend the airshower when resizing (Default: %(default)d)', default=2e3)
|
||||
|
||||
# Input directory
|
||||
parser.add_argument('--input-fname', type=str, default=None, help='Path to mysim.sry, either directory or path. If empty it takes DATA_DIR and appends mysim.sry. (Default: %(default)s)')
|
||||
parser.add_argument('--data-dir', type=str, default="./ZH_airshower", help='Path to Data Directory. (Default: %(default)s)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.input_fname:
|
||||
args.input_fname = args.data_dir
|
||||
|
||||
if path.isdir(args.input_fname):
|
||||
args.input_fname = path.join(args.input_fname, "mysim.sry")
|
||||
|
||||
##
|
||||
## End of ArgumentParsing
|
||||
##
|
||||
|
||||
rng = np.random.default_rng()
|
||||
|
||||
# Noise properties
|
||||
noise_sigma = args.noise_sigma # mu V/m set to None to ignore
|
||||
unique_noise_realisations = True # a new noise realisation per antenna vs. single noise realisation shared across antennas
|
||||
|
||||
# Beacon properties
|
||||
beacon_amplitudes = np.array(args.beacon_amplitudes) # mu V/m
|
||||
beacon_radiate_rsq = args.beacon_rsq_decay # beacon_amplitude is repaired for distance to 0,0,0
|
||||
|
||||
# Beacon properties
|
||||
f_beacon = args.beacon_frequency # GHz
|
||||
|
||||
# Transmitter
|
||||
remake_tx = True
|
||||
|
||||
tx = Antenna(x=0,y=0,z=0,name='tx') # m
|
||||
if True:
|
||||
# Move tx out a long way
|
||||
tx.x, tx.y = -75e3, 75e3 # m
|
||||
elif False:
|
||||
# Move it to 0,0,0 (among the antennas)
|
||||
tx.x, tx.y = 0, 0 #m
|
||||
|
||||
# modify beacon power to be beacon_amplitude at 0,0,0
|
||||
if beacon_radiate_rsq:
|
||||
dist = lib.distance(tx, Antenna(x=0, y=0, z=0))
|
||||
|
||||
ampl = max(1, dist**2)
|
||||
|
||||
beacon_amplitudes *= ampl
|
||||
|
||||
# Bandpass for E field blockfilter
|
||||
low_bp = args.passband_low if args.passband_low >= 0 else np.inf # GHz
|
||||
high_bp = args.passband_high if args.passband_high >= 0 else np.inf # GHz
|
||||
|
||||
# Enable/Disable block_filter
|
||||
if not args.use_passband:
|
||||
block_filter = lambda x, dt, low, high: x
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
tx_fname = path.join(fname_dir, tx_fname)
|
||||
antennas_fname = path.join(fname_dir, antennas_fname)
|
||||
|
||||
# read/write tx properties
|
||||
if not path.isfile(tx_fname) or remake_tx:
|
||||
write_tx_file(tx_fname, tx, f_beacon, amplitudes=beacon_amplitudes.tolist(), radiate_rsq=beacon_radiate_rsq)
|
||||
else:
|
||||
tx, f_beacon, _ = read_tx_file(tx_fname)
|
||||
|
||||
|
||||
print("Beacon amplitude at tx [muV/m]:", beacon_amplitudes)
|
||||
print("Beacon amplitude at 0,0,0 [muV/m]:", beacon_amplitudes/ampl)
|
||||
print("Tx location:", [tx.x, tx.y, tx.z])
|
||||
print("Noise sigma [muV/m]:", noise_sigma)
|
||||
|
||||
# read in antennas
|
||||
ev = REvent(args.input_fname)
|
||||
N_antennas = len(ev.antennas)
|
||||
|
||||
# initialize hdf5 file
|
||||
init_antenna_hdf5(antennas_fname, tx, f_beacon)
|
||||
|
||||
# make beacon per antenna
|
||||
noise_realisation = np.array([0])
|
||||
for i, antenna in enumerate(ev.antennas):
|
||||
#TODO: allow to change the samplerate (2, 4, 8 ns)
|
||||
|
||||
if i%10 == 0:
|
||||
print(f"Beaconed antenna {i} out of", len(ev.antennas))
|
||||
|
||||
if args.new_trace_length: # modify trace lengths
|
||||
N_samples = len(antenna.t)
|
||||
new_N = int(args.new_trace_length)
|
||||
pre_N = int(args.pre_trace_length)
|
||||
after_N = new_N - pre_N
|
||||
|
||||
dt = antenna.t[1] - antenna.t[0]
|
||||
new_t = np.arange(-pre_N, after_N)*dt + antenna.t[0]
|
||||
|
||||
antenna.t = new_t
|
||||
|
||||
# TODO:trace extrapolation?
|
||||
antenna.Ex = np.pad(antenna.Ex, (pre_N, after_N-N_samples), mode='constant', constant_values=0)
|
||||
antenna.Ey = np.pad(antenna.Ey, (pre_N, after_N-N_samples), mode='constant', constant_values=0)
|
||||
antenna.Ez = np.pad(antenna.Ez, (pre_N, after_N-N_samples), mode='constant', constant_values=0)
|
||||
|
||||
if i%10 == 0:
|
||||
print(f"Modified trace lengths by {pre_N},{after_N-N_samples}")
|
||||
|
||||
beacon = 1e-6 * lib.beacon_from(tx, antenna, f_beacon, antenna.t, c_light=c_light, radiate_rsq=beacon_radiate_rsq) # mu V/m
|
||||
|
||||
# noise realisation
|
||||
if unique_noise_realisations or (noise_realisation == 0).all(): # either create one for every antenna, or generate a single one
|
||||
print("Noise realisation!")
|
||||
noise_realisation = 1e-6 * rng.normal(0, noise_sigma or 0, size=len(antenna.t)) # mu V/m
|
||||
|
||||
# Collect all data to be saved (with the first 3 values the E fields)
|
||||
traces = np.array([antenna.Ex, antenna.Ey, antenna.Ez, beacon, noise_realisation])
|
||||
|
||||
# add beacon and noise to relevant polarisations
|
||||
for j, amp in enumerate(beacon_amplitudes):
|
||||
traces[j] = traces[j] + amp*beacon + noise_realisation
|
||||
|
||||
append_antenna_hdf5( antennas_fname, antenna, traces, name='prefiltered_traces', prepend_time=True)
|
||||
|
||||
# .. and apply block_filter to every trace
|
||||
dt = antenna.t[1] - antenna.t[0]
|
||||
for j in range(len(traces)):
|
||||
traces[j] = block_filter(traces[j], dt, low_bp, high_bp)
|
||||
|
||||
append_antenna_hdf5( antennas_fname, antenna, traces, name='filtered_traces', prepend_time=True)
|
||||
|
||||
# Save filtered E field in E_AxB
|
||||
E_AxB = [np.dot(ev.uAxB,[ex,ey,ez]) for ex,ey,ez in zip(traces[0], traces[1], traces[2])]
|
||||
t_AxB = antenna.t
|
||||
|
||||
append_antenna_hdf5( antennas_fname, antenna, [t_AxB, E_AxB], name='E_AxB', prepend_time=False)
|
||||
|
||||
print("Antenna HDF5 file written as " + str(antennas_fname))
|
|
@ -1,122 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
"""
|
||||
Add a uniformly sampled time offset
|
||||
to the clock of each antenna.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import json
|
||||
import h5py
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
|
||||
clocks_fname = 'clocks.csv'
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('max_clock_offset', nargs='?', type=float, default=25, help='(Default: %(default)d)')
|
||||
parser.add_argument('-s', '--seed', type=int, nargs='?', default=None, help='Fix seed if supplied.')
|
||||
parser.add_argument('--uniform', action='store_const', const='uniform', dest='dist_type')
|
||||
parser.add_argument('--gaussian', action='store_const', const='gauss', dest='dist_type')
|
||||
parser.add_argument('-r','--read-clocks-file', action='store_true', dest='read_clocks_file')
|
||||
parser.add_argument('--no-save-clocks', action='store_false', dest='save_clocks')
|
||||
parser.set_defaults(dist_type='gauss')
|
||||
|
||||
parser.add_argument('--data-dir', type=str, default="./data", help='Path to Data Directory. (Default: %(default)s)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
max_clock_offset = args.max_clock_offset # ns
|
||||
remake_clock_offsets = True
|
||||
|
||||
seed = args.seed
|
||||
rng = np.random.default_rng(seed)
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
clocks_fname = path.join(fname_dir, clocks_fname)
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
|
||||
|
||||
if path.isfile(clocks_fname) and not remake_clock_offsets:
|
||||
print("Clock offsets previously generated")
|
||||
sys.exit()
|
||||
|
||||
if not path.isfile(antennas_fname):
|
||||
print("Antenna file cannot be found, did you try generating a beacon?")
|
||||
sys.exit(1)
|
||||
|
||||
# read in antennas
|
||||
with h5py.File(antennas_fname, 'a') as fp:
|
||||
if 'antennas' not in fp.keys():
|
||||
print("Antenna file corrupted? no antennas")
|
||||
sys.exit(1)
|
||||
|
||||
group = fp['antennas']
|
||||
|
||||
N_antennas = len(group.keys())
|
||||
|
||||
if args.read_clocks_file and path.isfile(clocks_fname): # read clock deviations from file
|
||||
print(f"Reading clocks from {clocks_fname}.")
|
||||
clock_offsets = np.loadtxt(clocks_fname)
|
||||
|
||||
elif True: # random clock deviations
|
||||
print(f"Modifying clocks upto {max_clock_offset}ns.")
|
||||
clock_offsets = np.zeros( N_antennas )
|
||||
if args.dist_type == 'uniform': # uniform
|
||||
print("Uniform distribution")
|
||||
clock_offsets = max_clock_offset * (2*rng.uniform(size=N_antennas) - 1)
|
||||
else: # normal
|
||||
print("Gaussian distribution")
|
||||
clock_offsets = max_clock_offset * rng.normal(0, 1, size=N_antennas)
|
||||
else: # Hardcoded offsets
|
||||
print("Hardcoded offsets")
|
||||
|
||||
f_beacon = 51.53e-3 # GHz
|
||||
|
||||
clock_offsets = np.zeros( N_antennas )
|
||||
if False:
|
||||
clock_offsets[59] = np.pi/2 / (2*np.pi*f_beacon)
|
||||
elif True:
|
||||
clock_offsets += 1/8 * 1/f_beacon
|
||||
print(clock_offsets)
|
||||
|
||||
|
||||
# modify time values of each antenna
|
||||
trace_key = 'filtered_traces'
|
||||
for i, name in enumerate(group.keys()):
|
||||
h5ant = group[name]
|
||||
clk_offset = clock_offsets[i]
|
||||
|
||||
|
||||
if trace_key not in h5ant.keys():
|
||||
print(f"Antenna file corrupted? no 'traces' in {name}")
|
||||
sys.exit(1)
|
||||
|
||||
h5ant_attrs = h5ant.attrs
|
||||
if 'clock_offset' in h5ant_attrs:
|
||||
tmp_offset = h5ant_attrs['clock_offset']
|
||||
if remake_clock_offsets:
|
||||
h5ant[trace_key][0, :] -= tmp_offset
|
||||
h5ant['E_AxB'][0, :] -= tmp_offset
|
||||
else:
|
||||
clock_offsets[i] = tmp_offset
|
||||
continue
|
||||
|
||||
h5ant_attrs['clock_offset'] = clk_offset
|
||||
h5ant[trace_key][0, :] += clk_offset
|
||||
h5ant['E_AxB'][0, :] += clk_offset
|
||||
|
||||
# save to simple csv
|
||||
if args.save_clocks:
|
||||
np.savetxt(clocks_fname, clock_offsets)
|
||||
|
||||
print("Antenna clocks modified in " + str(antennas_fname))
|
|
@ -1,138 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
"""
|
||||
Show Signal to noise for the original simulation signal,
|
||||
the beacon signal and the combined signal for each antenna
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import h5py
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
from earsim import REvent, block_filter
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
import matplotlib
|
||||
import os
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
|
||||
# Bandpass
|
||||
parser.add_argument('-p', '--use-passband', type=bool, default=True, help='(Default: %(default)d)')
|
||||
parser.add_argument('-l', '--passband-low', type=float, default=30e-3, help='Lower frequency [GHz] of the passband filter. (set -1 for np.inf) (Default: %(default)d)')
|
||||
parser.add_argument('-u', '--passband-high', type=float, default=80e-3, help='Upper frequency [GHz] of the passband filter. (set -1 for np.inf) (Default: %(default)d)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
fig_dir = args.fig_dir
|
||||
show_plots = args.show_plots
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
tx_fname = path.join(fname_dir, beacon.tx_fname)
|
||||
snr_fname = path.join(fname_dir, beacon.snr_fname)
|
||||
|
||||
# create fig_dir
|
||||
if fig_dir:
|
||||
os.makedirs(fig_dir, exist_ok=True)
|
||||
|
||||
# Read in antennas from file
|
||||
f_beacon, tx, antennas = beacon.read_beacon_hdf5(antennas_fname, traces_key='filtered_traces')
|
||||
_, __, txdata = beacon.read_tx_file(tx_fname)
|
||||
|
||||
# general properties
|
||||
dt = antennas[0].t[1] - antennas[0].t[0] # ns
|
||||
beacon_pb = lib.passband(f_beacon, None) # GHz
|
||||
beacon_amp = np.max(txdata['amplitudes'])# mu V/m
|
||||
|
||||
# General Bandpass
|
||||
low_bp = args.passband_low if args.passband_low >= 0 else np.inf # GHz
|
||||
high_bp = args.passband_high if args.passband_high >= 0 else np.inf # GHz
|
||||
pb = lib.passband(low_bp, high_bp) # GHz
|
||||
|
||||
noise_pb = pb
|
||||
|
||||
if args.use_passband: # Apply filter to raw beacon/noise to compare with Filtered Traces
|
||||
myfilter = lambda x: block_filter(x, dt, pb[0], pb[1])
|
||||
else: # Compare raw beacon/noise with Filtered Traces
|
||||
myfilter = lambda x: x
|
||||
|
||||
##
|
||||
## Debug plot of Beacon vs Noise SNR
|
||||
##
|
||||
if True:
|
||||
ant = antennas[0]
|
||||
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
_ = lib.signal_to_noise(myfilter(beacon_amp*ant.beacon), myfilter(ant.noise), samplerate=1/dt, signal_band=beacon_pb, noise_band=noise_pb, debug_ax=ax)
|
||||
|
||||
ax.set_title("Spectra and passband")
|
||||
ax.set_xlabel("Frequency")
|
||||
ax.set_ylabel("Amplitude")
|
||||
low_x, high_x = min(beacon_pb[0], noise_pb[0]), max(beacon_pb[1] or 0, noise_pb[1])
|
||||
ax.set_xlim(low_x, high_x)
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".debug_plot.pdf"))
|
||||
##
|
||||
## Beacon vs Noise SNR
|
||||
##
|
||||
if True:
|
||||
N_samples = len(antennas[0].beacon)
|
||||
beacon_snrs = [ lib.signal_to_noise(myfilter(beacon_amp*ant.beacon), myfilter(ant.noise), samplerate=1/dt, signal_band=beacon_pb, noise_band=noise_pb) for i, ant in enumerate(antennas) ]
|
||||
|
||||
# write mean and std to file
|
||||
beacon.write_snr_file(snr_fname, beacon_snrs)
|
||||
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title(f"Maximum Beacon/Noise SNR (N_samples:{N_samples:.1e})")
|
||||
ax.set_xlabel("Antenna no.")
|
||||
ax.set_ylabel("SNR")
|
||||
ax.plot([ int(ant.name) for ant in antennas], beacon_snrs, 'o', ls='none')
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".beacon_vs_noise_snr.pdf"))
|
||||
|
||||
##
|
||||
## Beacon vs Total SNR
|
||||
##
|
||||
if True:
|
||||
beacon_snrs = [ lib.signal_to_noise(myfilter(beacon_amp*ant.beacon), ant.E_AxB, samplerate=1/dt, signal_band=beacon_pb, noise_band=pb) for ant in antennas ]
|
||||
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title("Maximum Beacon/Total SNR")
|
||||
ax.set_xlabel("Antenna no.")
|
||||
ax.set_ylabel("SNR")
|
||||
ax.plot([ int(ant.name) for ant in antennas], beacon_snrs, 'o', ls='none')
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".beacon_vs_total_snr.pdf"))
|
||||
##
|
||||
## Airshower signal vs Noise SNR
|
||||
##
|
||||
if True:
|
||||
shower_snrs = [ lib.signal_to_noise(ant.E_AxB, myfilter(ant.noise), samplerate=1/dt, signal_band=pb, noise_band=pb) for ant in antennas ]
|
||||
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title("Total (Signal+Beacon+Noise)/Noise SNR")
|
||||
ax.set_xlabel("Antenna no.")
|
||||
ax.set_ylabel("SNR")
|
||||
ax.plot([ int(ant.name) for ant in antennas], shower_snrs, 'o', ls='none')
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".total_snr.pdf"))
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,327 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
"""
|
||||
Find beacon phases in antenna traces
|
||||
And save these to a file
|
||||
"""
|
||||
|
||||
import h5py
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import figlib
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
import matplotlib
|
||||
import os
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
|
||||
group1 = parser.add_mutually_exclusive_group()
|
||||
group1.add_argument('--AxB', dest='use_AxB_trace', action='store_true', help='Only use AxB trace, if both AxB and beacon are not used, we use the antenna polarisations.')
|
||||
group1.add_argument('--beacon', dest='use_beacon_trace', action='store_true', help='Only use the beacon trace')
|
||||
|
||||
parser.add_argument('--N-mask', type=float, default=500, help='Mask N_MASK samples around the absolute maximum of the trace. (Default: %(default)d)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
f_beacon_band = (49e-3,55e-3) #GHz
|
||||
allow_frequency_fitting = False
|
||||
read_frequency_from_file = True
|
||||
N_mask = int(args.N_mask)
|
||||
|
||||
use_only_AxB_trace = args.use_AxB_trace
|
||||
use_only_beacon_trace = args.use_beacon_trace # only applicable if AxB = False
|
||||
|
||||
show_plots = args.show_plots
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
print("use_only_AxB_trace:", use_only_AxB_trace, "use_only_beacon_trace:", use_only_beacon_trace)
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
snr_fname = path.join(fname_dir, beacon.snr_fname)
|
||||
|
||||
fig_dir = args.fig_dir # set None to disable saving
|
||||
|
||||
if not path.isfile(antennas_fname):
|
||||
print("Antenna file cannot be found, did you try generating a beacon?")
|
||||
sys.exit(1)
|
||||
|
||||
# read in antennas
|
||||
with h5py.File(antennas_fname, 'a') as fp:
|
||||
if 'antennas' not in fp.keys():
|
||||
print("Antenna file corrupted? no antennas")
|
||||
sys.exit(1)
|
||||
|
||||
group = fp['antennas']
|
||||
|
||||
f_beacon = None
|
||||
if read_frequency_from_file and 'tx' in fp:
|
||||
tx = fp['tx']
|
||||
if 'f_beacon' in tx.attrs:
|
||||
f_beacon = tx.attrs['f_beacon']
|
||||
else:
|
||||
print("No frequency found in file.")
|
||||
sys.exit(2)
|
||||
f_beacon_estimate_band = 0.01*f_beacon
|
||||
|
||||
elif allow_frequency_fitting:
|
||||
f_beacon_estimate_band = (f_beacon_band[1] - f_beacon_band[0])/2
|
||||
f_beacon = f_beacon_band[1] - f_beacon_estimate_band
|
||||
else:
|
||||
print("Not allowed to fit frequency and no tx group found in file.")
|
||||
sys.exit(2)
|
||||
|
||||
N_antennas = len(group.keys())
|
||||
# just for funzies
|
||||
found_data = np.zeros((N_antennas, 3)) # freq, phase, amp
|
||||
noise_data = np.zeros((N_antennas, 2)) # phase, amp
|
||||
|
||||
# Determine frequency and phase
|
||||
for i, name in enumerate(group.keys()):
|
||||
h5ant = group[name]
|
||||
|
||||
# use E_AxB only instead of polarisations
|
||||
if use_only_AxB_trace:
|
||||
traces_key = 'E_AxB'
|
||||
if traces_key not in h5ant.keys():
|
||||
print(f"Antenna does not have '{traces_key}' in {name}")
|
||||
sys.exit(1)
|
||||
|
||||
traces = h5ant[traces_key]
|
||||
t_trace = traces[0]
|
||||
test_traces = [ traces[1] ]
|
||||
orients = ['E_AxB']
|
||||
|
||||
# Only beacon
|
||||
elif use_only_beacon_trace:
|
||||
traces_key = 'filtered_traces'
|
||||
if traces_key not in h5ant.keys():
|
||||
print(f"Antenna file corrupted? no '{traces_key}' in {name}")
|
||||
sys.exit(1)
|
||||
|
||||
traces = h5ant[traces_key]
|
||||
t_trace = traces[0]
|
||||
test_traces = [traces[4]]
|
||||
orients = ['B']
|
||||
|
||||
# use separate polarisations
|
||||
else:
|
||||
traces_key = 'filtered_traces'
|
||||
if traces_key not in h5ant.keys():
|
||||
print(f"Antenna file corrupted? no '{traces_key}' in {name}")
|
||||
sys.exit(1)
|
||||
|
||||
traces = h5ant[traces_key]
|
||||
t_trace = traces[0]
|
||||
test_traces = [traces[i] for i in range(1,4)]
|
||||
orients = ['Ex', 'Ey', 'Ez']
|
||||
|
||||
# Really only select the first component
|
||||
if True:
|
||||
test_traces = [test_traces[0]]
|
||||
orients = [orients[0]]
|
||||
|
||||
# TODO: refine masking
|
||||
# use beacon but remove where E_AxB-Beacon != 0
|
||||
# Uses the first traces as reference
|
||||
t_mask = 0
|
||||
if N_mask and orients[0] != 'B':
|
||||
N_pre, N_post = N_mask//2, N_mask//2
|
||||
|
||||
max_idx = np.argmax(test_traces[0])
|
||||
|
||||
low_idx = max(0, max_idx-N_pre)
|
||||
high_idx = min(len(t_trace), max_idx+N_post)
|
||||
|
||||
t_mask = np.ones(len(t_trace), dtype=bool)
|
||||
t_mask[low_idx:high_idx] = False
|
||||
|
||||
t_trace = t_trace[t_mask]
|
||||
for j, t in enumerate(test_traces):
|
||||
test_traces[j] = t[t_mask]
|
||||
orients[j] = orients[j] + ' masked'
|
||||
|
||||
# Do Fourier Transforms
|
||||
# to find phases and amplitudes
|
||||
if True:
|
||||
freqs, beacon_phases, amps = lib.find_beacon_in_traces(
|
||||
test_traces, t_trace,
|
||||
f_beacon_estimate=f_beacon,
|
||||
frequency_fit=allow_frequency_fitting,
|
||||
f_beacon_estimate_band=f_beacon_estimate_band
|
||||
)
|
||||
else:
|
||||
# Testing
|
||||
freqs = [f_beacon]
|
||||
t0 = h5ant.attrs['t0']
|
||||
|
||||
beacon_phases = [ 2*np.pi*t0*f_beacon ]
|
||||
amps = [ 3e-7 ]
|
||||
|
||||
# Also try to find the phase from the noise trace if available
|
||||
if len(h5ant[traces_key]) > 4:
|
||||
noise_trace = h5ant[traces_key][5]
|
||||
if np.any(t_mask): # Mask the same area
|
||||
noise_trace = noise_trace[t_mask]
|
||||
|
||||
real, imag = lib.direct_fourier_transform(f_beacon, t_trace, noise_trace)
|
||||
noise_phase = np.arctan2(imag, real)
|
||||
noise_amp = (real**2 + imag**2)**0.5
|
||||
|
||||
noise_data[i] = noise_phase, noise_amp
|
||||
|
||||
# choose highest amp
|
||||
idx = np.argmax(amps)
|
||||
if False and len(beacon_phases) > 1:
|
||||
#idx = np.argmax(amplitudes, axis=-1)
|
||||
raise NotImplementedError
|
||||
|
||||
frequency = freqs[idx]
|
||||
beacon_phase = beacon_phases[idx]
|
||||
amplitude = amps[idx]
|
||||
orientation = orients[idx]
|
||||
|
||||
# Correct for phase by t_trace[0]
|
||||
corr_phase = lib.phase_mod(2*np.pi*f_beacon*t_trace[0])
|
||||
if False:
|
||||
# Subtract phase due to not starting at t=0
|
||||
# This is already done in beacon_find_traces
|
||||
beacon_phase = lib.phase_mod(beacon_phase + corr_phase)
|
||||
|
||||
# for reporting using plots
|
||||
found_data[i] = frequency, beacon_phase, amplitude
|
||||
|
||||
if (show_plots or fig_dir) and (i == 0 or i == 72):
|
||||
p2t = lambda phase: phase/(2*np.pi*f_beacon)
|
||||
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title(f"Beacon at antenna {h5ant.attrs['name']}\nF:{frequency:.2e}, P:{beacon_phase:.4f}, A:{amplitude:.1e}")
|
||||
ax.set_xlabel("t [ns]")
|
||||
ax.set_ylabel("Amplitude")
|
||||
|
||||
if True:
|
||||
# let the trace start at t=0
|
||||
t_0 = min(t_trace)
|
||||
extra_phase = corr_phase
|
||||
else:
|
||||
t_0 = 0
|
||||
extra_phase = -1*corr_phase
|
||||
|
||||
for j, trace in enumerate(test_traces):
|
||||
ax.plot(t_trace - t_0, test_traces[j], marker='.', label='trace '+orients[j])
|
||||
|
||||
myt = np.linspace(min(t_trace), max(t_trace), 10*len(t_trace)) - t_0
|
||||
ax.plot(myt, lib.sine_beacon(frequency, myt, amplitude=amplitude, t0=0, phase=beacon_phase+extra_phase), ls='dotted', label='simulated beacon')
|
||||
|
||||
ax.axvline( p2t(lib.phase_mod(-1*(beacon_phase+extra_phase), low=0)), color='r', ls='dashed', label='$t_\\varphi$')
|
||||
|
||||
ax.axvline(0,color='grey',alpha=0.5)
|
||||
ax.axhline(0,color='grey',alpha=0.5)
|
||||
|
||||
ax.legend()
|
||||
|
||||
if fig_dir:
|
||||
old_xlims = ax.get_xlim()
|
||||
ax.set_xlim(min(t_trace)-t_0-10,min(t_trace)-t_0+40)
|
||||
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".A{h5ant.attrs['name']}.zoomed.pdf"))
|
||||
|
||||
ax.set_xlim(*old_xlims)
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".A{h5ant.attrs['name']}.pdf"))
|
||||
|
||||
# save to file
|
||||
h5beacon_info = h5ant.require_group('beacon_info')
|
||||
|
||||
# only take n_sig significant digits into account
|
||||
# for naming in hdf5 file
|
||||
n_sig = 3
|
||||
decimal = int(np.floor(np.log10(abs(frequency))))
|
||||
freq_name = str(np.around(frequency, n_sig-decimal))
|
||||
|
||||
# delete previous values
|
||||
if freq_name in h5beacon_info:
|
||||
del h5beacon_info[freq_name]
|
||||
|
||||
h5beacon_freq_info = h5beacon_info.create_group(freq_name)
|
||||
|
||||
h5attrs = h5beacon_freq_info.attrs
|
||||
h5attrs['freq'] = frequency
|
||||
h5attrs['beacon_phase'] = beacon_phase
|
||||
h5attrs['amplitude'] = amplitude
|
||||
h5attrs['orientation'] = orientation
|
||||
|
||||
if noise_phase:
|
||||
h5attrs['noise_phase'] = noise_phase
|
||||
h5attrs['noise_amp'] = noise_amp
|
||||
|
||||
print("Beacon Phases, Amplitudes and Frequencies written to", antennas_fname)
|
||||
|
||||
# show histogram of found frequencies
|
||||
if show_plots or fig_dir:
|
||||
snrs = beacon.read_snr_file(snr_fname)
|
||||
|
||||
if True or allow_frequency_fitting:
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_xlabel("Frequency")
|
||||
ax.set_ylabel("Counts")
|
||||
ax.axvline(f_beacon, ls='dashed', color='g')
|
||||
ax.hist(found_data[:,0], bins='sqrt', density=False)
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".hist_freq.pdf"))
|
||||
|
||||
if True:
|
||||
fig, _ = figlib.fitted_histogram_figure(found_data[:,2], fit_distr=[], mean_snr=snrs['mean'])
|
||||
ax = fig.axes[0]
|
||||
ax.set_xlabel("Amplitude")
|
||||
ax.set_ylabel("Counts")
|
||||
ax.hist(found_data[:,2], bins='sqrt', density=False)
|
||||
ax.legend()
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".hist_amp.pdf"))
|
||||
|
||||
if (noise_data[0] != 0).any():
|
||||
if True:
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title("Noise Phases")
|
||||
ax.set_xlabel("Phase")
|
||||
ax.set_ylabel("#")
|
||||
ax.hist(noise_data[:,0], bins='sqrt', density=False)
|
||||
ax.legend()
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".noise.hist_phase.pdf"))
|
||||
|
||||
if True:
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title("Noise Phase vs Amplitude")
|
||||
ax.set_xlabel("Phase")
|
||||
ax.set_ylabel("Amplitude [a.u.]")
|
||||
ax.plot(noise_data[:,0], noise_data[:,1], ls='none', marker='x')
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".noise.phase_vs_amp.pdf"))
|
||||
|
||||
if True:
|
||||
fig, _ = figlib.fitted_histogram_figure(noise_data[:,1], fit_distr=['rice', 'rayleigh'], mean_snr=snrs['mean'])
|
||||
ax = fig.axes[0]
|
||||
ax.set_title("Noise Amplitudes")
|
||||
ax.set_xlabel("Amplitude [a.u.]")
|
||||
ax.set_ylabel("#")
|
||||
ax.legend()
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".noise.hist_amp.pdf"))
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,197 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
import h5py
|
||||
from itertools import combinations, zip_longest
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import figlib
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
args = parser.parse_args()
|
||||
|
||||
figsize = (12,8)
|
||||
c_light = lib.c_light
|
||||
show_plots = args.show_plots
|
||||
|
||||
remove_absolute_phase_offset_first_antenna = True # takes precedence
|
||||
remove_absolute_phase_offset_minimum = True
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
snr_fname = path.join(fname_dir, beacon.snr_fname)
|
||||
|
||||
fig_dir = args.fig_dir # set None to disable saving
|
||||
|
||||
if not path.isfile(antennas_fname):
|
||||
print("Antenna file cannot be found, did you try generating a beacon?")
|
||||
sys.exit(1)
|
||||
|
||||
# Read in antennas from file
|
||||
f_beacon, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
|
||||
# Make sure at least one beacon has been identified
|
||||
if not hasattr(antennas[0], 'beacon_info') or len(antennas[0].beacon_info) == 0:
|
||||
print(f"No analysed beacon found for {antennas[0].name}, try running the beacon phase analysis script first.")
|
||||
sys.exit(1)
|
||||
|
||||
#
|
||||
N_beacon_freqs = len(antennas[0].beacon_info)
|
||||
|
||||
for freq_name in antennas[0].beacon_info.keys():
|
||||
beacon_phases = np.empty( (len(antennas)) )
|
||||
for i, ant in enumerate(antennas):
|
||||
beacon_phases[i] = ant.beacon_info[freq_name]['beacon_phase']
|
||||
|
||||
f_beacon = antennas[0].beacon_info[freq_name]['freq']
|
||||
|
||||
clock_phases = lib.remove_antenna_geometry_phase(tx, antennas, f_beacon, beacon_phases, c_light=c_light)
|
||||
|
||||
# Remove the phase from one antenna
|
||||
# this is a free parameter
|
||||
# (only required for absolute timing)
|
||||
if remove_absolute_phase_offset_first_antenna or remove_absolute_phase_offset_minimum:
|
||||
if remove_absolute_phase_offset_first_antenna: # just take the first phase
|
||||
minimum_phase = clock_phases[0]
|
||||
else: # take the minimum
|
||||
minimum_phase = np.min(clock_phases, axis=-1)
|
||||
|
||||
clock_phases -= minimum_phase
|
||||
clock_phases = lib.phase_mod(clock_phases)
|
||||
|
||||
# Save to antennas in file
|
||||
with h5py.File(antennas_fname, 'a') as fp:
|
||||
h5group = fp['antennas']
|
||||
|
||||
for i, ant in enumerate(antennas):
|
||||
h5ant = fp['antennas'][ant.name]
|
||||
|
||||
h5beacon_freq = h5ant['beacon_info'][freq_name]
|
||||
h5beacon_freq.attrs['clock_phase'] = clock_phases[i]
|
||||
|
||||
# Plot True Phases at their locations
|
||||
if show_plots or fig_dir:
|
||||
actual_clock_phases = lib.phase_mod(np.array([ -2*np.pi*a.attrs['clock_offset']*f_beacon for a in antennas ]))
|
||||
for i in range(2):
|
||||
plot_residuals = i == 1
|
||||
spatial_unit='m'
|
||||
|
||||
antenna_locs = list(zip(*[(ant.x, ant.y) for ant in antennas]))
|
||||
|
||||
scatter_kwargs = {}
|
||||
scatter_kwargs['cmap'] = 'inferno'
|
||||
|
||||
# Measurements
|
||||
if not plot_residuals:
|
||||
title='Clock phases'
|
||||
color_label='$\\varphi(\\sigma_t)$ [rad]'
|
||||
|
||||
fname_extra='measured.'
|
||||
|
||||
#scatter_kwargs['vmin'] = -np.pi
|
||||
#scatter_kwargs['vmax'] = +np.pi
|
||||
|
||||
# Plot Clock Phases - True Clock Phases at their location
|
||||
else:
|
||||
title='Clock phase Residuals'
|
||||
color_label='$\\Delta\\varphi(\\sigma_t) = \\varphi_{meas} - \\varphi_{true}$ [rad]'
|
||||
|
||||
fname_extra='residuals.'
|
||||
|
||||
# Modify actual_clock_phases, the same way as clock_phases
|
||||
# was modified
|
||||
if remove_absolute_phase_offset_first_antenna or remove_absolute_phase_offset_minimum:
|
||||
if remove_absolute_phase_offset_first_antenna: # just take the first phase
|
||||
minimum_phase = actual_clock_phases[0]
|
||||
else: # take the minimum
|
||||
minimum_phase = np.min(actual_clock_phases, axis=-1)
|
||||
|
||||
actual_clock_phases -= minimum_phase
|
||||
actual_clock_phases = lib.phase_mod(actual_clock_phases)
|
||||
|
||||
clock_phase_residuals = lib.phase_mod(clock_phases - actual_clock_phases)
|
||||
|
||||
if not plot_residuals:
|
||||
loc_c = clock_phases
|
||||
else:
|
||||
loc_c = clock_phase_residuals
|
||||
|
||||
##
|
||||
## Geometrical Plot
|
||||
##
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
|
||||
ax.set_xlabel('x' if spatial_unit is None else 'x [{}]'.format(spatial_unit))
|
||||
ax.set_ylabel('y' if spatial_unit is None else 'y [{}]'.format(spatial_unit))
|
||||
|
||||
fig.suptitle(title+'\nf_beacon= {:2.0f}MHz'.format(f_beacon*1e3))
|
||||
|
||||
sc = ax.scatter(*antenna_locs, c=loc_c, **scatter_kwargs)
|
||||
fig.colorbar(sc, ax=ax, label=color_label)
|
||||
|
||||
if False:
|
||||
for i, ant in enumerate(antennas):
|
||||
ax.text(ant.x, ant.y, ant.name)
|
||||
|
||||
if not True:
|
||||
ax.plot(tx.x, tx.y, 'X', color='k', markeredgecolor='white')
|
||||
|
||||
if fig_dir:
|
||||
fig.tight_layout()
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".geom.{fname_extra}F{freq_name}.pdf"))
|
||||
|
||||
##
|
||||
## Histogram
|
||||
##
|
||||
snrs = beacon.read_snr_file(snr_fname)
|
||||
|
||||
fig = figlib.phase_comparison_figure(
|
||||
loc_c,
|
||||
actual_clock_phases,
|
||||
plot_residuals=plot_residuals,
|
||||
f_beacon=f_beacon,
|
||||
figsize=figsize,
|
||||
fit_gaussian=plot_residuals,
|
||||
mean_snr=snrs['mean']
|
||||
)
|
||||
|
||||
if plot_residuals:
|
||||
fig.suptitle("Difference between Measured and True Clock phases")
|
||||
else:
|
||||
fig.suptitle("Comparison Measured and True Clock Phases")
|
||||
|
||||
axs = fig.get_axes()
|
||||
axs[-1].set_xlabel(f'Antenna {title} {color_label}')
|
||||
|
||||
#
|
||||
i=0
|
||||
secax = axs[i].child_axes[0]
|
||||
secax.set_xlabel('Time $\\Delta\\varphi/(2\\pi f_{beac})$ [ns]')
|
||||
|
||||
#
|
||||
i=1
|
||||
axs[i].set_ylabel("Antenna no.")
|
||||
|
||||
# Save figure
|
||||
if fig_dir:
|
||||
fig.tight_layout()
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".{fname_extra}F{freq_name}.pdf"))
|
||||
|
||||
print(f"True phases written to", antennas_fname)
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,156 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
import h5py
|
||||
from itertools import combinations, product
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import figlib
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
parser.add_argument('ref_ant_idx', default=None, nargs='*', type=int, help='Reference Antenna Indices for Baselines(ref_ant_idx, *). Leave empty to use all available antennas. (Default: %(default)s) ')
|
||||
args = parser.parse_args()
|
||||
|
||||
figsize = (12,8)
|
||||
c_light = 3e8*1e-9
|
||||
show_plots = args.show_plots
|
||||
ref_ant_id = args.ref_ant_idx # leave None for all baselines
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
time_diffs_fname = 'time_diffs.hdf5' if False else antennas_fname
|
||||
|
||||
fig_dir = args.fig_dir # set None to disable saving
|
||||
|
||||
if not path.isfile(antennas_fname):
|
||||
print("Antenna file cannot be found, did you try generating a beacon?")
|
||||
sys.exit(1)
|
||||
|
||||
# Read in antennas from file
|
||||
f_beacon, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
|
||||
# run over all baselines
|
||||
if not ref_ant_id:
|
||||
print("Doing all baselines")
|
||||
baselines = combinations(antennas,2)
|
||||
|
||||
# use ref_ant
|
||||
else:
|
||||
ref_ants = [antennas[i] for i in ref_ant_id]
|
||||
print("Doing all baselines with {}".format([int(a.name) for a in ref_ants]))
|
||||
baselines = product(ref_ants, antennas)
|
||||
|
||||
# For now, only one beacon_frequency is supported
|
||||
freq_names = antennas[0].beacon_info.keys()
|
||||
if len(freq_names) > 1:
|
||||
raise NotImplementedError
|
||||
|
||||
freq_name = next(iter(freq_names))
|
||||
|
||||
# Collect baselines from optional generators
|
||||
baselines = list(baselines)
|
||||
|
||||
# Get phase difference per baseline
|
||||
|
||||
phase_diffs = np.empty( (len(baselines), 2) )
|
||||
for i, base in enumerate(baselines):
|
||||
if i%1000==0:
|
||||
print(i, "out of", len(baselines))
|
||||
|
||||
# read f_beacon from the first antenna
|
||||
f_beacon = base[0].beacon_info[freq_name]['freq']
|
||||
|
||||
# Get true phase diffs
|
||||
try:
|
||||
clock_phases = np.array([ant.beacon_info[freq_name]['clock_phase'] for ant in base])
|
||||
clock_phases_diff = lib.phase_mod(lib.phase_mod(clock_phases[1]) - lib.phase_mod(clock_phases[0]))
|
||||
except IndexError:
|
||||
# clock_phase not determined yet
|
||||
print(f"Missing clock_phases for {freq_name} in baseline {base[0].name},{base[1].name}")
|
||||
clock_phases_diff = np.nan
|
||||
|
||||
# save phase difference with antenna names
|
||||
phase_diffs[i] = [f_beacon, clock_phases_diff]
|
||||
|
||||
beacon.write_baseline_time_diffs_hdf5(time_diffs_fname, baselines, phase_diffs[:,1], [0]*len(phase_diffs), phase_diffs[:,0])
|
||||
|
||||
##############################
|
||||
# Compare actual time shifts #
|
||||
##############################
|
||||
actual_antenna_clock_phases = { a.name: -2*np.pi*a.attrs['clock_offset']*f_beacon for a in sorted(antennas, key=lambda a: int(a.name)) }
|
||||
|
||||
# Compare actual time shifts
|
||||
my_phase_diffs = []
|
||||
for i,b in enumerate(baselines):
|
||||
actual_clock_phase_diff = lib.phase_mod( lib.phase_mod(actual_antenna_clock_phases[b[1].name]) - lib.phase_mod(actual_antenna_clock_phases[b[0].name]))
|
||||
|
||||
this_actual_clock_phase_diff = lib.phase_mod( actual_clock_phase_diff )
|
||||
my_phase_diffs.append(this_actual_clock_phase_diff)
|
||||
|
||||
# Make a plot
|
||||
if True:
|
||||
N_base = len(baselines)
|
||||
N_ant = len(antennas)
|
||||
|
||||
for i in range(2):
|
||||
plot_residuals = i == 1
|
||||
|
||||
true_phases = my_phase_diffs
|
||||
measured_phases = phase_diffs[:,1]
|
||||
|
||||
hist_kwargs = {}
|
||||
if plot_residuals:
|
||||
measured_phases = lib.phase_mod(measured_phases - true_phases)
|
||||
hist_kwargs['histtype'] = 'stepfilled'
|
||||
|
||||
fig = figlib.phase_comparison_figure(
|
||||
measured_phases,
|
||||
true_phases,
|
||||
plot_residuals=plot_residuals,
|
||||
f_beacon=f_beacon,
|
||||
figsize=figsize,
|
||||
hist_kwargs=hist_kwargs,
|
||||
fit_gaussian=plot_residuals,
|
||||
)
|
||||
|
||||
axs = fig.get_axes()
|
||||
|
||||
if plot_residuals:
|
||||
fig.suptitle("Difference between Measured and Actual phase difference\n for Baselines (i,j" + (')' if not ref_ant_id else '='+str([ int(a.name) for a in ref_ants])+')'))
|
||||
axs[-1].set_xlabel("Baseline Phase Residual $\\Delta\\varphi_{ij_{meas}} - \\Delta\\varphi_{ij_{true}}$ [rad]")
|
||||
else:
|
||||
fig.suptitle("Comparison Measured and Actual phase difference\n for Baselines (i,j" + (')' if not ref_ant_id else '='+str([ int(a.name) for a in ref_ants])+')'))
|
||||
axs[-1].set_xlabel("Baseline Phase $\\Delta\\varphi_{ij}$ [rad]")
|
||||
|
||||
#
|
||||
i=0
|
||||
secax = axs[i].child_axes[0]
|
||||
secax.set_xlabel('Time $\\Delta\\varphi/(2\\pi f_{beac})$ [ns]')
|
||||
|
||||
#
|
||||
i=1
|
||||
axs[i].set_ylabel("Baseline no.")
|
||||
|
||||
if fig_dir:
|
||||
extra_name = "measured"
|
||||
if plot_residuals:
|
||||
extra_name = "residuals"
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".{extra_name}.F{freq_name}.pdf"))
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,293 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
import h5py
|
||||
from itertools import combinations, zip_longest
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.colors import Normalize
|
||||
import matplotlib as mpl
|
||||
import numpy as np
|
||||
import json
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import figlib
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
args = parser.parse_args()
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
show_plots = args.show_plots
|
||||
ref_ant_id = None # leave None for all baselines
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
time_diffs_fname = 'time_diffs.hdf5' if False else antennas_fname
|
||||
fig_dir = args.fig_dir # set None to disable saving
|
||||
|
||||
basenames, time_diffs, f_beacons, clock_phase_diffs, k_periods = beacon.read_baseline_time_diffs_hdf5(time_diffs_fname)
|
||||
|
||||
f_beacon, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
|
||||
# TODO: allow multiple frequencies
|
||||
if (f_beacon != f_beacons).any():
|
||||
raise NotImplementedError
|
||||
|
||||
N_base = len(basenames)
|
||||
N_ant = len(antennas)
|
||||
|
||||
# reshape time_diffs into N_ant x N_ant matrix
|
||||
clock_phase_matrix = np.full( (N_ant, N_ant), np.nan, dtype=float)
|
||||
|
||||
## set i=i terms to 0
|
||||
for i in range(N_ant):
|
||||
clock_phase_matrix[i,i] = 0
|
||||
|
||||
## fill matrix
|
||||
name2idx = lambda name: int(name)-1
|
||||
for i, b in enumerate(basenames):
|
||||
idx = (name2idx(b[0]), name2idx(b[1]))
|
||||
|
||||
clock_phase_matrix[(idx[0], idx[1])] = lib.phase_mod(clock_phase_diffs[i])
|
||||
clock_phase_matrix[(idx[1], idx[0])] = lib.phase_mod(-1*clock_phase_diffs[i])
|
||||
|
||||
mat_kwargs = dict(
|
||||
norm = Normalize(vmin=-np.pi, vmax=+np.pi),
|
||||
cmap = mpl.cm.get_cmap('Spectral_r')
|
||||
)
|
||||
|
||||
# Show Matrix as figure
|
||||
if True:
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title("Measured clock phase differences Baseline i,j")
|
||||
ax.set_ylabel("Antenna no. i")
|
||||
ax.set_xlabel("Antenna no. j")
|
||||
|
||||
im = ax.imshow(clock_phase_matrix, interpolation='none', **mat_kwargs)
|
||||
fig.colorbar(im, ax=ax)
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".matrix.original.pdf"))
|
||||
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
# Modify the matrix to let each column represent multiple
|
||||
# measurements of the same baseline (j,0) phase difference
|
||||
if True:
|
||||
# for each row j subtract the 0,j element from the whole row
|
||||
# and apply phase_mod
|
||||
first_row = -1*(clock_phase_matrix[0,:] * np.ones_like(clock_phase_matrix)).T
|
||||
|
||||
# Show subtraction Matrix as figure
|
||||
if True:
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title("Clock Phase Subtraction matrix i,j")
|
||||
ax.set_ylabel("Antenna no. i")
|
||||
ax.set_xlabel("Antenna no. j")
|
||||
|
||||
im = ax.imshow(first_row, interpolation='none', **mat_kwargs)
|
||||
fig.colorbar(im, ax=ax)
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".matrix.first_row.pdf"))
|
||||
|
||||
plt.close(fig)
|
||||
|
||||
clock_phase_matrix = clock_phase_matrix - first_row
|
||||
clock_phase_matrix = lib.phase_mod(clock_phase_matrix)
|
||||
|
||||
# Except for the first row, these are all separate measurements
|
||||
# Condense into phase offset per antenna
|
||||
if True: # do not use the first row
|
||||
my_mask = np.arange(1, len(clock_phase_matrix), dtype=int)
|
||||
else:
|
||||
my_mask = np.arange(0, len(clock_phase_matrix), dtype=int)
|
||||
|
||||
mean_clock_phase = np.nanmean(clock_phase_matrix[my_mask], axis=0)
|
||||
std_clock_phase = np.nanstd( clock_phase_matrix[my_mask], axis=0)
|
||||
|
||||
# Remove the mean from the matrix
|
||||
if False:
|
||||
clock_phase_matrix = clock_phase_matrix - np.mean(mean_clock_phase)
|
||||
mean_clock_phase = np.nanmean(clock_phase_matrix[my_mask], axis=0)
|
||||
std_clock_phase = np.nanstd( clock_phase_matrix[my_mask], axis=0)
|
||||
|
||||
# Show resulting matrix as figure
|
||||
if True:
|
||||
fig, axs = plt.subplots(2,1, sharex=True, figsize=figsize)
|
||||
axs[0].set_title("Modified clock phase differences Baseline 0,j")
|
||||
axs[0].set_ylabel("Antenna no. 0")
|
||||
axs[-1].set_xlabel("Antenna no. j")
|
||||
|
||||
im = axs[0].imshow(clock_phase_matrix, interpolation='none', **mat_kwargs)
|
||||
fig.colorbar(im, ax=axs)
|
||||
axs[0].set_aspect('auto')
|
||||
|
||||
colours = [mat_kwargs['cmap'](mat_kwargs['norm'](x)) for x in mean_clock_phase]
|
||||
axs[1].set_ylabel("Mean Baseline Phase (0, j)[rad]")
|
||||
axs[1].errorbar(np.arange(N_ant), mean_clock_phase, yerr=std_clock_phase, ls='none')
|
||||
axs[1].scatter(np.arange(N_ant), mean_clock_phase, c=colours,s=4)
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".matrix.modified.pdf"))
|
||||
|
||||
plt.close(fig)
|
||||
|
||||
# write into antenna hdf5
|
||||
with h5py.File(antennas_fname, 'a') as fp:
|
||||
group = fp['antennas']
|
||||
|
||||
freq_name = None
|
||||
for i, ant in enumerate(antennas):
|
||||
h5ant = group[ant.name]
|
||||
|
||||
h5beacon_info = h5ant['beacon_info']
|
||||
|
||||
# find out freq_name
|
||||
if freq_name is None:
|
||||
freq_name = [ k for k in h5beacon_info.keys() if np.isclose(h5beacon_info[k].attrs['freq'], f_beacon)][0]
|
||||
|
||||
h5attrs = h5beacon_info[freq_name].attrs
|
||||
|
||||
idx = name2idx(ant.name)
|
||||
h5attrs['clock_phase_mean'] = mean_clock_phase[idx]
|
||||
h5attrs['clock_phase_std'] = std_clock_phase[idx]
|
||||
|
||||
|
||||
##############################
|
||||
# Compare actual time shifts #
|
||||
##############################
|
||||
actual_antenna_time_shifts = { a.name: a.attrs['clock_offset'] for a in sorted(antennas, key=lambda a: int(a.name)) }
|
||||
|
||||
if True:
|
||||
actual_antenna_phase_shifts = [ -1*lib.phase_mod(2*np.pi*f_beacon*v) for k,v in actual_antenna_time_shifts.items() ]
|
||||
antenna_names = [int(k)-1 for k,v in actual_antenna_time_shifts.items() ]
|
||||
|
||||
# Make sure to shift all antennas by a global phase
|
||||
global_phase_shift = actual_antenna_phase_shifts[0] - mean_clock_phase[0]
|
||||
actual_antenna_phase_shifts = lib.phase_mod(actual_antenna_phase_shifts - global_phase_shift )
|
||||
|
||||
fit_info = {}
|
||||
for i in range(2):
|
||||
plot_residuals = i == 1
|
||||
true_phases = actual_antenna_phase_shifts
|
||||
measured_phases = mean_clock_phase
|
||||
|
||||
hist_kwargs = {}
|
||||
if plot_residuals:
|
||||
measured_phases = lib.phase_mod(measured_phases - actual_antenna_phase_shifts)
|
||||
|
||||
fig, _fit_info = figlib.phase_comparison_figure(
|
||||
measured_phases,
|
||||
true_phases,
|
||||
plot_residuals=plot_residuals,
|
||||
f_beacon=f_beacon,
|
||||
figsize=figsize,
|
||||
hist_kwargs=hist_kwargs,
|
||||
fit_gaussian=plot_residuals,
|
||||
return_fit_info = True,
|
||||
)
|
||||
|
||||
axs = fig.get_axes()
|
||||
|
||||
if plot_residuals:
|
||||
fig.suptitle("Difference between Measured and Actual phases (minus global phase)\n for Antenna $i$")
|
||||
axs[-1].set_xlabel("Antenna Mean Phase Residual $\\Delta_\\varphi$")
|
||||
else:
|
||||
fig.suptitle("Comparison Measured and Actual phases (minus global phase)\n for Antenna $i$")
|
||||
axs[-1].set_xlabel("Antenna Mean Phase $\\varphi$")
|
||||
|
||||
i=1
|
||||
axs[i].set_ylabel("Antenna no.")
|
||||
#axs[i].errorbar(mean_clock_phase, np.arange(N_ant), yerr=std_clock_phase, marker='4', alpha=0.7, ls='none', color=colors[0], label='Measured')
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
if fig_dir:
|
||||
extra_name = "measured"
|
||||
if plot_residuals:
|
||||
extra_name = "residuals"
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".phase.{extra_name}.pdf"))
|
||||
|
||||
# Save fit_info to data file
|
||||
if fname_dir and plot_residuals:
|
||||
with open(path.join(fname_dir, 'phase_time_residuals.json'), 'w') as fp:
|
||||
json.dump(
|
||||
{
|
||||
'mean': np.mean(measured_phases),
|
||||
'std': np.std(measured_phases),
|
||||
'values': measured_phases.tolist(),
|
||||
},
|
||||
fp)
|
||||
|
||||
|
||||
|
||||
##########################
|
||||
##########################
|
||||
##########################
|
||||
|
||||
actual_baseline_time_shifts = []
|
||||
for i,b in enumerate(basenames):
|
||||
actual_baseline_time_shift = actual_antenna_time_shifts[b[0]] - actual_antenna_time_shifts[b[1]]
|
||||
|
||||
actual_baseline_time_shifts.append(actual_baseline_time_shift)
|
||||
|
||||
# unpack mean_clock_phase back into a list of time diffs
|
||||
measured_baseline_time_diffs = []
|
||||
for i,b in enumerate(basenames):
|
||||
phase0, phase1 = mean_clock_phase[name2idx(b[0])], mean_clock_phase[name2idx(b[1])]
|
||||
measured_baseline_time_diffs.append(lib.phase_mod(phase1 - phase0)/(2*np.pi*f_beacon))
|
||||
|
||||
# Make a plot
|
||||
if True:
|
||||
for i in range(2):
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title("Baseline Time difference reconstruction" + ( '' if i == 0 else ' (wrapped time)'))
|
||||
ax.set_xlabel("Baseline no.")
|
||||
ax.set_ylabel("Time $\\Delta t$ [ns]")
|
||||
if True:
|
||||
forward = lambda x: x/(2*np.pi*f_beacon)
|
||||
inverse = lambda x: 2*np.pi*x*f_beacon
|
||||
secax = ax.secondary_yaxis('right', functions=(inverse, forward))
|
||||
secax.set_ylabel('Phase $\\Delta \\varphi$ [rad]')
|
||||
|
||||
if True: # indicate single beacon period span
|
||||
ax.plot((-1, -1), (-1/(2*f_beacon), 1/(2*f_beacon)), marker='3', ms=10, label='1/f_beacon')
|
||||
if i == 0:
|
||||
ax.plot(np.arange(N_base), actual_baseline_time_shifts, ls='none', marker='h', alpha=0.8, label='actual time shifts')
|
||||
else:
|
||||
ax.plot(np.arange(N_base), (actual_baseline_time_shifts+1/(2*f_beacon))%(1/f_beacon) - 1/(2*f_beacon), ls='none', marker='h', label='actual time shifts', alpha=0.8)
|
||||
ax.plot(np.arange(N_base), measured_baseline_time_diffs, ls='none', alpha=0.8, marker='x', label='calculated')
|
||||
|
||||
ax.legend()
|
||||
if fig_dir:
|
||||
extra_name = ''
|
||||
if i == 1:
|
||||
extra_name = '.wrapped'
|
||||
|
||||
old_lims = (ax.get_xlim(), ax.get_ylim())
|
||||
for j in range(2):
|
||||
if j == 1:
|
||||
ax.set_xlim(-5, 50)
|
||||
extra_name += '.n50'
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".time_comparison{extra_name}.pdf"))
|
||||
|
||||
ax.set_xlim(*old_lims[0])
|
||||
ax.set_ylim(*old_lims[1])
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,543 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
"""
|
||||
Find the best integer multiple to shift
|
||||
antennas to be able to resolve
|
||||
"""
|
||||
|
||||
import h5py
|
||||
from itertools import combinations, zip_longest, product
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from os import path
|
||||
import os
|
||||
from scipy.interpolate import interp1d
|
||||
|
||||
from earsim import REvent
|
||||
from atmocal import AtmoCal
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import rit
|
||||
|
||||
def find_best_sample_shifts_summing_at_location(test_loc, antennas, allowed_sample_shifts, dt=None, sample_shift_first_trace=0, plot_iteration_with_shifted_trace=None, fig_dir=None, fig_distinguish=None):
|
||||
"""
|
||||
Find the best sample_shift for each antenna by summing the antenna traces
|
||||
and seeing how to get the best alignment.
|
||||
"""
|
||||
a_ = []
|
||||
t_ = []
|
||||
t_min = 1e9
|
||||
t_max = -1e9
|
||||
a_maxima = []
|
||||
N_ant = len(antennas)
|
||||
|
||||
if dt is None:
|
||||
dt = antennas[0].t_AxB[1] - antennas[0].t_AxB[0]
|
||||
|
||||
if not hasattr(plot_iteration_with_shifted_trace, '__len__'):
|
||||
if plot_iteration_with_shifted_trace:
|
||||
plot_iteration_with_shifted_trace = [ plot_iteration_with_shifted_trace ]
|
||||
else:
|
||||
plot_iteration_with_shifted_trace = []
|
||||
|
||||
# propagate to test location
|
||||
for i, ant in enumerate(antennas):
|
||||
aloc = [ant.x, ant.y, ant.z]
|
||||
delta, dist = atm.light_travel_time(test_loc, aloc)
|
||||
delta = delta*1e9
|
||||
|
||||
t__ = np.subtract(ant.t_AxB, delta)
|
||||
t_.append(t__)
|
||||
a_.append(ant.E_AxB)
|
||||
a_maxima.append(max(ant.E_AxB))
|
||||
|
||||
if t__[0] < t_min:
|
||||
t_min = t__[0]
|
||||
if t__[-1] > t_max:
|
||||
t_max = t__[-1]
|
||||
|
||||
# sort traces with descending maxima
|
||||
sort_idx = np.argsort(a_maxima)[::-1]
|
||||
t_ = [ t_[i] for i in sort_idx ]
|
||||
a_ = [ a_[i] for i in sort_idx ]
|
||||
|
||||
# Interpolate and find best sample shift
|
||||
max_neg_shift = 0 #np.min(allowed_sample_shifts) * dt
|
||||
max_pos_shift = 0 #np.max(allowed_sample_shifts) * dt
|
||||
|
||||
t_sum = np.arange(t_min+max_neg_shift, t_max+max_pos_shift, dt)
|
||||
a_sum = np.zeros(len(t_sum))
|
||||
|
||||
best_sample_shifts = np.zeros( (len(antennas)) ,dtype=int)
|
||||
for i, (t_r, E_) in enumerate(zip(t_, a_)):
|
||||
f = interp1d(t_r, E_, assume_sorted=True, bounds_error=False, fill_value=0)
|
||||
a_int = f(t_sum)
|
||||
|
||||
if i == 0:
|
||||
a_sum += a_int
|
||||
best_sample_shifts[i] = sample_shift_first_trace
|
||||
continue
|
||||
|
||||
# init figure
|
||||
if i in plot_iteration_with_shifted_trace:
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title("Traces at ({:.1f},{:.1f},{:.1f}) i={i}/{tot}".format(*test_loc, i=i, tot=N_ant))
|
||||
ax.set_xlabel("Time [ns]")
|
||||
ax.set_ylabel("Amplitude")
|
||||
ax.plot(t_sum, a_sum)
|
||||
|
||||
shift_maxima = np.zeros( len(allowed_sample_shifts) )
|
||||
for j, shift in enumerate(allowed_sample_shifts):
|
||||
augmented_a = np.roll(a_int, shift)
|
||||
|
||||
shift_maxima[j] = np.max(augmented_a + a_sum)
|
||||
|
||||
if i in plot_iteration_with_shifted_trace:
|
||||
ax.plot(t_sum, augmented_a, alpha=0.7, ls='dashed', label=f'{shift}')
|
||||
|
||||
# transform maximum into best_sample_shift
|
||||
best_idx = np.argmax(shift_maxima)
|
||||
|
||||
best_sample_shifts[i] = allowed_sample_shifts[best_idx]
|
||||
best_augmented_a = np.roll(a_int, best_sample_shifts[i])
|
||||
a_sum += best_augmented_a
|
||||
|
||||
# cleanup figure
|
||||
if i in plot_iteration_with_shifted_trace:
|
||||
if True: # plot best k again
|
||||
ax.plot(t_sum, augmented_a, alpha=0.8, label=f'best k={best_sample_shifts[i]}', lw=2)
|
||||
|
||||
ax.legend( ncol=5 )
|
||||
if fig_dir:
|
||||
fig.tight_layout()
|
||||
fname = path.join(fig_dir, path.basename(__file__) + f'.{fig_distinguish}i{i}' + '.loc{:.1f}-{:.1f}-{:.1f}'.format(*test_loc))
|
||||
if True:
|
||||
old_xlim = ax.get_xlim()
|
||||
|
||||
if True: # zoomed on part without peak of this trace
|
||||
wx = 100
|
||||
x = max(t_r) - wx
|
||||
ax.set_xlim(x-wx, x+wx)
|
||||
fig.savefig(fname + ".zoomed.beacon.pdf")
|
||||
|
||||
if True: # zoomed on peak of this trace
|
||||
x = t_r[np.argmax(E_)]
|
||||
wx = 50 + (max(best_sample_shifts) - min(best_sample_shifts))*dt
|
||||
ax.set_xlim(x-wx, x+wx)
|
||||
fig.savefig(fname + ".zoomed.peak.pdf")
|
||||
|
||||
ax.set_xlim(*old_xlim)
|
||||
|
||||
fig.savefig(fname + ".pdf")
|
||||
plt.close(fig)
|
||||
|
||||
# sort by antenna (undo sorting by maximum)
|
||||
undo_sort_idx = np.argsort(sort_idx)
|
||||
|
||||
best_sample_shifts = best_sample_shifts[undo_sort_idx]
|
||||
|
||||
# Return ks
|
||||
return best_sample_shifts, np.max(a_sum)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
atm = AtmoCal()
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser(default_fig_dir="./figures/periods_from_shower_figures/")
|
||||
parser.add_argument('--quick_run', action='store_true', help='Use a very coarse grid (6x6)')
|
||||
|
||||
parser.add_argument('--max-k', type=float, default=2, help='Maximum abs(k) allowed to be shifted. (Default: %(default)d)')
|
||||
parser.add_argument('-N', '--N_runs', type=int, default=5, help='Maximum amount of iterations to grid search. (Default: %(default)d)')
|
||||
|
||||
parser.add_argument('-l', '--passband-low', type=float, default=30e-3, help='Lower frequency [GHz] of the passband filter. (set -1 for np.inf) (Default: %(default)g)')
|
||||
parser.add_argument('-u', '--passband-high', type=float, default=80e-3, help='Upper frequency [GHz] of the passband filter. (set -1 for np.inf) (Default: %(default)g)')
|
||||
|
||||
parser.add_argument('--input-fname', type=str, default=None, help='Path to mysim.sry, either directory or path. If empty it takes DATA_DIR and appends mysim.sry. (Default: %(default)s)')
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.input_fname:
|
||||
args.input_fname = args.data_dir
|
||||
|
||||
if path.isdir(args.input_fname):
|
||||
args.input_fname = path.join(args.input_fname, "mysim.sry")
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
fig_dir = args.fig_dir
|
||||
fig_subdir = path.join(fig_dir, 'shifts/')
|
||||
show_plots = args.show_plots
|
||||
|
||||
max_k = int(args.max_k)
|
||||
allowed_ks = np.arange(-max_k, max_k+1, dtype=int)
|
||||
Xref = 400
|
||||
|
||||
N_runs = args.N_runs
|
||||
remove_beacon_from_trace = True
|
||||
apply_signal_window_from_max = True
|
||||
|
||||
low_bp = args.passband_low if args.passband_low >= 0 else np.inf # GHz
|
||||
high_bp = args.passband_high if args.passband_high >= 0 else np.inf # GHz
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
time_diffs_fname = 'time_diffs.hdf5' if not True else antennas_fname
|
||||
tx_fname = path.join(fname_dir, beacon.tx_fname)
|
||||
|
||||
## This is a file indicating whether the k-finding algorithm was
|
||||
## stopped early. This happens when the ks do not change between
|
||||
## two consecutive iterations.
|
||||
run_break_fname = path.join(fname_dir, 'ca_breaked_run')
|
||||
|
||||
# create fig_dir
|
||||
if fig_dir:
|
||||
os.makedirs(fig_dir, exist_ok=True)
|
||||
if fig_subdir:
|
||||
os.makedirs(fig_subdir, exist_ok=True)
|
||||
|
||||
# Read in antennas from file
|
||||
_, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
_, __, txdata = beacon.read_tx_file(tx_fname)
|
||||
# Read original REvent
|
||||
ev = REvent(args.input_fname)
|
||||
# .. patch in our antennas
|
||||
ev.antennas = antennas
|
||||
|
||||
# For now only implement using one freq_name
|
||||
freq_names = antennas[0].beacon_info.keys()
|
||||
if len(freq_names) > 1:
|
||||
raise NotImplementedError
|
||||
|
||||
freq_name = next(iter(freq_names))
|
||||
f_beacon = ev.antennas[0].beacon_info[freq_name]['freq']
|
||||
|
||||
##
|
||||
## Manipulate time and traces of each antenna
|
||||
##
|
||||
### Remove time due to true phase
|
||||
### and optionally remove the beacon
|
||||
|
||||
### Note: there is no use in changing *_AxB variables here (except for plotting),
|
||||
### they're recomputed by the upcoming rit.set_pol_and_bp call.
|
||||
measured_repair_offsets = beacon.read_antenna_clock_repair_offsets(ev.antennas, mode='phases', freq_name=freq_name)
|
||||
for i, ant in enumerate(ev.antennas):
|
||||
ev.antennas[i].orig_t = ev.antennas[i].t
|
||||
ev.antennas[i].t += measured_repair_offsets[i]
|
||||
# t_AxB will be set by the rit.set_pol_and_bp function
|
||||
ev.antennas[i].t_AxB += measured_repair_offsets[i]
|
||||
|
||||
if apply_signal_window_from_max:
|
||||
N_pre, N_post = 250, 250 # TODO: make this configurable
|
||||
|
||||
# Get max idx from all the traces
|
||||
# and select the strongest
|
||||
max_idx = []
|
||||
maxs = []
|
||||
|
||||
for trace in [ant.Ex, ant.Ey, ant.Ez]:
|
||||
idx = np.argmax(np.abs(trace))
|
||||
max_idx.append(idx)
|
||||
maxs.append( np.abs(trace[idx]) )
|
||||
|
||||
idx = np.argmax(maxs)
|
||||
max_idx = max_idx[idx]
|
||||
|
||||
# Create window around max_idx
|
||||
low_idx = max(0, max_idx-N_pre)
|
||||
high_idx = min(len(ant.t), max_idx+N_post)
|
||||
|
||||
ev.antennas[i].orig_t = ant.orig_t[low_idx:high_idx]
|
||||
ev.antennas[i].t = ant.t[low_idx:high_idx]
|
||||
|
||||
ev.antennas[i].Ex = ant.Ex[low_idx:high_idx]
|
||||
ev.antennas[i].Ey = ant.Ey[low_idx:high_idx]
|
||||
ev.antennas[i].Ez = ant.Ez[low_idx:high_idx]
|
||||
|
||||
ev.antennas[i].t_AxB = ant.t_AxB[low_idx:high_idx]
|
||||
ev.antennas[i].E_AxB = ant.E_AxB[low_idx:high_idx]
|
||||
|
||||
# .. and remove the beacon from the traces
|
||||
# Note: ant.E_AxB is recalculated by rit.set_pol_and_bp
|
||||
if remove_beacon_from_trace:
|
||||
clock_phase = measured_repair_offsets[i]*2*np.pi*f_beacon
|
||||
|
||||
beacon_phase = ant.beacon_info[freq_name]['beacon_phase']
|
||||
f = ant.beacon_info[freq_name]['freq']
|
||||
ampl = ant.beacon_info[freq_name]['amplitude']
|
||||
calc_beacon = lib.sine_beacon(f, ev.antennas[i].t, amplitude=ampl, phase=beacon_phase-clock_phase)
|
||||
tx_amps = txdata['amplitudes']
|
||||
tx_amps_sum = np.sum(tx_amps)
|
||||
|
||||
# Split up contribution to the various polarisations
|
||||
for j, amp in enumerate(tx_amps):
|
||||
if j == 0:
|
||||
ev.antennas[i].Ex -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
elif j == 1:
|
||||
ev.antennas[i].Ey -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
elif j == 2:
|
||||
ev.antennas[i].Ez -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
|
||||
# Subtract the beacon from E_AxB
|
||||
ev.antennas[i].E_AxB -= calc_beacon
|
||||
|
||||
# Make a figure of the manipulated traces
|
||||
if i == 72:
|
||||
orig_beacon_amplifier = ampl/max(ant.beacon)
|
||||
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title(f"Signal and Beacon traces Antenna {ant.name}")
|
||||
ax.set_xlabel("Time [ns]")
|
||||
ax.set_ylabel("Amplitude [$\\mu V/m$]")
|
||||
|
||||
ax.plot(ant.t_AxB, ant.E_AxB + calc_beacon, alpha=0.6, ls='dashed', label='Signal') # calc_beacon was already removed
|
||||
ax.plot(ant.t_AxB, calc_beacon, alpha=0.6, ls='dashed', label='Calc Beacon')
|
||||
ax.plot(ant.t_AxB, ant.E_AxB, alpha=0.6, label="Signal - Calc Beacon")
|
||||
|
||||
ax.legend()
|
||||
|
||||
# save
|
||||
if fig_dir:
|
||||
fig.tight_layout()
|
||||
|
||||
if True: # zoom
|
||||
old_xlim = ax.get_xlim()
|
||||
|
||||
if True: # zoomed on part without peak of this trace
|
||||
wx, x = 200, min(ant.t_AxB)
|
||||
ax.set_xlim(x-5, x+wx)
|
||||
|
||||
fig.savefig(path.join(fig_dir, __file__+f'.traces.A{ant.name}.zoomed.beacon.pdf'))
|
||||
|
||||
if True: # zoomed on peak of this trace
|
||||
idx = np.argmax(ev.antennas[i].E_AxB)
|
||||
x = ev.antennas[i].t_AxB[idx]
|
||||
wx = 300
|
||||
ax.set_xlim(x-wx//2, x+wx//2)
|
||||
fig.savefig(path.join(fig_dir, __file__+f".traces.A{ant.name}.zoomed.peak.pdf"))
|
||||
|
||||
ax.set_xlim(*old_xlim)
|
||||
|
||||
fig.savefig(path.join(fig_dir, __file__+f'.traces.A{ant.name}.pdf'))
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
||||
|
||||
# Prepare polarisation and passbands
|
||||
rit.set_pol_and_bp(ev, low=low_bp, high=high_bp)
|
||||
|
||||
# determine allowable ks per location
|
||||
dt = ev.antennas[0].t_AxB[1] - ev.antennas[0].t_AxB[0]
|
||||
allowed_sample_shifts = np.rint(allowed_ks/f_beacon /dt).astype(int)
|
||||
print("Checking:", allowed_ks, ": shifts :", allowed_sample_shifts)
|
||||
|
||||
##
|
||||
## Determine grid positions
|
||||
##
|
||||
|
||||
dXref = atm.distance_to_slant_depth(np.deg2rad(ev.zenith),Xref,0)
|
||||
scale2d = dXref*np.tan(np.deg2rad(2.))
|
||||
scale4d = dXref*np.tan(np.deg2rad(4.))
|
||||
|
||||
if args.quick_run: #quicky
|
||||
x_coarse = np.linspace(-scale2d, scale2d, 6)
|
||||
y_coarse = np.linspace(-scale2d, scale2d, 6)
|
||||
|
||||
x_fine = x_coarse/4
|
||||
y_fine = y_coarse/4
|
||||
else: # long
|
||||
x_coarse = np.linspace(-scale4d, scale4d, 40)
|
||||
y_coarse = np.linspace(-scale4d, scale4d, 40)
|
||||
|
||||
x_fine = np.linspace(-scale2d, scale2d, 40)
|
||||
y_fine = np.linspace(-scale2d, scale2d, 40)
|
||||
|
||||
## Remove run_break_fname if it exists
|
||||
try:
|
||||
os.remove(run_break_fname)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
##
|
||||
## Do calculations on the grid
|
||||
##
|
||||
|
||||
for r in range(N_runs):
|
||||
# Setup Plane grid to test
|
||||
if r == 0:
|
||||
xoff, yoff = 0,0
|
||||
x = x_coarse
|
||||
y = y_coarse
|
||||
else:
|
||||
# zooming in
|
||||
# best_idx is defined at the end of the loop
|
||||
old_ks_per_loc = ks_per_loc[best_idx]
|
||||
xoff, yoff = locs[best_idx]
|
||||
if r == 1:
|
||||
x = x_fine
|
||||
y = y_fine
|
||||
else:
|
||||
x /= 4
|
||||
y /= 4
|
||||
|
||||
print(f"Testing grid run {r} centered on ({xoff}, {yoff})")
|
||||
|
||||
ks_per_loc = np.zeros( (len(x)*len(y), len(ev.antennas)) , dtype=int)
|
||||
maxima_per_loc = np.zeros( (len(x)*len(y)))
|
||||
|
||||
## Check each location on grid
|
||||
xx = []
|
||||
yy = []
|
||||
N_loc = len(maxima_per_loc)
|
||||
|
||||
for i, (x_, y_) in enumerate(product(x,y)):
|
||||
tmp_fig_subdir = None
|
||||
if i % 10 ==0:
|
||||
print(f"Testing location {i} out of {N_loc}")
|
||||
tmp_fig_subdir = fig_subdir
|
||||
|
||||
test_loc = (x_+xoff)* ev.uAxB + (y_+yoff)*ev.uAxAxB + dXref *ev.uA
|
||||
xx.append(x_+xoff)
|
||||
yy.append(y_+yoff)
|
||||
|
||||
# Find best k for each antenna
|
||||
shifts, maximum = find_best_sample_shifts_summing_at_location(test_loc, ev.antennas, allowed_sample_shifts, dt=dt, fig_dir=tmp_fig_subdir, plot_iteration_with_shifted_trace=[ 5, len(ev.antennas)-1], fig_distinguish=f"run{r}.")
|
||||
|
||||
# Translate sample shifts back into period multiple k
|
||||
ks = np.rint(shifts*f_beacon*dt)
|
||||
|
||||
ks_per_loc[i] = ks
|
||||
maxima_per_loc[i] = maximum
|
||||
|
||||
xx = np.array(xx)
|
||||
yy = np.array(yy)
|
||||
locs = list(zip(xx, yy))
|
||||
|
||||
## Save maxima to file
|
||||
np.savetxt(path.join(fig_dir, path.basename(__file__)+f'.maxima.run{r}.txt'), np.column_stack((locs, maxima_per_loc, ks_per_loc)) )
|
||||
|
||||
if True: #plot maximum at test locations
|
||||
fig, axs = plt.subplots(figsize=figsize)
|
||||
axs.set_title(f"Optimizing signal strength by varying $k$ per antenna,\n Grid Run {r}")
|
||||
axs.set_ylabel("vxvxB [km]")
|
||||
axs.set_xlabel(" vxB [km]")
|
||||
axs.set_aspect('equal', 'datalim')
|
||||
sc = axs.scatter(xx/1e3, yy/1e3, c=maxima_per_loc, cmap='Spectral_r', alpha=0.6)
|
||||
fig.colorbar(sc, ax=axs, label='Max Amplitude [$\\mu V/m$]')
|
||||
|
||||
# indicate maximum value
|
||||
idx = np.argmax(maxima_per_loc)
|
||||
axs.plot(xx[idx]/1e3, yy[idx]/1e3, 'bx', ms=30)
|
||||
|
||||
if fig_dir:
|
||||
old_xlims = axs.get_xlim()
|
||||
old_ylims = axs.get_ylim()
|
||||
fig.tight_layout()
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__)+f'.maxima.run{r}.pdf'))
|
||||
if False:
|
||||
axs.plot(tx.x/1e3, tx.y/1e3, marker='X', color='k')
|
||||
fig.tight_layout()
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__)+f'.maxima.run{r}.with_tx.pdf'))
|
||||
axs.set_xlim(*old_xlims)
|
||||
axs.set_ylim(*old_ylims)
|
||||
fig.tight_layout()
|
||||
|
||||
##
|
||||
best_idx = np.argmax(maxima_per_loc)
|
||||
best_k = ks_per_loc[best_idx]
|
||||
|
||||
print("Max at location: ", locs[best_idx])
|
||||
print('Best k:', best_k)
|
||||
|
||||
## Save best ks to file
|
||||
np.savetxt(path.join(fig_dir, path.basename(__file__)+f'.bestk.run{r}.txt'), best_k )
|
||||
|
||||
## Do a small reconstruction of the shower for best ks
|
||||
if True:
|
||||
print("Reconstructing for best k")
|
||||
|
||||
for j in range(2):
|
||||
power_reconstruction = j==1
|
||||
|
||||
if power_reconstruction: # Do power reconstruction
|
||||
# backup antenna times
|
||||
backup_times = [ ant.t_AxB for ant in ev.antennas ]
|
||||
|
||||
# incorporate ks into timing
|
||||
for i, ant in enumerate(ev.antennas):
|
||||
ev.antennas[i].t_AxB = ant.t_AxB - best_k[i] * 1/f_beacon
|
||||
|
||||
xx, yy, p, ___ = rit.shower_plane_slice(ev, X=Xref, Nx=len(x), Ny=len(y), wx=x[-1]-x[0], wy=y[-1]-y[0], xoff=xoff, yoff=yoff, zgr=0)
|
||||
|
||||
# repair antenna times
|
||||
for i, backup_t_AxB in enumerate(backup_times):
|
||||
ev.antennas[i].t_AxB = backup_t_AxB
|
||||
else: # get maximum amplitude at each location
|
||||
maxima = np.empty( len(locs) )
|
||||
for i, loc in enumerate(locs):
|
||||
test_loc = loc[0]* ev.uAxB + loc[1]*ev.uAxAxB + dXref *ev.uA
|
||||
P, t_, a_, a_sum, t_sum = rit.pow_and_time(test_loc, ev, dt=dt)
|
||||
maxima[i] = np.max(a_sum)
|
||||
|
||||
fig, axs = plt.subplots(figsize=figsize)
|
||||
axs.set_title(f"Shower slice for best k, Grid Run {r}")
|
||||
axs.set_ylabel("vxvxB [km]")
|
||||
axs.set_xlabel(" vxB [km]")
|
||||
axs.set_aspect('equal', 'datalim')
|
||||
if power_reconstruction:
|
||||
sc = axs.scatter(xx/1e3, yy/1e3, c=p, cmap='Spectral_r', alpha=0.6)
|
||||
fig.colorbar(sc, ax=axs, label='Power')
|
||||
else:
|
||||
sc = axs.scatter(xx/1e3, yy/1e3, c=maxima, cmap='Spectral_r', alpha=0.6)
|
||||
fig.colorbar(sc, ax=axs, label='Max Amplitude [$\\mu V/m$]')
|
||||
|
||||
|
||||
if fig_dir:
|
||||
if power_reconstruction:
|
||||
fname_extra = "power"
|
||||
else:
|
||||
fname_extra = "max_amp"
|
||||
|
||||
fig.tight_layout()
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__)+f'.reconstruction.run{r}.{fname_extra}.pdf'))
|
||||
|
||||
# Abort if no improvement
|
||||
if ( r!= 0 and (old_ks_per_loc == ks_per_loc[best_idx]).all() ):
|
||||
print(f"No changes from previous grid, breaking at iteration {r} out of {N_runs}")
|
||||
|
||||
try:
|
||||
with open(run_break_fname, 'wt', encoding='utf-8') as fp:
|
||||
fp.write(f"Breaked at grid iteration {r} out of {N_runs}")
|
||||
except:
|
||||
pass
|
||||
|
||||
break
|
||||
|
||||
old_ks_per_loc = ks_per_loc[best_idx]
|
||||
|
||||
# Save best ks to hdf5 antenna file
|
||||
with h5py.File(antennas_fname, 'a') as fp:
|
||||
group = fp.require_group('antennas')
|
||||
|
||||
for i, ant in enumerate(antennas):
|
||||
h5ant = group[ant.name]
|
||||
|
||||
h5beacon_info = h5ant['beacon_info']
|
||||
|
||||
# find out freq_name
|
||||
if freq_name is None:
|
||||
freq_name = [ k for k in h5beacon_info.keys() if np.isclose(h5beacon_info[k].attrs['freq'], f_beacon)][0]
|
||||
|
||||
h5attrs = h5beacon_info[freq_name].attrs
|
||||
|
||||
h5attrs['best_k'] = old_ks_per_loc[i]
|
||||
h5attrs['best_k_time'] = old_ks_per_loc[i]/f_beacon
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,118 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
"""
|
||||
Report best time offset per frequency for each antenna
|
||||
"""
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from os import path
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
from lib import figlib
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
args = parser.parse_args()
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
fig_dir = args.fig_dir # set None to disable saving
|
||||
show_plots = args.show_plots
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
time_diffs_fname = 'time_diffs.hdf5' if not True else antennas_fname
|
||||
|
||||
# create fig_dir
|
||||
if fig_dir:
|
||||
os.makedirs(fig_dir, exist_ok=True)
|
||||
|
||||
# Read in antennas from file
|
||||
_, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
|
||||
# For now only implement using one freq_name
|
||||
freq_names = antennas[0].beacon_info.keys()
|
||||
if len(freq_names) > 1:
|
||||
raise NotImplementedError
|
||||
|
||||
freq_name = next(iter(freq_names))
|
||||
f_beacon = antennas[0].beacon_info[freq_name]['freq']
|
||||
|
||||
|
||||
# TODO: redo matrix sweeping for new timing??
|
||||
measured_antenna_time_shifts = {}
|
||||
for i, ant in enumerate(antennas):
|
||||
clock_phase_time = ant.beacon_info[freq_name]['clock_phase_mean']/(2*np.pi*f_beacon)
|
||||
best_k_time = ant.beacon_info[freq_name]['best_k_time']
|
||||
|
||||
total_clock_time = best_k_time + clock_phase_time
|
||||
measured_antenna_time_shifts[ant.name] = -1*total_clock_time
|
||||
|
||||
###
|
||||
# Compare actual vs measured time shifts
|
||||
###
|
||||
actual_antenna_time_shifts = { a.name: a.attrs['clock_offset'] for a in sorted(antennas, key=lambda a: int(a.name)) }
|
||||
|
||||
N_ant = len(antennas)
|
||||
|
||||
if True:
|
||||
# keep dataset in the same ordering
|
||||
antenna_names = [int(k)-1 for k,v in actual_antenna_time_shifts.items()]
|
||||
actual_time_shifts = np.array([ v for k,v in actual_antenna_time_shifts.items()])
|
||||
measured_time_shifts = np.array([ measured_antenna_time_shifts[k] for k,v in actual_antenna_time_shifts.items() ])
|
||||
|
||||
# remove global shift
|
||||
global_shift = actual_time_shifts[0] - measured_time_shifts[0]
|
||||
actual_time_shifts -= global_shift
|
||||
|
||||
for i in range(2):
|
||||
plot_residuals = i == 1
|
||||
|
||||
|
||||
true_phases = actual_time_shifts
|
||||
measured_phases = measured_time_shifts
|
||||
|
||||
hist_kwargs = {}
|
||||
if plot_residuals:
|
||||
measured_phases = measured_phases - true_phases
|
||||
hist_kwargs['histtype'] = 'stepfilled'
|
||||
|
||||
fig = figlib.phase_comparison_figure(
|
||||
measured_phases,
|
||||
true_phases,
|
||||
plot_residuals=plot_residuals,
|
||||
f_beacon=f_beacon,
|
||||
figsize=figsize,
|
||||
hist_kwargs=hist_kwargs,
|
||||
secondary_axis='phase',
|
||||
fit_gaussian=True,
|
||||
)
|
||||
|
||||
axs = fig.get_axes()
|
||||
|
||||
if plot_residuals:
|
||||
time_shift_residuals = measured_time_shifts - actual_time_shifts
|
||||
fig.suptitle("Difference between Measured and Actual clock offsets")
|
||||
axs[-1].set_xlabel("Antenna Time Offset Residual $\\Delta_t$ [ns]")
|
||||
else:
|
||||
fig.suptitle("Comparison Measured and Actual clock offset")
|
||||
axs[-1].set_xlabel("Antenna Time Offset $t_c = \\left(\\frac{\\Delta\\varphi}{2\\pi} + k\\right) / f_{beac}$ [ns]")
|
||||
|
||||
if fig_dir:
|
||||
extra_name = "comparison"
|
||||
if plot_residuals:
|
||||
extra_name = "residuals"
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".time.{extra_name}.pdf"))
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,208 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
"""
|
||||
Do a reconstruction of airshower after correcting for the
|
||||
clock offsets.
|
||||
"""
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D # required for projection='3d' on old matplotliblib versions
|
||||
import numpy as np
|
||||
from os import path
|
||||
import pickle
|
||||
import joblib
|
||||
|
||||
from earsim import REvent
|
||||
from atmocal import AtmoCal
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import rit
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
atm = AtmoCal()
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
parser.add_argument('--input-fname', type=str, default=None, help='Path to mysim.sry, either directory or path. If empty it takes DATA_DIR and appends mysim.sry. (Default: %(default)s)')
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.input_fname:
|
||||
args.input_fname = args.data_dir
|
||||
|
||||
if path.isdir(args.input_fname):
|
||||
args.input_fname = path.join(args.input_fname, "mysim.sry")
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
fig_dir = args.fig_dir
|
||||
fig_subdir = path.join(fig_dir, 'reconstruction')
|
||||
show_plots = args.show_plots
|
||||
|
||||
apply_signal_window_from_max = True
|
||||
remove_beacon_from_traces = True
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
pickle_fname = path.join(fname_dir, 'res.pkl')
|
||||
tx_fname = path.join(fname_dir, beacon.tx_fname)
|
||||
|
||||
# create fig_dir
|
||||
if fig_dir:
|
||||
os.makedirs(fig_dir, exist_ok=True)
|
||||
if fig_subdir:
|
||||
os.makedirs(fig_subdir, exist_ok=True)
|
||||
|
||||
# Read in antennas from file
|
||||
_, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
_, __, txdata = beacon.read_tx_file(tx_fname)
|
||||
# Read original REvent
|
||||
ev = REvent(args.input_fname)
|
||||
# .. patch in our antennas
|
||||
ev.antennas = antennas
|
||||
|
||||
# For now only implement using one freq_name
|
||||
freq_names = antennas[0].beacon_info.keys()
|
||||
if len(freq_names) > 1:
|
||||
raise NotImplementedError
|
||||
|
||||
freq_name = next(iter(freq_names))
|
||||
f_beacon = ev.antennas[0].beacon_info[freq_name]['freq']
|
||||
|
||||
# Repair clock offsets with the measured offsets
|
||||
measured_repair_offsets = beacon.read_antenna_clock_repair_offsets(ev.antennas, mode='phases', freq_name=freq_name)
|
||||
for i, ant in enumerate(ev.antennas):
|
||||
# t_AxB will be set by the rit.set_pol_and_bp function
|
||||
ev.antennas[i].t += measured_repair_offsets[i]
|
||||
ev.antennas[i].t_AxB += measured_repair_offsets[i]
|
||||
|
||||
if apply_signal_window_from_max:
|
||||
N_pre, N_post = 250, 250 # TODO: make this configurable
|
||||
|
||||
# Get max idx from all the traces
|
||||
# and select the strongest
|
||||
max_idx = []
|
||||
maxs = []
|
||||
|
||||
for trace in [ant.Ex, ant.Ey, ant.Ez]:
|
||||
idx = np.argmax(np.abs(trace))
|
||||
max_idx.append(idx)
|
||||
maxs.append( np.abs(trace[idx]) )
|
||||
|
||||
idx = np.argmax(maxs)
|
||||
max_idx = max_idx[idx]
|
||||
|
||||
# Create window around max_idx
|
||||
low_idx = max(0, max_idx-N_pre)
|
||||
high_idx = min(len(ant.t), max_idx+N_post)
|
||||
|
||||
ev.antennas[i].orig_t = ant.orig_t[low_idx:high_idx]
|
||||
ev.antennas[i].t = ant.t[low_idx:high_idx]
|
||||
|
||||
ev.antennas[i].Ex = ant.Ex[low_idx:high_idx]
|
||||
ev.antennas[i].Ey = ant.Ey[low_idx:high_idx]
|
||||
ev.antennas[i].Ez = ant.Ez[low_idx:high_idx]
|
||||
|
||||
ev.antennas[i].t_AxB = ant.t_AxB[low_idx:high_idx]
|
||||
ev.antennas[i].E_AxB = ant.E_AxB[low_idx:high_idx]
|
||||
|
||||
# .. and remove the beacon from the traces
|
||||
# Note: ant.E_AxB is recalculated by rit.set_pol_and_bp
|
||||
if remove_beacon_from_traces:
|
||||
clock_phase = measured_repair_offsets[i]*2*np.pi*f_beacon
|
||||
|
||||
beacon_phase = ant.beacon_info[freq_name]['beacon_phase']
|
||||
f = ant.beacon_info[freq_name]['freq']
|
||||
ampl_AxB = ant.beacon_info[freq_name]['amplitude']
|
||||
calc_beacon = lib.sine_beacon(f, ev.antennas[i].t, amplitude=ampl_AxB, phase=beacon_phase-clock_phase)
|
||||
|
||||
tx_amps = txdata['amplitudes']
|
||||
tx_amps_sum = np.sum(tx_amps)
|
||||
|
||||
# Split up contribution to the various polarisations
|
||||
for j, amp in enumerate(tx_amps):
|
||||
if j == 0:
|
||||
ev.antennas[i].Ex -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
elif j == 1:
|
||||
ev.antennas[i].Ey -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
elif j == 2:
|
||||
ev.antennas[i].Ez -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
|
||||
# Subtract the beacon from E_AxB
|
||||
ev.antennas[i].E_AxB -= calc_beacon
|
||||
|
||||
##
|
||||
## Make a figure of the manipulated traces
|
||||
##
|
||||
if i == 72:
|
||||
orig_beacon_amplifier = ampl_AxB/max(ant.beacon)
|
||||
|
||||
for k in range(2):
|
||||
if k == 0:
|
||||
time = ant.t_AxB
|
||||
trace = ant.E_AxB
|
||||
tmp_beacon = calc_beacon
|
||||
fname_extra = ""
|
||||
else:
|
||||
time = ant.t
|
||||
trace = ant.Ex
|
||||
tmp_beacon = tx_amps[0]/tx_amps_sum * calc_beacon
|
||||
fname_extra = ".Ex"
|
||||
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_title(f"Signal and Beacon traces Antenna {ant.name}")
|
||||
ax.set_xlabel("Time [ns]")
|
||||
ax.set_ylabel("Amplitude [$\\mu V/m$]")
|
||||
|
||||
ax.plot(time, trace + tmp_beacon, alpha=0.6, ls='dashed', label='Signal') # calc_beacon was already removed
|
||||
ax.plot(time, tmp_beacon, alpha=0.6, ls='dashed', label='Calc Beacon')
|
||||
ax.plot(time, trace, alpha=0.6, label="Signal - Calc Beacon")
|
||||
|
||||
if k == 0:
|
||||
ax.legend()
|
||||
else:
|
||||
ax.legend(title="Ex")
|
||||
|
||||
# save
|
||||
if fig_dir:
|
||||
fig.tight_layout()
|
||||
|
||||
if True: # zoom
|
||||
old_xlim = ax.get_xlim()
|
||||
|
||||
if True: # zoomed on part without peak of this trace
|
||||
wx, x = 100, 100
|
||||
ax.set_xlim(x-wx, x+wx)
|
||||
|
||||
fig.savefig(path.join(fig_dir, __file__+f'.traces.A{ant.name}.zoomed.beacon{fname_extra}.pdf'))
|
||||
|
||||
if True: # zoomed on peak of this trace
|
||||
idx = np.argmax(ev.antennas[i].E_AxB)
|
||||
x = ev.antennas[i].t_AxB[idx]
|
||||
wx = 100
|
||||
ax.set_xlim(x-wx, x+wx)
|
||||
fig.savefig(path.join(fig_dir, __file__+f".traces.A{ant.name}.zoomed.peak{fname_extra}.pdf"))
|
||||
|
||||
ax.set_xlim(*old_xlim)
|
||||
|
||||
fig.savefig(path.join(fig_dir, __file__+f'.traces.A{i}.pdf'))
|
||||
|
||||
|
||||
N_X, Xlow, Xhigh = 23, 100, 1200
|
||||
with joblib.parallel_backend("loky"):
|
||||
res = rit.reconstruction(ev, outfile=fig_subdir+'/fig.pdf', slice_outdir=fig_subdir+'/', Xlow=Xlow, N_X=N_X, Xhigh=Xhigh, disable_pol_and_bp=True)
|
||||
|
||||
## Save a pickle
|
||||
with open(pickle_fname, 'wb') as fp:
|
||||
pickle.dump(res,fp)
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,56 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
"""
|
||||
Do a reconstruction of airshower after correcting for the
|
||||
clock offsets.
|
||||
"""
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D # required for projection='3d' on old matplotliblib versions
|
||||
import numpy as np
|
||||
from os import path
|
||||
import pickle
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import rit
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
args = parser.parse_args()
|
||||
|
||||
fig_dir = args.fig_dir
|
||||
show_plots = args.show_plots
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
pickle_fname = path.join(fname_dir, 'res.pkl')
|
||||
|
||||
# create fig_dir
|
||||
if fig_dir:
|
||||
os.makedirs(fig_dir, exist_ok=True)
|
||||
|
||||
# Load res from pickle
|
||||
with open(pickle_fname, 'rb') as f:
|
||||
res = pickle.load(f)
|
||||
|
||||
##
|
||||
# Longitudinal figures
|
||||
##
|
||||
for i in range(2):
|
||||
mode = ['grammage', 'distance'][i]
|
||||
|
||||
fig = rit.longitudinal_figure(res.dl[0], res.dX[0], res.profile_rit[0], mode=mode)
|
||||
|
||||
if fig_dir:
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f".{mode}.pdf"))
|
|
@ -1,315 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
"""
|
||||
Show how the Power changes when incorporating the
|
||||
various clock offsets by plotting on a grid.
|
||||
"""
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D # required for projection='3d' on old matplotliblib versions
|
||||
import numpy as np
|
||||
from os import path
|
||||
import joblib
|
||||
|
||||
from earsim import REvent
|
||||
from atmocal import AtmoCal
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import rit
|
||||
|
||||
|
||||
def save_overlapping_traces_figure(test_location, ev, N_plot = 30, wx=200, title_extra=None, fname_distinguish='', fig_dir=None, **fig_kwargs):
|
||||
P, t_, a_, a_sum, t_sum = rit.pow_and_time(test_location, ev, dt=1)
|
||||
|
||||
fig, axs = plt.subplots(**fig_kwargs)
|
||||
axs.set_title("Antenna traces" + (("\n" + title_extra) if title_extra is not None else '') )
|
||||
axs.set_xlabel("Time [ns]")
|
||||
axs.set_ylabel("Amplitude [$\\mu V/m$]")
|
||||
if False:
|
||||
text_loc = (0.02, 0.95)
|
||||
axs.text(*text_loc, '[' + ', '.join(['{:.2e}'.format(x) for x in test_location]) + ']', ha='left', transform=axs.transAxes)
|
||||
|
||||
a_max = [ np.amax(ant.E_AxB) for ant in ev.antennas ]
|
||||
power_sort_idx = np.argsort(a_max)
|
||||
|
||||
for i, idx in enumerate(reversed(power_sort_idx)):
|
||||
if i >= N_plot:
|
||||
break
|
||||
|
||||
alpha = max(0.4, 1/N_plot)
|
||||
|
||||
axs.plot(t_[idx], a_[idx], color='r', alpha=alpha, lw=2)
|
||||
|
||||
if fig_dir:
|
||||
if fname_distinguish:
|
||||
fname_distinguish = "." + fname_distinguish
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f'{fname_distinguish}.trace_overlap.{case}.pdf'))
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f'{fname_distinguish}.trace_overlap.{case}.png'), transparent=True)
|
||||
|
||||
# Take center between t_low and t_high
|
||||
if True:
|
||||
orig_xlims = axs.get_xlim()
|
||||
|
||||
if not True: # t_high and t_low from strongest signal
|
||||
t_low = np.min(t_[power_sort_idx[-1]])
|
||||
t_high = np.max(t_[power_sort_idx[-1]])
|
||||
else: # take t_high and t_low from plotted signals
|
||||
a = [np.min(t_[idx]) for idx in power_sort_idx[-N_plot:]]
|
||||
t_low = np.nanmin(a)
|
||||
b = [np.max(t_[idx]) for idx in power_sort_idx[-N_plot:]]
|
||||
t_high = np.nanmax(b)
|
||||
|
||||
if False:
|
||||
axs.plot(a, [0]*N_plot, 'gx', ms=10)
|
||||
axs.plot(b, [0]*N_plot, 'b+', ms=10)
|
||||
|
||||
center_x = (t_high - t_low)/2 + t_low
|
||||
|
||||
low_xlim = max(orig_xlims[0], center_x - wx)
|
||||
high_xlim = min(orig_xlims[1], center_x + wx)
|
||||
|
||||
axs.set_xlim(low_xlim, high_xlim)
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f'{fname_distinguish}.trace_overlap.zoomed.{case}.pdf'))
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f'{fname_distinguish}.trace_overlap.zoomed.{case}.png'), transparent=True)
|
||||
|
||||
return fig
|
||||
|
||||
if __name__ == "__main__":
|
||||
valid_cases = ['no_offset', 'repair_none', 'repair_phases', 'repair_all']
|
||||
|
||||
import sys
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
atm = AtmoCal()
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
parser.add_argument('--input-fname', type=str, default=None, help='Path to mysim.sry, either directory or path. If empty it takes DATA_DIR and appends mysim.sry. (Default: %(default)s)')
|
||||
|
||||
group = parser.add_argument_group('figures')
|
||||
for case in valid_cases:
|
||||
group.add_argument('--'+case.replace('_','-'), dest='figures', action='append_const', const=case)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.input_fname:
|
||||
args.input_fname = args.data_dir
|
||||
|
||||
if path.isdir(args.input_fname):
|
||||
args.input_fname = path.join(args.input_fname, "mysim.sry")
|
||||
|
||||
wanted_cases = args.figures
|
||||
|
||||
if not wanted_cases or 'all' in wanted_cases:
|
||||
wanted_cases = valid_cases
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
fig_dir = args.fig_dir
|
||||
show_plots = args.show_plots
|
||||
|
||||
remove_beacon_from_traces = True
|
||||
apply_signal_window_from_max = True
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
pickle_fname = path.join(fname_dir, 'res.pkl')
|
||||
tx_fname = path.join(fname_dir, beacon.tx_fname)
|
||||
|
||||
# create fig_dir
|
||||
if fig_dir:
|
||||
os.makedirs(fig_dir, exist_ok=True)
|
||||
|
||||
# Read in antennas from file
|
||||
_, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
_, __, txdata = beacon.read_tx_file(tx_fname)
|
||||
# Read original REvent
|
||||
ev = REvent(args.input_fname)
|
||||
bak_ants = ev.antennas
|
||||
# .. patch in our antennas
|
||||
ev.antennas = antennas
|
||||
|
||||
##
|
||||
## Setup grid
|
||||
##
|
||||
X = 400
|
||||
zgr = 0 #not exact
|
||||
dXref = atm.distance_to_slant_depth(np.deg2rad(ev.zenith),750,zgr+ev.core[2])
|
||||
scale2d = dXref*np.tan(np.deg2rad(2.))
|
||||
scale4d = dXref*np.tan(np.deg2rad(4.))
|
||||
scale02d = dXref*np.tan(np.deg2rad(0.2))
|
||||
|
||||
Nx, Ny = 21, 21
|
||||
scales = {
|
||||
'scale2d': scale2d,
|
||||
'scale4d': scale4d,
|
||||
'scale02d': scale02d,
|
||||
}
|
||||
|
||||
N_plot = 30
|
||||
trace_zoom_wx = 100
|
||||
|
||||
plot_titling = {
|
||||
'no_offset': "no clock offset",
|
||||
'repair_none': "unrepaired clock offset",
|
||||
'repair_phases': "phase resolved clock offsets repaired",
|
||||
'repair_all': "final measured clock offsets repaired"
|
||||
}
|
||||
|
||||
# For now only implement using one freq_name
|
||||
freq_names = ev.antennas[0].beacon_info.keys()
|
||||
if len(freq_names) > 1:
|
||||
raise NotImplementedError
|
||||
|
||||
freq_name = next(iter(freq_names))
|
||||
|
||||
# Pre remove the beacon from the traces
|
||||
#
|
||||
# We need to remove it here, so we do not shoot ourselves in
|
||||
# the foot when changing to the various clock offsets.
|
||||
#
|
||||
# Note that the bandpass filter is applied only after E_AxB is
|
||||
# reconstructed so we have to manipulate the original traces.
|
||||
if remove_beacon_from_traces:
|
||||
tx_amps = txdata['amplitudes']
|
||||
tx_amps_sum = np.sum(tx_amps)
|
||||
|
||||
for i, ant in enumerate(ev.antennas):
|
||||
beacon_phase = ant.beacon_info[freq_name]['beacon_phase']
|
||||
f = ant.beacon_info[freq_name]['freq']
|
||||
ampl_AxB = ant.beacon_info[freq_name]['amplitude']
|
||||
calc_beacon = lib.sine_beacon(f, ev.antennas[i].t, amplitude=ampl_AxB, phase=beacon_phase)
|
||||
|
||||
# Split up contribution to the various polarisations
|
||||
for j, amp in enumerate(tx_amps):
|
||||
if j == 0:
|
||||
ev.antennas[i].Ex -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
elif j == 1:
|
||||
ev.antennas[i].Ey -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
elif j == 2:
|
||||
ev.antennas[i].Ez -= amp*(1/tx_amps_sum)*calc_beacon
|
||||
|
||||
# Subtract the beacon from E_AxB
|
||||
ev.antennas[i].E_AxB -= calc_beacon
|
||||
|
||||
# Slice the traces to a small part around the peak
|
||||
if apply_signal_window_from_max:
|
||||
N_pre, N_post = 250, 250 # TODO: make this configurable
|
||||
|
||||
for i, ant in enumerate(ev.antennas):
|
||||
# Get max idx from all the traces
|
||||
# and select the strongest
|
||||
max_idx = []
|
||||
maxs = []
|
||||
|
||||
for trace in [ant.Ex, ant.Ey, ant.Ez]:
|
||||
idx = np.argmax(np.abs(trace))
|
||||
max_idx.append(idx)
|
||||
maxs.append( np.abs(trace[idx]) )
|
||||
|
||||
idx = np.argmax(maxs)
|
||||
max_idx = max_idx[idx]
|
||||
|
||||
|
||||
low_idx = max(0, max_idx-N_pre)
|
||||
high_idx = min(len(ant.t), max_idx+N_post)
|
||||
|
||||
ev.antennas[i].t = ant.t[low_idx:high_idx]
|
||||
ev.antennas[i].t_AxB = ant.t_AxB[low_idx:high_idx]
|
||||
|
||||
ev.antennas[i].Ex = ant.Ex[low_idx:high_idx]
|
||||
ev.antennas[i].Ey = ant.Ey[low_idx:high_idx]
|
||||
ev.antennas[i].Ez = ant.Ez[low_idx:high_idx]
|
||||
ev.antennas[i].E_AxB = ant.E_AxB[low_idx:high_idx]
|
||||
|
||||
## Apply polarisation and bandpass filter
|
||||
rit.set_pol_and_bp(ev)
|
||||
|
||||
# backup antenna times
|
||||
backup_antenna_t = [ ant.t for ant in ev.antennas ]
|
||||
backup_antenna_t_AxB = [ ant.t_AxB for ant in ev.antennas ]
|
||||
|
||||
fig = save_overlapping_traces_figure([0,0,0], ev, N_plot=1, wx=trace_zoom_wx, title_extra = plot_titling[case], fname_distinguish=f'single', fig_dir=fig_dir, figsize=figsize)
|
||||
plt.close(fig)
|
||||
|
||||
with joblib.parallel_backend("loky"):
|
||||
for case in wanted_cases:
|
||||
print(f"Starting {case} figure")
|
||||
# Repair clock offsets with the measured offsets
|
||||
transl_modes = {'no_offset':'orig', 'repair_phases':'phases', 'repair_all':'all'}
|
||||
|
||||
if case in transl_modes:
|
||||
transl_mode = transl_modes[case]
|
||||
measured_offsets = beacon.read_antenna_clock_repair_offsets(antennas, mode=transl_mode, freq_name=freq_name)
|
||||
else:
|
||||
measured_offsets = [0]*len(ev.antennas)
|
||||
|
||||
for i, ant in enumerate(ev.antennas):
|
||||
total_clock_offset = measured_offsets[i]
|
||||
|
||||
ev.antennas[i].t = backup_antenna_t[i] + total_clock_offset
|
||||
ev.antennas[i].t_AxB = backup_antenna_t_AxB[i] + total_clock_offset
|
||||
|
||||
if i == 0:
|
||||
# Specifically compare the times
|
||||
print("backup time, time with measured_offset, true clock offset, measured clock offset")
|
||||
print(bak_ants[i].t[0], ev.antennas[i].t[0], ev.antennas[i].attrs['clock_offset'], measured_offsets[i])
|
||||
|
||||
#
|
||||
# Plot overlapping traces at 0,0,0
|
||||
#
|
||||
fig = save_overlapping_traces_figure([0,0,0], ev, N_plot=N_plot, wx=trace_zoom_wx, title_extra = plot_titling[case], fname_distinguish=f'{case}.0', fig_dir=fig_dir, figsize=figsize)
|
||||
plt.close(fig)
|
||||
|
||||
# Measure power on grid
|
||||
# and plot overlapping traces at position with highest power
|
||||
for scalename, scale in scales.items():
|
||||
wx, wy = scale, scale
|
||||
print(f"Starting grid measurement for figure {case} with {scalename}")
|
||||
xx, yy, p, maxp_loc = rit.shower_plane_slice(ev, X=X, Nx=Nx, Ny=Nx, wx=wx, wy=wy, zgr=zgr)
|
||||
|
||||
fig, axs = rit.slice_figure(ev, X, xx, yy, p, mode='sp', scatter_kwargs=dict(
|
||||
vmax=1e5,
|
||||
vmin=0,
|
||||
s=150,
|
||||
cmap='inferno',
|
||||
# edgecolor='black',
|
||||
))
|
||||
|
||||
suptitle = fig._suptitle.get_text()
|
||||
fig.suptitle("")
|
||||
axs.set_title(suptitle +"\n" +plot_titling[case])
|
||||
#axs.set_aspect('equal', 'datalim')
|
||||
|
||||
if fig_dir:
|
||||
fig.tight_layout()
|
||||
fig.savefig(path.join(fig_dir, path.basename(__file__) + f'.X{X}.{case}.{scalename}.pdf'))
|
||||
plt.close(fig)
|
||||
|
||||
#
|
||||
# Plot overlapping traces at highest power of each scale
|
||||
#
|
||||
fig = save_overlapping_traces_figure(maxp_loc, ev, N_plot=N_plot, wx=trace_zoom_wx, title_extra = plot_titling[case] + ', ' + scalename + ' best', fname_distinguish=scalename+'.best', fig_dir=fig_dir, figsize=figsize)
|
||||
|
||||
#
|
||||
# and plot overlapping traces at two other locations
|
||||
#
|
||||
if True:
|
||||
for dist in [ 0.5, 5, 10, 50, 100]:
|
||||
# only add distance horizontally
|
||||
location = maxp_loc + np.sqrt(dist*1e3)*np.array([1,1,0])
|
||||
|
||||
fig = save_overlapping_traces_figure(location, ev, N_plot=N_plot, wx=wx, title_extra = plot_titling[case] + ', ' + scalename + f', x + {dist}km', fname_distinguish=f'{scalename}.{dist}', fig_dir=fig_dir, figsize=figsize)
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
if args.show_plots:
|
||||
plt.show()
|
|
@ -1,3 +0,0 @@
|
|||
from .lib import *
|
||||
from . import rit
|
||||
from .snr import *
|
|
@ -1 +0,0 @@
|
|||
Subproject commit cd903a30f99e7f640ed068c4393cd38c23c316e2
|
|
@ -1 +0,0 @@
|
|||
Subproject commit a5abe360fa5210be6ab423ecf2b5f783ae45b675
|
|
@ -1,219 +0,0 @@
|
|||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
import scipy.stats as stats
|
||||
from itertools import zip_longest
|
||||
|
||||
def phase_comparison_figure(
|
||||
measured_phases,
|
||||
true_phases,
|
||||
plot_residuals=True,
|
||||
f_beacon=None,
|
||||
hist_kwargs={},
|
||||
sc_kwargs={},
|
||||
text_kwargs={},
|
||||
colors=['blue', 'orange'],
|
||||
legend_on_scatter=True,
|
||||
secondary_axis='time',
|
||||
fit_gaussian=False,
|
||||
mean_snr=None,
|
||||
return_fit_info=False,
|
||||
**fig_kwargs
|
||||
):
|
||||
"""
|
||||
Create a figure comparing measured_phase against true_phase
|
||||
by both plotting the values, and the residuals.
|
||||
"""
|
||||
default_fig_kwargs = dict(sharex=True)
|
||||
default_hist_kwargs = dict(bins='sqrt', density=False, alpha=0.8, histtype='step')
|
||||
default_text_kwargs = dict(fontsize=14, verticalalignment='top')
|
||||
default_sc_kwargs = dict(alpha=0.6, ls='none')
|
||||
|
||||
fig_kwargs = {**default_fig_kwargs, **fig_kwargs}
|
||||
hist_kwargs = {**default_hist_kwargs, **hist_kwargs}
|
||||
text_kwargs = {**default_text_kwargs, **text_kwargs}
|
||||
sc_kwargs = {**default_sc_kwargs, **sc_kwargs}
|
||||
|
||||
do_hist_plot = hist_kwargs is not False
|
||||
do_scatter_plot = sc_kwargs is not False
|
||||
|
||||
fig, axs = plt.subplots(0+do_hist_plot+do_scatter_plot, 1, **fig_kwargs)
|
||||
|
||||
if not hasattr(axs, '__len__'):
|
||||
axs = [axs]
|
||||
|
||||
if f_beacon and secondary_axis in ['phase', 'time']:
|
||||
phase2time = lambda x: x/(2*np.pi*f_beacon)
|
||||
time2phase = lambda x: 2*np.pi*x*f_beacon
|
||||
|
||||
if secondary_axis == 'time':
|
||||
functions = (phase2time, time2phase)
|
||||
label = 'Time $\\varphi/(2\\pi f_{beac})$ [ns]'
|
||||
else:
|
||||
functions = (time2phase, phase2time)
|
||||
label = 'Phase $2\\pi t f_{beac}$ [rad]'
|
||||
|
||||
secax = axs[0].secondary_xaxis('top', functions=functions)
|
||||
|
||||
# Histogram
|
||||
fit_info = {}
|
||||
if do_hist_plot:
|
||||
i=0
|
||||
|
||||
axs[i].set_ylabel("#")
|
||||
|
||||
this_kwargs = dict(
|
||||
ax = axs[i],
|
||||
text_kwargs=text_kwargs,
|
||||
hist_kwargs={**hist_kwargs, **dict(label='Measured', color=colors[0], ls='solid')},
|
||||
mean_snr=mean_snr,
|
||||
)
|
||||
|
||||
if fit_gaussian:
|
||||
this_kwargs['fit_distr'] = 'gaussian'
|
||||
|
||||
_, fit_info = fitted_histogram_figure(
|
||||
measured_phases,
|
||||
**this_kwargs
|
||||
)
|
||||
|
||||
if not plot_residuals: # also plot the true clock phases
|
||||
_bins = fit_info['bins']
|
||||
axs[i].hist(true_phases, color=colors[1], label='Actual', ls='dashed', **{**hist_kwargs, **dict(bins=_bins)})
|
||||
|
||||
# Scatter plot
|
||||
if do_scatter_plot:
|
||||
i=1
|
||||
axs[i].set_ylabel("Antenna no.")
|
||||
axs[i].plot(measured_phases, np.arange(len(measured_phases)), marker='x' if plot_residuals else '3', color=colors[0], label='Measured', **sc_kwargs)
|
||||
|
||||
if not plot_residuals: # also plot the true clock phases
|
||||
axs[i].plot(true_phases, np.arange(len(true_phases)), marker='4', color=colors[1], label='Actual', **sc_kwargs)
|
||||
|
||||
if not plot_residuals and legend_on_scatter:
|
||||
axs[i].legend()
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
if return_fit_info:
|
||||
return fig, fit_info
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
def fitted_histogram_figure(
|
||||
amplitudes,
|
||||
fit_distr = None,
|
||||
calc_chisq = True,
|
||||
text_kwargs={},
|
||||
hist_kwargs={},
|
||||
mean_snr = None,
|
||||
ax = None,
|
||||
**fig_kwargs
|
||||
):
|
||||
"""
|
||||
Create a figure showing $amplitudes$ as a histogram.
|
||||
If fit_distr is a (list of) string, also fit the respective
|
||||
distribution function and show the parameters on the figure.
|
||||
"""
|
||||
default_hist_kwargs = dict(bins='sqrt', density=False, alpha=0.8, histtype='step', label='hist')
|
||||
default_text_kwargs = dict(fontsize=14, verticalalignment='top')
|
||||
|
||||
if isinstance(fit_distr, str):
|
||||
fit_distr = [fit_distr]
|
||||
|
||||
hist_kwargs = {**default_hist_kwargs, **hist_kwargs}
|
||||
text_kwargs = {**default_text_kwargs, **text_kwargs}
|
||||
|
||||
if ax is None:
|
||||
fig, ax = plt.subplots(1,1, **fig_kwargs)
|
||||
else:
|
||||
fig = ax.get_figure()
|
||||
|
||||
text_kwargs['transform'] = ax.transAxes
|
||||
|
||||
counts, bins, _patches = ax.hist(amplitudes, **hist_kwargs)
|
||||
|
||||
fit_info = []
|
||||
if fit_distr:
|
||||
min_x = min(amplitudes)
|
||||
max_x = max(amplitudes)
|
||||
|
||||
dx = bins[1] - bins[0]
|
||||
scale = len(amplitudes) * dx
|
||||
|
||||
xs = np.linspace(min_x, max_x)
|
||||
|
||||
for distr in fit_distr:
|
||||
fit_params2text_params = lambda x: x
|
||||
|
||||
if 'rice' == distr:
|
||||
name = "Rice"
|
||||
param_names = [ "$\\nu$", "$\\sigma$" ]
|
||||
distr_func = stats.rice
|
||||
|
||||
fit_params2text_params = lambda x: (x[0]*x[1], x[1])
|
||||
|
||||
elif 'gaussian' == distr:
|
||||
name = "Norm"
|
||||
param_names = [ "$\\mu$", "$\\sigma$" ]
|
||||
distr_func = stats.norm
|
||||
|
||||
elif 'rayleigh' == distr:
|
||||
name = "Rayleigh"
|
||||
param_names = [ "$\\sigma$" ]
|
||||
distr_func = stats.rayleigh
|
||||
|
||||
fit_params2text_params = lambda x: (x[0]+x[1]/2,)
|
||||
|
||||
else:
|
||||
raise ValueError('Unknown distribution function '+distr)
|
||||
|
||||
label = name +"(" + ','.join(param_names) + ')'
|
||||
|
||||
fit_params = distr_func.fit(amplitudes)
|
||||
fit_ys = distr_func.pdf(xs, *fit_params)
|
||||
|
||||
ax.plot(xs, fit_ys*scale, label=label)
|
||||
|
||||
chisq_strs = []
|
||||
if calc_chisq:
|
||||
ct = np.diff(distr_func.cdf(bins, *fit_params))*np.sum(counts)
|
||||
c2t = stats.chisquare(counts, ct, ddof=len(fit_params))
|
||||
chisq_strs = [
|
||||
f"$\\chi^2$/dof = {c2t[0]: .2g}/{len(fit_params)}"
|
||||
]
|
||||
|
||||
# change parameters if needed
|
||||
text_fit_params = fit_params2text_params(fit_params)
|
||||
|
||||
text_str = "\n".join(
|
||||
[label]
|
||||
+
|
||||
[ f"{param} = {value: .2e}" for param, value in zip_longest(param_names, text_fit_params, fillvalue='?') ]
|
||||
+
|
||||
chisq_strs
|
||||
)
|
||||
|
||||
this_info = {
|
||||
'name': name,
|
||||
'param_names': param_names,
|
||||
'param_values': text_fit_params,
|
||||
'text_str': text_str,
|
||||
}
|
||||
|
||||
if chisq_strs:
|
||||
this_info['chisq'] = c2t[0]
|
||||
this_info['dof'] = len(fit_params)
|
||||
|
||||
fit_info.append(this_info)
|
||||
|
||||
loc = (0.02, 0.95)
|
||||
ax.text(*loc, "\n\n".join([info['text_str'] for info in fit_info]), **{**text_kwargs, **dict(ha='left')})
|
||||
|
||||
if mean_snr:
|
||||
text_str = f"$\\langle SNR \\rangle$ = {mean_snr: .1e}"
|
||||
loc = (0.98, 0.95)
|
||||
ax.text(*loc, text_str, **{**text_kwargs, **dict(ha='right')})
|
||||
|
||||
return fig, dict(fit_info=fit_info, counts=counts, bins=bins)
|
|
@ -1,258 +0,0 @@
|
|||
# vim: fdm=indent ts=4
|
||||
"""
|
||||
Library for this simulation
|
||||
"""
|
||||
import numpy as np
|
||||
from numpy.polynomial import Polynomial
|
||||
|
||||
from earsim import Antenna
|
||||
c_light = 3e8*1e-9 # m/ns
|
||||
|
||||
""" Beacon utils """
|
||||
def sine_beacon(f, t, t0=0, amplitude=1, baseline=0, phase=0, peak_at_t0=0):
|
||||
"""
|
||||
Return a sine appropriate as a beacon
|
||||
"""
|
||||
baseline = baseline*np.ones_like(t)
|
||||
|
||||
if peak_at_t0: # add peak near t0
|
||||
idx = (np.abs(t-t0)).argmin()
|
||||
baseline[ max(0, idx-1):min(len(t), idx+1) ] += peak_at_t0 + amplitude
|
||||
|
||||
return amplitude * np.cos(2*np.pi*f*(t+t0) + phase) + baseline
|
||||
|
||||
def phase_mod(phase, low=np.pi):
|
||||
"""
|
||||
Modulo phase such that it falls within the
|
||||
interval $[-low, 2\pi - low)$.
|
||||
"""
|
||||
return (phase + low) % (2*np.pi) - low
|
||||
|
||||
def distance(x1, x2):
|
||||
"""
|
||||
Calculate the Euclidean distance between two locations x1 and x2
|
||||
"""
|
||||
|
||||
assert type(x1) in [Antenna]
|
||||
x1 = np.array([x1.x, x1.y, x1.z])
|
||||
|
||||
assert type(x2) in [Antenna]
|
||||
x2 = np.array([x2.x, x2.y, x2.z])
|
||||
|
||||
return np.sqrt( np.sum( (x1-x2)**2 ) )
|
||||
|
||||
def geometry_time(dist, x2=None, c_light=c_light):
|
||||
if x2 is not None:
|
||||
dist = distance(dist, x2)
|
||||
|
||||
return dist/c_light
|
||||
|
||||
def beacon_from(tx, rx, f, t=0, t0=0, c_light=c_light, radiate_rsq=True, amplitude=1,**kwargs):
|
||||
dist = distance(tx,rx)
|
||||
# suppress extra time delay from distance
|
||||
if c_light is not None and np.isfinite(c_light):
|
||||
t0 = t0 + dist/c_light
|
||||
|
||||
if radiate_rsq:
|
||||
if np.isclose(dist, 0):
|
||||
dist = 1
|
||||
amplitude *= 1/(dist**2)
|
||||
|
||||
return sine_beacon(f, t, t0=t0, amplitude=amplitude,**kwargs)
|
||||
|
||||
def remove_antenna_geometry_phase(tx, antennas, f_beacon, measured_phases=None, c_light=c_light):
|
||||
"""
|
||||
Remove the geometrical phase from the measured antenna phase.
|
||||
"""
|
||||
if not hasattr(antennas, '__len__'):
|
||||
antennas = [antennas]
|
||||
|
||||
if not hasattr(measured_phases, '__len__'):
|
||||
measured_phases = [measured_phases]
|
||||
|
||||
clock_phases = np.empty( (len(antennas)) )
|
||||
for i, ant in enumerate(antennas):
|
||||
measured_phase = measured_phases[i]
|
||||
|
||||
geom_time = geometry_time(tx, ant, c_light=c_light)
|
||||
geom_phase = geom_time * 2*np.pi*f_beacon
|
||||
|
||||
clock_phases[i] = phase_mod(measured_phase - geom_phase)
|
||||
|
||||
return clock_phases
|
||||
|
||||
|
||||
""" Fourier """
|
||||
def ft_corr_vectors(freqs, time):
|
||||
"""
|
||||
Get the cosine and sine terms for freqs at time.
|
||||
|
||||
Takes the outer product of freqs and time.
|
||||
"""
|
||||
freqtime = np.outer(freqs, time)
|
||||
|
||||
c_k = np.cos(2*np.pi*freqtime)
|
||||
s_k = -1*np.sin(2*np.pi*freqtime)
|
||||
|
||||
return c_k, s_k
|
||||
|
||||
def direct_fourier_transform(freqs, time, samplesets_iterable):
|
||||
"""
|
||||
Determine the fourier transform of each sampleset in samplesets_iterable at freqs.
|
||||
|
||||
The samplesets are expected to have the same time vector.
|
||||
|
||||
Returns either a generator to return the fourier transform for each sampleset
|
||||
if samplesets_iterable is a generator
|
||||
or a numpy array.
|
||||
"""
|
||||
|
||||
c_k, s_k = ft_corr_vectors(freqs, time)
|
||||
|
||||
if not hasattr(samplesets_iterable, '__len__') and hasattr(samplesets_iterable, '__iter__'):
|
||||
# samplesets_iterable is an iterator
|
||||
# return a generator containing (real, imag) amplitudes
|
||||
return ( (np.dot(c_k, samples), np.dot(s_k, samples)) for samples in samplesets_iterable )
|
||||
|
||||
# Numpy array
|
||||
return np.dot(c_k, samplesets_iterable), np.dot(s_k, samplesets_iterable)
|
||||
|
||||
def phase_field_from_tx(x, y, tx, f_beacon, c_light=c_light, t0=0, wrap_phase=True, return_meshgrid=True):
|
||||
"""
|
||||
"""
|
||||
|
||||
assert type(tx) in [Antenna]
|
||||
|
||||
xs, ys = np.meshgrid(x, y, sparse=True)
|
||||
|
||||
x_distances = (tx.x - xs)**2
|
||||
y_distances = (tx.y - ys)**2
|
||||
|
||||
dist = np.sqrt( x_distances + y_distances )
|
||||
|
||||
phase = (dist/c_light + t0) * f_beacon*2*np.pi
|
||||
if wrap_phase:
|
||||
phase = phase_mod(phase)
|
||||
|
||||
if return_meshgrid:
|
||||
return phase, (xs, ys)
|
||||
else:
|
||||
return phase, (np.repeat(xs, len(ys), axis=0), np.repeat(ys, len(xs[0]), axis=1))
|
||||
|
||||
|
||||
def find_beacon_in_traces(
|
||||
traces,
|
||||
t_trace,
|
||||
f_beacon_estimate = 50e6,
|
||||
frequency_fit = False,
|
||||
N_test_freqs = 5e2,
|
||||
f_beacon_estimate_band = 0.01,
|
||||
amp_cut = 0.8
|
||||
):
|
||||
"""
|
||||
f_beacon_band is inclusive
|
||||
|
||||
traces is [trace, trace, trace, .. ]
|
||||
"""
|
||||
|
||||
amplitudes = np.zeros(len(traces))
|
||||
phases = np.zeros(len(traces))
|
||||
frequencies = np.zeros(len(traces))
|
||||
|
||||
if frequency_fit: # fit frequency
|
||||
test_freqs = f_beacon_estimate + f_beacon_estimate_band * np.linspace(-1, 1, int(N_test_freqs)+1)
|
||||
ft_amp_gen = direct_fourier_transform(test_freqs, t_trace, (x for x in traces))
|
||||
|
||||
n_samples = len(t_trace)
|
||||
|
||||
for i, ft_amp in enumerate(ft_amp_gen):
|
||||
real, imag = ft_amp
|
||||
amps = 1/n_samples * ( real**2 + imag**2)**0.5
|
||||
|
||||
# find frequency peak and surrounding bins
|
||||
# that are valid for the parabola fit
|
||||
max_amp_idx = np.argmax(amps)
|
||||
max_amp = amps[max_amp_idx]
|
||||
|
||||
if True:
|
||||
frequencies[i] = test_freqs[max_amp_idx]
|
||||
continue
|
||||
|
||||
valid_mask = amps >= amp_cut*max_amp
|
||||
|
||||
if True: # make sure not to use other peaks
|
||||
lower_mask = valid_mask[0:max_amp_idx]
|
||||
upper_mask = valid_mask[max_amp_idx:]
|
||||
|
||||
if any(lower_mask):
|
||||
lower_end = np.argmin(lower_mask[::-1])
|
||||
else:
|
||||
lower_end = max_amp_idx
|
||||
|
||||
if any(upper_mask):
|
||||
upper_end = np.argmin(upper_mask)
|
||||
else:
|
||||
upper_end = 0
|
||||
|
||||
|
||||
valid_mask[0:(max_amp_idx - lower_end)] = False
|
||||
valid_mask[(max_amp_idx + upper_end):] = False
|
||||
|
||||
if all(~valid_mask):
|
||||
frequencies[i] = np.nan
|
||||
continue
|
||||
|
||||
# fit Parabola
|
||||
parafit = Polynomial.fit(test_freqs[valid_mask], amps[valid_mask], 2)
|
||||
func = parafit.convert()
|
||||
|
||||
# find frequency where derivative is 0
|
||||
deriv = func.deriv(1)
|
||||
freq = deriv.roots()[0]
|
||||
|
||||
frequencies[i] = freq
|
||||
|
||||
else: # no frequency finding
|
||||
frequencies[:] = f_beacon_estimate
|
||||
|
||||
|
||||
n_samples = len(t_trace)
|
||||
# evaluate fourier transform at freq for each trace
|
||||
for i, freq in enumerate(frequencies):
|
||||
if freq is np.nan:
|
||||
phases[i] = np.nan
|
||||
amplitudes[i] = np.nan
|
||||
continue
|
||||
|
||||
real, imag = direct_fourier_transform(freq, t_trace, traces[i])
|
||||
|
||||
phases[i] = np.arctan2(imag, real)
|
||||
amplitudes[i] = 2/n_samples * (real**2 + imag**2)**0.5
|
||||
|
||||
return frequencies, phases, amplitudes
|
||||
|
||||
def coherence_sum_maxima(ref_x, y, k_step=1, k_start=0, k_end=None, periodic=True):
|
||||
"""
|
||||
Use the maximum of a coherent sum to determine
|
||||
the best number of samples to move
|
||||
"""
|
||||
N_samples = int( len(ref_x) )
|
||||
k_end = N_samples if k_end is None or k_end > max_k else k_end
|
||||
|
||||
ks = np.arange(k_start, k_end, step=k_step)
|
||||
|
||||
maxima = np.empty(len(ks))
|
||||
|
||||
if periodic is False:
|
||||
# prepend zeros
|
||||
N_zeros = N_samples
|
||||
preshift = 0 # only required for testing purposes
|
||||
|
||||
ref_x = np.pad(ref_x, (N_zeros-0,0), 'constant')
|
||||
y = np.pad(y, (N_zeros-preshift,preshift), 'constant')
|
||||
|
||||
for i,k in enumerate(ks, 0):
|
||||
augmented_y = np.roll(y, k)
|
||||
maxima[i] = max(ref_x + augmented_y)
|
||||
|
||||
return ks, maxima
|
|
@ -1,394 +0,0 @@
|
|||
# from wappy import *
|
||||
from earsim import *
|
||||
from atmocal import *
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from scipy.signal import hilbert
|
||||
from scipy import signal
|
||||
from scipy.interpolate import interp1d
|
||||
from scipy.optimize import curve_fit,minimize
|
||||
import pandas as pd
|
||||
import os
|
||||
|
||||
try:
|
||||
from joblib import Parallel, delayed
|
||||
except:
|
||||
Parallel = None
|
||||
delayed = lambda x: x
|
||||
|
||||
plt.rcParams.update({'font.size': 16})
|
||||
|
||||
atm = AtmoCal()
|
||||
|
||||
from matplotlib import cm
|
||||
|
||||
def set_pol_and_bp(e,low=0.03,high=0.08):
|
||||
for ant in e.antennas:
|
||||
E = [np.dot(e.uAxB,[ex,ey,ez]) for ex,ey,ez in zip(ant.Ex,ant.Ey,ant.Ez)]
|
||||
dt = ant.t[1] -ant.t[0]
|
||||
E = block_filter(E,dt,low,high)
|
||||
ant.E_AxB = E
|
||||
ant.t_AxB = ant.t
|
||||
|
||||
|
||||
def pow_and_time(test_loc,ev,dt=1.0):
|
||||
t_ = []
|
||||
a_ = []
|
||||
t_min = 1e9
|
||||
t_max = -1e9
|
||||
for ant in ev.antennas:
|
||||
#propagate to test location
|
||||
aloc = [ant.x,ant.y,ant.z]
|
||||
delta,dist = atm.light_travel_time(test_loc,aloc)
|
||||
delta = delta*1e9
|
||||
t__ = np.subtract(ant.t_AxB,delta)
|
||||
t_.append(t__)
|
||||
a_.append(ant.E_AxB)
|
||||
if t__[0] < t_min:
|
||||
t_min = t__[0]
|
||||
if t__[-1] > t_max:
|
||||
t_max = t__[-1]
|
||||
|
||||
t_sum = np.arange(t_min+1,t_max-1,dt)
|
||||
a_sum = np.zeros(len(t_sum))
|
||||
#interpolation
|
||||
for t_r,E_ in zip (t_,a_):
|
||||
f = interp1d(t_r,E_,assume_sorted=True,bounds_error=False,fill_value=0.)
|
||||
a_int = f(t_sum)
|
||||
a_sum = np.add(a_sum,a_int)
|
||||
if len(a_sum) != 0:
|
||||
P = np.sum(np.square(np.absolute(np.fft.fft(a_sum))))
|
||||
# normalise P with the length of the traces
|
||||
P = P/( t_sum[-1] - t_sum[0])
|
||||
else:
|
||||
print("ERROR, a_sum lenght = 0",
|
||||
"tmin ",t_min,
|
||||
"t_max ",t_max,
|
||||
"dt",dt)
|
||||
P = 0
|
||||
return P,t_,a_,a_sum,t_sum
|
||||
|
||||
def shower_axis_slice(e,Xb=200,Xe=1200,dX=2,zgr=0):
|
||||
zgr = zgr + e.core[2]
|
||||
N = int((Xe-Xb)/dX)
|
||||
Xs = np.array(np.linspace(Xb,Xe,N+1))
|
||||
ds = np.array([atm.distance_to_slant_depth(np.deg2rad(e.zenith),X,zgr) for X in Xs])
|
||||
|
||||
locs = []
|
||||
for d_ in ds:
|
||||
xc = np.sin(np.deg2rad(e.zenith))*np.cos(np.deg2rad(e.azimuth))* d_
|
||||
yc = np.sin(np.deg2rad(e.zenith))*np.sin(np.deg2rad(e.azimuth))* d_
|
||||
zc = np.cos(np.deg2rad(e.zenith))* d_
|
||||
locs.append([xc,yc,zc])
|
||||
p = []
|
||||
for loc in locs:
|
||||
P,t_,pulses_,wav,twav = pow_and_time(loc,e)
|
||||
p.append(P)
|
||||
p = np.asanyarray(p)
|
||||
return ds,Xs,locs,p
|
||||
|
||||
def shower_plane_slice(e,X=750.,Nx=10,Ny=10,wx=1e3,wy=1e3,xoff=0,yoff=0,zgr=0,n_jobs=None):
|
||||
zgr = zgr + e.core[2]
|
||||
dX = atm.distance_to_slant_depth(np.deg2rad(e.zenith),X,zgr)
|
||||
x = np.linspace(-wx,wx,Nx)
|
||||
y = np.linspace(-wy,wy,Ny)
|
||||
|
||||
def loop_func(x_, y_, xoff=xoff, yoff=yoff):
|
||||
loc = (x_+xoff)* e.uAxB + (y_+yoff)*e.uAxAxB + dX *e.uA
|
||||
P,t_,pulses_,wav,twav = pow_and_time(loc,e)
|
||||
|
||||
return x_+xoff, y_+yoff, P, loc
|
||||
|
||||
res = ( delayed(loop_func)(x_, y_) for x_ in x for y_ in y)
|
||||
|
||||
if Parallel:
|
||||
#if n_jobs is None change with `with parallel_backend`
|
||||
res = Parallel(n_jobs=n_jobs)(res)
|
||||
|
||||
# unpack loop results
|
||||
xx, yy, p, locs = zip(*res)
|
||||
|
||||
xx = np.asarray(xx)
|
||||
yy = np.asarray(yy)
|
||||
p = np.asanyarray(p)
|
||||
|
||||
return xx,yy,p,locs[np.argmax(p)]
|
||||
|
||||
def slice_figure(e,X,xx,yy,p,mode='horizontal', scatter_kwargs={}, colorbar_kwargs={'label':'Power'}):
|
||||
scatter_kwargs = {
|
||||
**dict(
|
||||
cmap='Spectral_r',
|
||||
alpha=0.9,
|
||||
s=30
|
||||
),
|
||||
**scatter_kwargs
|
||||
}
|
||||
|
||||
|
||||
fig, axs = plt.subplots(1,figsize=(10,8))
|
||||
fig.suptitle(r'E = %.1f EeV, $\theta$ = %.1f$^\circ$, $\phi$ = %.1f$^\circ$ X = %.f'%(e.energy,e.zenith,e.azimuth,X))
|
||||
sc = axs.scatter(xx/1e3,yy/1e3,c=p,**scatter_kwargs)
|
||||
fig.colorbar(sc,ax=axs, **colorbar_kwargs)
|
||||
zgr = 0 + e.core[2]
|
||||
dX = atm.distance_to_slant_depth(np.deg2rad(e.zenith),X,zgr)
|
||||
xc = np.sin(np.deg2rad(e.zenith))*np.cos(np.deg2rad(e.azimuth))* dX
|
||||
yc = np.sin(np.deg2rad(e.zenith))*np.sin(np.deg2rad(e.azimuth))* dX
|
||||
if mode == 'horizontal':
|
||||
axs.plot(xc/1e3,yc/1e3,'r+',ms=30)
|
||||
axs.set_xlabel('x (km)')
|
||||
axs.set_ylabel('y (km)')
|
||||
elif mode == "sp":
|
||||
axs.plot(0,0,'r+',ms=30)
|
||||
axs.set_xlabel('-v x B (km)')
|
||||
axs.set_ylabel(' vxvxB (km)')
|
||||
im = np.argmax(p)
|
||||
axs.plot(xx[im]/1e3,yy[im]/1e3,'bx',ms=30)
|
||||
fig.tight_layout()
|
||||
return fig,axs
|
||||
|
||||
def dist_to_line(xp,core,u):
|
||||
xp = np.array(xp)
|
||||
xp_core = xp-core
|
||||
c2 = np.dot(xp_core,xp_core)
|
||||
a2 = np.dot((np.dot(xp_core,u)*u),(np.dot(xp_core,u)*u))
|
||||
d = (np.abs(c2 - a2))**0.5
|
||||
return d
|
||||
|
||||
def dist_to_line_sum(param,data,weights):
|
||||
#distance line point: a = xp-core is D= | (a)^2-(a dot n)n |
|
||||
#where ux is direction of line and x0 is a point in the line (like t = 0)
|
||||
x0 = param[0]
|
||||
y0 = param[1]
|
||||
theta = param[2]
|
||||
phi = param[3]
|
||||
core = np.array([x0, y0, 0.])
|
||||
u = np.array([np.cos(phi)*np.sin(theta),np.sin(phi)*np.sin(theta),np.cos(theta)])
|
||||
dsum = 0
|
||||
for xp,w in zip(data,weights):
|
||||
dsum += dist_to_line(xp,core,u)*w**2
|
||||
# print('%.2e %.2e %.2e %.2e %.2e'%(x0,y0,theta,phi,dsum))
|
||||
return dsum/len(data)
|
||||
|
||||
def get_axis_points(e,savefig=True,path="",zgr=0,Xlow=300, Xhigh=1000, N_X=15, n_jobs=None):
|
||||
Xsteps = np.linspace(Xlow, Xhigh, N_X)
|
||||
zgr=zgr+e.core[2] #not exact
|
||||
dXref = atm.distance_to_slant_depth(np.deg2rad(e.zenith),750,zgr)
|
||||
scale2d = dXref*np.tan(np.deg2rad(2.))
|
||||
scale4d = dXref*np.tan(np.deg2rad(4.))
|
||||
scale0_2d=dXref*np.tan(np.deg2rad(0.2))
|
||||
|
||||
def loop_func(X):
|
||||
print("Starting", X)
|
||||
x,y,p,loc_max = shower_plane_slice(e,X,21,21,scale2d,scale2d)
|
||||
if savefig:
|
||||
fig,axs = slice_figure(e,X,x,y,p,'sp')
|
||||
fig.savefig(path+'X%d_a.pdf'%(X))
|
||||
plt.close(fig)
|
||||
im = np.argmax(p)
|
||||
if np.abs(x[im]) == np.max(x) or np.abs(y[im]) == (np.max(y)):
|
||||
x,y,p,loc_max = shower_plane_slice(e,X,21,21,scale4d,scale4d)
|
||||
if savefig:
|
||||
fig,axs = slice_figure(e,X,x,y,p,'sp')
|
||||
fig.savefig(path+'X%d_c.pdf'%(X))
|
||||
plt.close(fig)
|
||||
im = np.argmax(p)
|
||||
x,y,p,loc_max = shower_plane_slice(e,X,21,21,scale0_2d,scale0_2d,x[im],y[im])
|
||||
if savefig:
|
||||
fig,axs = slice_figure(e,X,x,y,p,'sp')
|
||||
fig.savefig(path+'X%d_b.pdf'%(X))
|
||||
plt.close(fig)
|
||||
|
||||
print("Finished", X)
|
||||
return np.max(p), loc_max
|
||||
|
||||
res = (delayed(loop_func)(X) for X in Xsteps)
|
||||
|
||||
if Parallel:
|
||||
#if n_jobs is None change with `with parallel_backend`
|
||||
res = Parallel(n_jobs=n_jobs)(res)
|
||||
|
||||
# unpack loop results
|
||||
max_vals, axis_points = zip(*res)
|
||||
|
||||
return Xsteps,axis_points,max_vals
|
||||
|
||||
def fit_track(e,axis_points,vals,nscale=1e0):
|
||||
weights = vals/np.max(vals)
|
||||
data=axis_points[:]
|
||||
data = [d/nscale for d in data] #km, to have more comparable step sizes
|
||||
x0=[0,0,np.deg2rad(e.zenith),np.deg2rad(e.azimuth)]
|
||||
res = minimize(dist_to_line_sum,args=(data,weights),x0=x0)
|
||||
zen_r = np.rad2deg(res.x[2])
|
||||
azi_r = np.rad2deg(res.x[3])
|
||||
print(res,zen_r,e.zenith,azi_r,e.azimuth)
|
||||
return zen_r,azi_r,[res.x[0]*nscale,res.x[1]*nscale,0]
|
||||
|
||||
|
||||
def update_event(e,core,theta,phi,axp=None):
|
||||
#recalculate
|
||||
e.zenith = theta
|
||||
e.azimuth = phi
|
||||
theta = np.deg2rad(theta)
|
||||
phi = np.deg2rad(phi)
|
||||
e.core = e.core+core
|
||||
e.uA = np.array([np.cos(phi)*np.sin(theta),np.sin(phi)*np.sin(theta),np.cos(theta)])
|
||||
e.uAxB = np.cross(e.uA,e.uB)
|
||||
e.uAxB = e.uAxB/(np.dot(e.uAxB,e.uAxB))**0.5
|
||||
e.uAxAxB = np.cross(e.uA,e.uAxB)
|
||||
#antenna position
|
||||
for a in e.antennas:
|
||||
a.x -= core[0]
|
||||
a.y -= core[1]
|
||||
a.z -= core[2]
|
||||
if axp != None:
|
||||
for ap in axp:
|
||||
ap[0] -= core[0]
|
||||
ap[1] -= core[1]
|
||||
ap[2] -= core[2]
|
||||
|
||||
def longitudinal_figure(dist,Xs,p,mode='grammage'):
|
||||
fig, axs = plt.subplots(1,figsize=(6,5))
|
||||
if mode=='grammage':
|
||||
axs.plot(Xs,p/np.max(p),'o-')
|
||||
axs.set_xlabel('X (g/cm$^2$)')
|
||||
if mode=='distance':
|
||||
axs.plot(dist/1e3,p/np.max(p),'o-')
|
||||
axs.set_xlabel('distance from ground (km)')
|
||||
axs.grid()
|
||||
fig.tight_layout()
|
||||
return fig
|
||||
|
||||
def time_residuals(e,tlable=True):
|
||||
ds,tp,nsum,ssum,swidth,azi,x,y,sid = lateral_parameters(e,True,[0,0,0])
|
||||
fig, axs = plt.subplots(1,figsize=(6,5),sharex=True)
|
||||
tp = tp-np.min(tp)
|
||||
cut_outlier = ~((ds<200)&(tp > 10))
|
||||
axs.plot(ds,tp,'o')
|
||||
if tlable:
|
||||
for d,t,s in zip(ds,tp,sid):
|
||||
plt.text(d,t,s)
|
||||
# axs.text(ds,tp,sid)
|
||||
axs.set_xlabel('distance (m)')
|
||||
axs.set_ylabel('$\Delta t (ns)$')
|
||||
axs.grid()
|
||||
z = np.polyfit(ds[cut_outlier],tp[cut_outlier],3)
|
||||
pfit = np.poly1d(z)
|
||||
xfit = np.linspace(np.min(ds),np.max(ds),100)
|
||||
yfit = pfit(xfit)
|
||||
tres = tp - pfit(ds)
|
||||
sigma =np.std(tres[cut_outlier])
|
||||
axs.plot(xfit,yfit,label=r'pol3 fit, $\sigma=%.2f$ (ns)'%(sigma))
|
||||
axs.legend()
|
||||
fig.tight_layout()
|
||||
return fig,tres
|
||||
|
||||
def figure_3D(axis_points,max_vals,zen,azi,core,res = 0):
|
||||
fig = plt.figure(figsize=(5,9))
|
||||
# fig, axs = plt.subplots(1,2,figsize=(12,8))
|
||||
ax = fig.add_subplot(2,1,1,projection='3d')
|
||||
xp = [ap[0]/1e3 for ap in axis_points]
|
||||
yp = [ap[1]/1e3 for ap in axis_points]
|
||||
zp = [ap[2]/1e3 for ap in axis_points]
|
||||
max_vals = np.asarray(max_vals)
|
||||
ax.scatter(xp, yp, zp,c=max_vals,s=150*(max_vals/np.max(max_vals))**2,cmap='Spectral_r')
|
||||
ax = fig.add_subplot(2,1,2)
|
||||
core = np.array(core)
|
||||
theta = np.deg2rad(zen)
|
||||
phi = np.deg2rad(azi)
|
||||
u = np.array([np.cos(phi)*np.sin(theta),np.sin(phi)*np.sin(theta),np.cos(theta)])
|
||||
residuals = [dist_to_line(ap,core,u) for ap in axis_points]
|
||||
dist = [np.sum((ap-core)**2)**0.5 for ap in axis_points]
|
||||
ax.scatter(dist,residuals,c=max_vals,cmap='Spectral_r')
|
||||
ax.grid()
|
||||
# ax.plot(xl,yl,zl,'-')
|
||||
# ax.set_zlim(0,18)
|
||||
# ax.view_init(15, 10)
|
||||
fig.tight_layout()
|
||||
if res != 0:
|
||||
res.track_dis.append(dist)
|
||||
res.track_res.append(residuals)
|
||||
res.track_val.append(max_vals)
|
||||
return fig
|
||||
|
||||
class RITResult():
|
||||
"""docstring for RITResult."""
|
||||
def __init__(self):
|
||||
super(RITResult, self).__init__()
|
||||
self.xmax_rit = []
|
||||
self.xmax = []
|
||||
self.profile_rit = []
|
||||
self.dX = []
|
||||
self.dl = []
|
||||
self.zenith_ini = []
|
||||
self.azimuth_ini = []
|
||||
self.core_ini = []
|
||||
self.dcore_rec = []
|
||||
self.zenith_rec = []
|
||||
self.azimuth_rec = []
|
||||
self.index = []
|
||||
self.isMC = []
|
||||
self.track_dis = []
|
||||
self.track_res =[]
|
||||
self.track_val =[]
|
||||
self.station_ids =[]
|
||||
self.station_x =[]
|
||||
self.station_y =[]
|
||||
self.station_z =[]
|
||||
self.station_maxE = []
|
||||
self.has_pulse = []
|
||||
|
||||
def fill_stations_propeties(e,res):
|
||||
x = np.array([a.x for a in e.antennas])
|
||||
y = np.array([a.y for a in e.antennas])
|
||||
z = np.array([a.z for a in e.antennas])
|
||||
ids = [a.name for a in e.antennas]
|
||||
maxE = np.array([np.max(a.E_AxB) for a in e.antennas])
|
||||
#has_pulse = np.array([np.max(a.has_pulse) for a in e.antennas])
|
||||
res.station_x.append(x)
|
||||
res.station_y.append(y)
|
||||
res.station_z.append(z)
|
||||
res.station_ids.append(ids)
|
||||
#res.has_pulse.append(has_pulse)
|
||||
|
||||
def reconstruction(e,outfile='', slice_outdir=None, Xlow=300, Xhigh=1000, N_X=15, disable_pol_and_bp=False):
|
||||
res = RITResult()
|
||||
res.isMC.append(True)
|
||||
res.zenith_ini.append(e.zenith)
|
||||
res.azimuth_ini.append(e.azimuth)
|
||||
res.core_ini.append(e.core)
|
||||
|
||||
if not disable_pol_and_bp:
|
||||
set_pol_and_bp(e, 0.03, 0.08)
|
||||
|
||||
#only use signal that have a signal in data
|
||||
fill_stations_propeties(e,res)
|
||||
Xs,axis_points,max_vals = get_axis_points(e,savefig=(slice_outdir is not None), path=slice_outdir, Xlow=Xlow, Xhigh=Xhigh, N_X=N_X)
|
||||
zen,azi,core = fit_track(e,axis_points,max_vals,1e2)
|
||||
fig = figure_3D(axis_points,max_vals,zen,azi,core,res)
|
||||
fig.savefig(outfile)
|
||||
update_event(e,core,zen,azi)
|
||||
ds,Xs,locs,p = shower_axis_slice(e)
|
||||
#result
|
||||
res.dX.append(Xs)
|
||||
res.dl.append(ds)
|
||||
res.profile_rit.append(p)
|
||||
res.xmax_rit.append(Xs[np.argmax(p)])
|
||||
res.azimuth_rec.append(e.azimuth)
|
||||
res.zenith_rec.append(e.zenith)
|
||||
res.dcore_rec.append(core)
|
||||
return res
|
||||
|
||||
if __name__ == "__main__":
|
||||
file = '../ZH_airshower/mysim.sry'
|
||||
ev = REvent(file)
|
||||
set_pol_and_bp(ev)
|
||||
X = 750
|
||||
|
||||
dXref = atm.distance_to_slant_depth(np.deg2rad(ev.zenith),X,0)
|
||||
scale2d = dXref*np.tan(np.deg2rad(2.))
|
||||
xx,yy,p,km= shower_plane_slice(ev,X,21,21,scale2d,scale2d)
|
||||
|
||||
slice_figure(ev,X,xx,yy,p,mode='sp')
|
||||
#plt.scatter(xx,yy,c=p)
|
||||
#plt.colorbar()
|
||||
plt.show()
|
|
@ -1,97 +0,0 @@
|
|||
import numpy as np
|
||||
from collections import namedtuple
|
||||
|
||||
from lib import direct_fourier_transform as dtft
|
||||
|
||||
import matplotlib.pyplot as plt # for debug plotting
|
||||
|
||||
passband = namedtuple("passband", ['low', 'high'], defaults=[0, np.inf])
|
||||
|
||||
def get_freq_spec(val,dt):
|
||||
"""From earsim/tools.py"""
|
||||
fval = np.fft.fft(val)[:len(val)//2]
|
||||
freq = np.fft.fftfreq(len(val),dt)[:len(val)//2]
|
||||
return fval, freq
|
||||
|
||||
|
||||
def bandpass_samples(samples, samplerate, band=passband()):
|
||||
"""
|
||||
Bandpass the samples with this passband.
|
||||
This is a hard filter.
|
||||
"""
|
||||
fft, freqs = get_freq_spec(samples, samplerate)
|
||||
|
||||
fft[ ~ self.freq_mask(freqs) ] = 0
|
||||
|
||||
return np.fft.irfft(fft)
|
||||
|
||||
def bandpass_mask(freqs, band=passband()):
|
||||
low_pass = abs(freqs) <= band[1]
|
||||
high_pass = abs(freqs) >= band[0]
|
||||
|
||||
return low_pass & high_pass
|
||||
|
||||
def bandpower(samples, samplerate=1, band=passband(), normalise_bandsize=True, debug_ax=False):
|
||||
bins = 0
|
||||
fft, freqs = get_freq_spec(samples, 1/samplerate)
|
||||
bandmask = [False]*len(freqs)
|
||||
|
||||
if band[1] is None:
|
||||
# Only a single frequency given
|
||||
# use a DTFT for finding the power
|
||||
time = np.arange(0, len(samples), 1/samplerate)
|
||||
|
||||
real, imag = dtft(band[0], time, samples)
|
||||
power = np.sum(np.abs(real**2 + imag**2))
|
||||
else:
|
||||
bandmask = bandpass_mask(freqs, band=band)
|
||||
|
||||
if normalise_bandsize:
|
||||
bins = np.count_nonzero(bandmask, axis=-1)
|
||||
else:
|
||||
bins = 1
|
||||
|
||||
bins = max(1, bins)
|
||||
|
||||
power = 1/bins * np.sum(np.abs(fft[bandmask])**2)
|
||||
|
||||
# Prepare plotting variables if an Axes is supplied
|
||||
if debug_ax:
|
||||
if any(bandmask):
|
||||
min_f, max_f = min(freqs[bandmask]), max(freqs[bandmask])
|
||||
else:
|
||||
min_f, max_f = 0, 0
|
||||
|
||||
if band[1] is None:
|
||||
min_f, max_f = band[0], band[0]
|
||||
|
||||
if debug_ax is True:
|
||||
debug_ax = plt.gca()
|
||||
|
||||
l = debug_ax.plot(freqs, np.abs(fft), alpha=0.9)
|
||||
|
||||
amp = np.sqrt(power)
|
||||
|
||||
if min_f != max_f:
|
||||
debug_ax.plot( [min_f, max_f], [amp, amp], alpha=0.7, color=l[0].get_color(), ls='dashed')
|
||||
debug_ax.axvspan(min_f, max_f, color=l[0].get_color(), alpha=0.2)
|
||||
else:
|
||||
debug_ax.plot( min_f, amp, '4', alpha=0.7, color=l[0].get_color(), ms=10)
|
||||
|
||||
return power
|
||||
|
||||
def signal_to_noise(samples, noise, samplerate=1, signal_band=passband(), noise_band=None, debug_ax=False):
|
||||
if noise_band is None:
|
||||
noise_band = signal_band
|
||||
|
||||
if noise is None:
|
||||
noise = samples
|
||||
|
||||
if debug_ax is True:
|
||||
debug_ax = plt.gca()
|
||||
|
||||
noise_power = bandpower(noise, samplerate, noise_band, debug_ax=debug_ax)
|
||||
|
||||
signal_power = bandpower(samples, samplerate, signal_band, debug_ax=debug_ax)
|
||||
|
||||
return (signal_power/noise_power)**0.5
|
|
@ -1 +0,0 @@
|
|||
../
|
|
@ -1,108 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Test the functions in lib concerning
|
||||
beacon generation and phase measuring
|
||||
work correctly together.
|
||||
"""
|
||||
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
import lib
|
||||
|
||||
seed = 12345
|
||||
dt = 1 # ns
|
||||
frequency = 52.12345e-3 # GHz
|
||||
N = 5e2
|
||||
t_clock = 0
|
||||
beacon_amplitude = 1
|
||||
|
||||
t = np.arange(0, 10*int(1e3), dt, dtype=float)
|
||||
rng = np.random.default_rng(seed)
|
||||
|
||||
|
||||
# Vary both the base time and the phase
|
||||
t_extra = 0
|
||||
phase_res = np.zeros(int(N))
|
||||
amp_res = np.zeros(int(N))
|
||||
for i in range(int(N)):
|
||||
# Change timebase
|
||||
t -= t_extra
|
||||
t_extra = (2*rng.uniform(size=1) - 1) *1e3
|
||||
t += t_extra
|
||||
|
||||
# Randomly phased beacon
|
||||
phase = lib.phase_mod(np.pi*(2*rng.uniform(size=1) -1)) # rad
|
||||
beacon = beacon_amplitude * lib.sine_beacon(frequency, t, t0=0, phase=phase, peak_at_t0=False)
|
||||
|
||||
if False: # blank part of the beacon
|
||||
blank_low, blank_high = int(0.2*len(t)), int(0.4*len(t))
|
||||
t_mask = np.ones(len(t), dtype=bool)
|
||||
t_mask[blank_low:blank_high] = False
|
||||
|
||||
t = t[t_mask]
|
||||
beacon = beacon[t_mask]
|
||||
|
||||
# Introduce clock errors
|
||||
t += t_clock
|
||||
_, measured_phases, measured_amplitudes = lib.find_beacon_in_traces([beacon], t, frequency, frequency_fit=False)
|
||||
t -= t_clock
|
||||
|
||||
# Save residuals
|
||||
phase_res[i] = lib.phase_mod(measured_phases[0] - phase)
|
||||
amp_res[i] = measured_amplitudes[0] - beacon_amplitude
|
||||
|
||||
###
|
||||
## Present figures
|
||||
###
|
||||
phase2time = lambda x: x/(2*np.pi*frequency)
|
||||
time2phase = lambda x: 2*np.pi*x*frequency
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_title("Sine beacon phase determination\nwith random time shifts")
|
||||
ax.set_xlabel("$\\varphi_{meas} - \\varphi_{true}$ [rad]")
|
||||
ax.set_ylabel("#")
|
||||
ax.hist(phase_res, bins='sqrt')
|
||||
if True:
|
||||
ax.axvline( -1*lib.phase_mod(t_clock*frequency*2*np.pi), color='red', lw=5, alpha=0.8, label='true t_clock')
|
||||
if True:
|
||||
secax = ax.secondary_xaxis(1.0, functions=(phase2time, time2phase))
|
||||
secax.set_xlabel('Time [ns]')
|
||||
ax.legend(title='N={:.1e}'.format(len(t)))
|
||||
phase_xlims = ax.get_xlim()
|
||||
fig.tight_layout()
|
||||
|
||||
amp_xlims = None
|
||||
if True:
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_title("Amplitude")
|
||||
ax.set_xlabel("$A_{meas} - 1$")
|
||||
ax.set_ylabel("#")
|
||||
ax.legend(title='N={:.1e}'.format(len(t)))
|
||||
ax.hist(amp_res, bins='sqrt')
|
||||
fig.tight_layout()
|
||||
|
||||
amp_xlims = ax.get_xlim()
|
||||
|
||||
if True:
|
||||
fig, ax = plt.subplots()
|
||||
ax.grid()
|
||||
ax.set_xlabel("Phase Res [rad]")
|
||||
ax.set_ylabel("Amplitude Res")
|
||||
sc = ax.scatter( phase_res, amp_res )
|
||||
#fig.colorbar(sc, ax=ax)
|
||||
|
||||
ax.set_xlim(phase_xlims)
|
||||
if amp_xlims is not None:
|
||||
ax.set_ylim(amp_xlims)
|
||||
if True:
|
||||
ax.axvline( -1*lib.phase_mod(t_clock*frequency*2*np.pi), color='red', lw=5, alpha=0.8, label='true t_clock')
|
||||
if True:
|
||||
secax = ax.secondary_xaxis(1.0, functions=(phase2time, time2phase))
|
||||
secax.set_xlabel('Time [ns]')
|
||||
ax.legend(title='N={:.1e}'.format(len(t)))
|
||||
fig.tight_layout()
|
||||
|
||||
plt.show()
|
|
@ -1,119 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Test the functions in lib concerning
|
||||
beacon generation and removing the geometrical phase
|
||||
work correctly together.
|
||||
"""
|
||||
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
from earsim import Antenna
|
||||
import lib
|
||||
|
||||
seed = 12345
|
||||
dt = 1 # ns
|
||||
frequency = 52.12345e-3 # GHz
|
||||
N = 5e2
|
||||
t_clock = 0
|
||||
beacon_amplitude = 1
|
||||
c_light = lib.c_light
|
||||
|
||||
t = np.arange(0, 10*int(1e3), dt, dtype=float)
|
||||
rng = np.random.default_rng(seed)
|
||||
|
||||
tx = Antenna(x=0,y=0,z=0,name='tx')
|
||||
rx = Antenna(x=tx.x,y=tx.y,z=tx.z,name='rx')
|
||||
|
||||
# Vary both the base time and the phase
|
||||
t_extra = 0
|
||||
phase_res = np.zeros(int(N))
|
||||
amp_res = np.zeros(int(N))
|
||||
for i in range(int(N)):
|
||||
# Change timebase
|
||||
t -= t_extra
|
||||
t_extra = (2*rng.uniform(size=1) - 1) *1e3
|
||||
t += t_extra
|
||||
|
||||
# Randomise Antenna Location
|
||||
if True:
|
||||
rx.x, rx.y, rx.z = (2*rng.uniform(size=3) -1) * 1e4
|
||||
|
||||
# Randomly phased beacon
|
||||
# at Antenna
|
||||
phase = lib.phase_mod(np.pi*(2*rng.uniform(size=1) -1)) # rad
|
||||
beacon = beacon_amplitude * lib.beacon_from(tx, rx, frequency, t, t0=0, phase=phase, peak_at_t0=False, c_light=c_light, radiate_rsq=False)
|
||||
|
||||
if False: # blank part of the beacon
|
||||
blank_low, blank_high = int(0.2*len(t)), int(0.4*len(t))
|
||||
t_mask = np.ones(len(t), dtype=bool)
|
||||
t_mask[blank_low:blank_high] = False
|
||||
|
||||
t = t[t_mask]
|
||||
beacon = beacon[t_mask]
|
||||
|
||||
# Introduce clock errors
|
||||
t += t_clock
|
||||
_, measured_phases, measured_amplitudes = lib.find_beacon_in_traces([beacon], t, frequency, frequency_fit=False)
|
||||
t -= t_clock
|
||||
|
||||
calculated_phases = lib.remove_antenna_geometry_phase(tx, rx, frequency, measured_phases, c_light=c_light)
|
||||
|
||||
# Save residuals
|
||||
phase_res[i] = lib.phase_mod(calculated_phases[0] - phase)
|
||||
amp_res[i] = measured_amplitudes[0] - beacon_amplitude
|
||||
|
||||
###
|
||||
## Present figures
|
||||
###
|
||||
phase2time = lambda x: x/(2*np.pi*frequency)
|
||||
time2phase = lambda x: 2*np.pi*x*frequency
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_title("Measured phase at Antenna - geometrical phase")
|
||||
ax.set_xlabel("$\\varphi_{meas} - \\varphi_{true}$ [rad]")
|
||||
ax.set_ylabel("#")
|
||||
ax.hist(phase_res, bins='sqrt')
|
||||
if True:
|
||||
ax.axvline( -1*lib.phase_mod(t_clock*frequency*2*np.pi), color='red', lw=5, alpha=0.8, label='true t_clock')
|
||||
if True:
|
||||
secax = ax.secondary_xaxis(1.0, functions=(phase2time, time2phase))
|
||||
secax.set_xlabel('Time [ns]')
|
||||
ax.legend(title='N={:.1e}'.format(len(t)))
|
||||
phase_xlims = ax.get_xlim()
|
||||
fig.tight_layout()
|
||||
|
||||
amp_xlims = None
|
||||
if True:
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_title("Amplitude")
|
||||
ax.set_xlabel("$A_{meas} - 1$")
|
||||
ax.set_ylabel("#")
|
||||
ax.legend(title='N={:.1e}'.format(len(t)))
|
||||
ax.hist(amp_res, bins='sqrt')
|
||||
fig.tight_layout()
|
||||
|
||||
amp_xlims = ax.get_xlim()
|
||||
|
||||
if True:
|
||||
fig, ax = plt.subplots()
|
||||
ax.grid()
|
||||
ax.set_xlabel("Phase Res [rad]")
|
||||
ax.set_ylabel("Amplitude Res")
|
||||
sc = ax.scatter( phase_res, amp_res )
|
||||
#fig.colorbar(sc, ax=ax)
|
||||
|
||||
ax.set_xlim(phase_xlims)
|
||||
if amp_xlims is not None:
|
||||
ax.set_ylim(amp_xlims)
|
||||
if True:
|
||||
ax.axvline( -1*lib.phase_mod(t_clock*frequency*2*np.pi), color='red', lw=5, alpha=0.8, label='true t_clock')
|
||||
if True:
|
||||
secax = ax.secondary_xaxis(1.0, functions=(phase2time, time2phase))
|
||||
secax.set_xlabel('Time [ns]')
|
||||
ax.legend(title='N={:.1e}'.format(len(t)))
|
||||
fig.tight_layout()
|
||||
|
||||
plt.show()
|
|
@ -1 +0,0 @@
|
|||
base
|
|
@ -1,67 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
def parse_env_file(fname):
|
||||
envs = {}
|
||||
env_reg = re.compile('^(?:\s*export)?\s*(.*)\s*=\s*(.*)\s*$')
|
||||
|
||||
with open(fname, 'r') as f:
|
||||
for line in f:
|
||||
if '=' not in line:
|
||||
continue
|
||||
|
||||
m = env_reg.match(line)
|
||||
envs[m.group(1)] = m.group(2)
|
||||
|
||||
return envs
|
||||
|
||||
def mutilate_figure_name(fig_fname, envs):
|
||||
return fig_fname
|
||||
|
||||
if __name__ == "__main__":
|
||||
from argparse import ArgumentParser
|
||||
|
||||
parser = ArgumentParser()
|
||||
#parser.add_argument('-f', '--figures', nargs='*')
|
||||
parser.add_argument("-d", "--directories", nargs='*')
|
||||
parser.add_argument('out_dir', default='./figures', type=str)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
os.makedirs(args.out_dir, exist_ok=True)
|
||||
|
||||
#with open(args.out_file, 'w') as fp:
|
||||
if True:
|
||||
for d in args.directories:
|
||||
d = os.path.realpath(d)
|
||||
fig_dir = os.path.join(d, 'figures')
|
||||
env_fname = os.path.join(d, 'env.sh')
|
||||
|
||||
if not os.path.exists(fig_dir):
|
||||
print(f"Cannot find {fig_dir}")
|
||||
continue
|
||||
|
||||
## parse properties from env.sh
|
||||
#envs = parse_env_file(env_fname)
|
||||
#print(envs, fig_dir)
|
||||
|
||||
for f in os.listdir(fig_dir):
|
||||
fname, ext = os.path.splitext(f)
|
||||
|
||||
dname = os.path.basename(d)
|
||||
|
||||
if ext not in ['.pdf', '.png']:
|
||||
continue
|
||||
|
||||
link_name = fname + "_" + dname + ext
|
||||
|
||||
target = os.path.realpath(os.path.join(fig_dir, f))
|
||||
tmpLink = tempfile.mktemp(dir=args.out_dir)
|
||||
|
||||
os.symlink(target, tmpLink)
|
||||
os.rename(tmpLink, os.path.join(args.out_dir, link_name))
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import os.path as path
|
||||
from itertools import product
|
||||
|
||||
baselines = [ '', 72 ]
|
||||
noise_sigmas = [ 0, '1e4' ]
|
||||
clock_devs = [0, 20]
|
||||
trace_lengths = [ 4096 ]#, 16384 ]
|
||||
|
||||
for options in product(baselines, clock_devs, noise_sigmas, trace_lengths):
|
||||
baseline, clk_dev, noise, trace = options
|
||||
|
||||
dirname = f"matrix_c{clk_dev}_b{baseline}_N{trace}_noise{noise}"
|
||||
print(dirname)
|
||||
|
||||
# Make directory
|
||||
if path.exists(dirname):
|
||||
print(f"{dirname} already exists! continuing anyway..")
|
||||
|
||||
os.makedirs(dirname, exist_ok=True)
|
||||
|
||||
# Soft link clock file if available
|
||||
if True:
|
||||
os.makedirs(path.join(dirname, 'data'), exist_ok=True)
|
||||
|
||||
if not path.isfile(path.join(dirname, 'data/clocks.csv')):
|
||||
os.symlink(f'../../c{clk_dev}_clocks.csv', path.join(dirname, 'data/clocks.csv'))
|
||||
|
||||
# Setup config.mk
|
||||
with open(path.join(dirname, 'env.sh'), 'w') as fp:
|
||||
template = f"""
|
||||
export CLK_DEV={clk_dev}
|
||||
export REF_ANTS={baseline}
|
||||
export NOISE_SIGMA={noise}
|
||||
export TRACE_N={trace}
|
||||
"""
|
||||
fp.write(template)
|
|
@ -1,217 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import json
|
||||
|
||||
from scipy import special
|
||||
|
||||
|
||||
# Mimic import aa_generate_beacon as beacon
|
||||
beacon = lambda: None
|
||||
|
||||
def read_snr_file(fname):
|
||||
with open(fname, 'r') as fp:
|
||||
return json.load(fp)
|
||||
|
||||
def read_tx_file(fname):
|
||||
with open(fname, 'r') as fp:
|
||||
data = json.load(fp)
|
||||
|
||||
f_beacon = data['f_beacon']
|
||||
tx = data['tx']
|
||||
|
||||
del data['f_beacon']
|
||||
del data['tx']
|
||||
|
||||
return tx, f_beacon, data
|
||||
|
||||
|
||||
beacon.snr_fname = 'snr.json'
|
||||
beacon.tx_fname = 'tx.json'
|
||||
beacon.read_snr_file = read_snr_file
|
||||
beacon.read_tx_file = read_tx_file
|
||||
|
||||
def read_snr_directories(data_directories, tx_fname=beacon.tx_fname, snr_fname=beacon.snr_fname, phase_res_fname='phase_time_residuals.json'):
|
||||
# Read in snr
|
||||
snrs = np.zeros(len(data_directories), dtype=float)
|
||||
time_residuals = np.zeros( (len(snrs), 2), dtype=float)
|
||||
|
||||
|
||||
tx, f_beacon, _ = beacon.read_tx_file(path.join(data_directories[0], tx_fname))
|
||||
for i, data_dir in enumerate(data_directories):
|
||||
# Read SNR file
|
||||
snr_data = read_snr_file(path.join(data_dir, snr_fname))
|
||||
|
||||
# Open antennas file
|
||||
with open(path.join(data_dir, phase_res_fname), 'r') as fp:
|
||||
time_res_data = json.load(fp)
|
||||
|
||||
snrs[i] = snr_data['mean']
|
||||
|
||||
time_residuals[i] = time_res_data['mean'], time_res_data['std']
|
||||
|
||||
return f_beacon, snrs, time_residuals
|
||||
|
||||
|
||||
## Math
|
||||
def expectation(x, pdfx):
|
||||
dx = x[1] - x[0]
|
||||
return np.sum(x*pdfx*dx)
|
||||
|
||||
def variance(x, pdfx):
|
||||
mu = expectation(x, pdfx)
|
||||
dx = x[1] - x[0]
|
||||
return np.sum(x**2 *pdfx*dx) - mu**2
|
||||
|
||||
def phase_distribution(theta, sigma, s):
|
||||
k = s/sigma
|
||||
ct = np.cos(theta)
|
||||
st = np.sin(theta)
|
||||
pipi = 2*np.pi
|
||||
|
||||
return (np.exp(-k**2/2)/pipi) \
|
||||
+ (
|
||||
(pipi**-0.5)*k*np.exp(-(k*st)**2/2)
|
||||
* ((1.+special.erf(k*ct*2**-0.5))*ct/2)
|
||||
)
|
||||
|
||||
def phase_distribution_gauss(theta, sigma, s):
|
||||
k = s/sigma
|
||||
return 1/np.sqrt(2*np.pi) * k *np.exp( -(k*theta)**2/2)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
|
||||
import os
|
||||
import matplotlib
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from argparse import ArgumentParser
|
||||
parser = ArgumentParser()
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
# Multiple Data Directories
|
||||
parser.add_argument("-d", dest='data_directories', default=[], nargs='*')
|
||||
|
||||
# Whether to show plots
|
||||
group1 = parser.add_mutually_exclusive_group(required=False)
|
||||
group1.add_argument('--show-plots', action='store_true', default=True, help='Default: %(default)s')
|
||||
group1.add_argument('--no-show-plots', dest='show-plots', action='store_false')
|
||||
|
||||
# Figures directory
|
||||
parser.add_argument('--fig-dir', type=str, default='./figures', help='Set None to disable saving figures. (Default: %(default)s)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
show_plots = args.show_plots
|
||||
|
||||
if not args.data_directories:
|
||||
parser.error("At least one data directory should be specified.")
|
||||
|
||||
f_beacon, snrs, time_residuals = read_snr_directories(args.data_directories)
|
||||
|
||||
phase2time = lambda x: x/(2*np.pi*f_beacon)
|
||||
time2phase = lambda x: 2*np.pi*x*f_beacon
|
||||
|
||||
fig, ax = plt.subplots(figsize=(8,6))
|
||||
ax.set_title("Beacon ({:.2f}MHz) Simulation".format(f_beacon*1e3))
|
||||
ax.set_xlabel('Signal to Noise ratio')
|
||||
ax.set_ylabel('Time Accuracy $\\sigma(t)$ [ns]')
|
||||
|
||||
# group per directories per N
|
||||
if True:
|
||||
import re
|
||||
|
||||
dirdict = {}
|
||||
N_re = re.compile(r'_N(\d+)_')
|
||||
|
||||
for d in args.data_directories:
|
||||
m = N_re.findall(d)[0]
|
||||
|
||||
if m not in dirdict:
|
||||
dirdict[m] = []
|
||||
|
||||
dirdict[m].append(d)
|
||||
|
||||
|
||||
dirlist = dirdict.values()
|
||||
|
||||
# plot data directories as one group
|
||||
else:
|
||||
dirlist = [args.data_directories]
|
||||
|
||||
for dirlist in dirlist:
|
||||
f_beacon, snrs, time_residuals = read_snr_directories(dirlist)
|
||||
|
||||
# plot data
|
||||
ax.plot(snrs*np.sqrt(np.pi/2), phase2time(time_residuals[:,1]), ls='none', marker='o')
|
||||
|
||||
# Add secondary axis
|
||||
if True:
|
||||
if False and secondary_axis == 'time':
|
||||
functions = (phase2time, time2phase)
|
||||
label = 'Time Accuracy $\\sigma_t\\varphi/(2\\pi f_{beac})$ [ns]'
|
||||
else:
|
||||
functions = (time2phase, phase2time)
|
||||
label = 'Phase Accuracy $\\sigma_\\varphi$ [rad]'
|
||||
|
||||
secax = ax.secondary_yaxis('right', functions=functions)
|
||||
secax.set_ylabel(label)
|
||||
|
||||
# logscales
|
||||
if True:
|
||||
ax.set_xscale('log')
|
||||
ax.set_yscale('log')
|
||||
|
||||
# plot phasor snr
|
||||
if True:
|
||||
thetas = np.linspace(-np.pi, np.pi, 500)
|
||||
sigma = 1
|
||||
_snr_min = min(10, min(snrs))
|
||||
_snr_max = min(100, max(snrs))
|
||||
|
||||
if ax.get_xscale() == 'log': #log
|
||||
_snrs = np.logspace(np.log10(_snr_min), np.log10(_snr_max))
|
||||
else: #linear
|
||||
_snrs = np.linspace(_snr_min, _snr_max)
|
||||
|
||||
# Phasor Rice
|
||||
phasor_pdfs = np.array([phase_distribution(thetas, sigma, s) for s in _snrs ])
|
||||
phasor_sigma = np.sqrt(np.array([variance(thetas, pdf) for pdf in phasor_pdfs]))
|
||||
|
||||
ax.plot(_snrs, phase2time(phasor_sigma), label='Rice')
|
||||
|
||||
if True: # plot a pdf
|
||||
fig2, ax2 = plt.subplots()
|
||||
for idx in [0, len(_snrs)//4, len(_snrs)//2, -1]:
|
||||
ax2.plot(thetas, phasor_pdfs[idx], label='s = {:.1f}'.format(_snrs[idx]))
|
||||
ax2.set_xlabel('$\\theta$')
|
||||
ax2.set_ylabel('$p(\\theta)$')
|
||||
ax2.legend()
|
||||
|
||||
# Gauss Phasor
|
||||
phasor_pdfs = np.array([phase_distribution_gauss(thetas, sigma, s) for s in _snrs ])
|
||||
phasor_sigma = np.sqrt(np.array([variance(thetas, pdf) for pdf in phasor_pdfs]))
|
||||
|
||||
ax.plot(_snrs, phase2time(phasor_sigma), label='Gauss')
|
||||
ax.legend()
|
||||
|
||||
# Set limit on x values
|
||||
if not True or ax.get_xscale() != 'log':
|
||||
ax.set_xlim(0, 100)
|
||||
|
||||
if args.fig_dir:
|
||||
fig.tight_layout()
|
||||
fig.savefig(path.join(args.fig_dir, "time_res_vs_snr.pdf"))
|
||||
|
||||
if args.show_plots:
|
||||
plt.show()
|
||||
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
MATRIXDIR='/scratch/etdeboone/matrix'
|
||||
MATRIX_ELS="${@:-$MATRIXDIR/matrix*/}"
|
||||
|
||||
BASE=$(realpath ../base)
|
||||
MAKE="make -C ${BASE} "
|
||||
|
||||
for d in "$MATRIX_ELS" ;
|
||||
do
|
||||
echo "Entering $d"
|
||||
pushd "$d";
|
||||
|
||||
# Source constants
|
||||
. env.sh
|
||||
export FIG_DIR=$(realpath "./figures")
|
||||
export DATA_DIR=$(realpath "./data")
|
||||
|
||||
mkdir -p $FIG_DIR $DATA_DIR
|
||||
|
||||
$MAKE beacon;
|
||||
$MAKE clocks;
|
||||
$MAKE phases;
|
||||
$MAKE findks;
|
||||
#$MAKE reconstruct;
|
||||
echo "Popping"
|
||||
popd
|
||||
done
|
|
@ -1,122 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
import h5py
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D # required for projection='3d' on old matplotliblib versions
|
||||
import numpy as np
|
||||
from copy import deepcopy
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
from lib import rit
|
||||
from earsim import REvent, Antenna
|
||||
from atmocal import AtmoCal
|
||||
import pickle
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
|
||||
fname = "ZH_airshower/mysim.sry"
|
||||
dirname = '/scratch/etdeboone/reconstructions/'+ (sys.argv[2]+'/' if 2 in sys.argv else '')
|
||||
print("Dirname:", dirname)
|
||||
|
||||
####
|
||||
fname_dir = path.dirname(fname)
|
||||
max_clock_offset = None
|
||||
if True: # use the original files
|
||||
ev = REvent(fname)
|
||||
|
||||
max_clock_offset = int(sys.argv[1]) if len(sys.argv) > 1 else 5# ns
|
||||
# randomise timing for antenna copies
|
||||
seed = 12345
|
||||
rng = np.random.default_rng(seed)
|
||||
|
||||
dirname += f'rand{max_clock_offset}ns'
|
||||
else:
|
||||
raise NotImplementedError
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
|
||||
if not path.isfile(antennas_fname):
|
||||
print("Antenna file cannot be found, did you try generating a beacon?")
|
||||
sys.exit(1)
|
||||
|
||||
# Full reconstruction?
|
||||
if False:
|
||||
print("Full reconstruction")
|
||||
|
||||
if max_clock_offset:
|
||||
print(f"Randomising timing: {max_clock_offset}")
|
||||
clock_offsets = max_clock_offset * (2*rng.uniform(size=len(ev.antennas)) - 1)
|
||||
for i, ant in enumerate(ev.antennas):
|
||||
ev.antennas[i].t += clock_offsets[i]
|
||||
else:
|
||||
print(f"Not randomising timing")
|
||||
|
||||
with open(dirname + '/res.pkl', 'wb') as fp:
|
||||
res = rit.reconstruction(ev, outfile=dirname+'/fig.pdf', slice_outdir=dirname+'/', Xlow=100, N_X=23, Xhigh=1200)
|
||||
|
||||
pickle.dump(res, fp)
|
||||
sys.exit(0)
|
||||
|
||||
# Only a single slice
|
||||
else:
|
||||
print("Shower plane reconstruction")
|
||||
|
||||
# atm = AtmoCal()
|
||||
# X = 750
|
||||
# rit.set_pol_and_bp(ev)
|
||||
# dXref = atm.distance_to_slant_depth(np.deg2rad(ev.zenith),750,0)
|
||||
# scale2d = dXref*np.tan(np.deg2rad(2.))
|
||||
|
||||
if max_clock_offset is None:
|
||||
print(" + randomised timing")
|
||||
|
||||
ants_copy = deepcopy(ev.antennas)
|
||||
clock_offsets = max_clock_offset * (2*rng.uniform(size=len(ants_copy)) - 1)
|
||||
for i, ant in enumerate(ants_copy):
|
||||
ant.t -= clock_offsets[i]
|
||||
|
||||
fig, axs = plt.subplots(1,1+(max_clock_offset is not None), sharex=True, sharey=True)
|
||||
fig.suptitle(f"Reconstructed Shower plane slice at X={X}")
|
||||
if max_clock_offset is None:
|
||||
axs = [ax]
|
||||
for ax in axs:
|
||||
ax.set_xlabel("-v x B (m)")
|
||||
ax.set_ylabel(" vxvxB (m)")
|
||||
|
||||
if max_clock_offset is not None:
|
||||
axs[0].set_title("Simulated timing")
|
||||
axs[1].set_title(f"Randomised timing [0, {max_clock_offset}]")
|
||||
|
||||
try:
|
||||
for i, ax in enumerate(axs):
|
||||
# modify timing
|
||||
if i == 1:
|
||||
ev.antennas = ants_copy
|
||||
|
||||
xx,yy,p,km= rit.shower_plane_slice(ev,X,21,21,scale2d,scale2d)
|
||||
|
||||
if i == 0:
|
||||
vmax, vmin = max(p), min(p)
|
||||
|
||||
sc = ax.scatter(xx,yy,c=p, vmax=vmax, vmin=vmin)
|
||||
|
||||
# Plot centers
|
||||
im = np.argmax(p)
|
||||
|
||||
ax.plot(0, 0,'r+',ms=30)
|
||||
ax.plot(xx[im],yy[im],'bx',ms=30)
|
||||
|
||||
fig.colorbar(sc, ax=axs[0])
|
||||
# Always make sure to show the plot
|
||||
except:
|
||||
if True:
|
||||
fig.savefig(dirname + f"/shower_plane_slice_X{X}_T{max_clock_offset}_exception.pdf")
|
||||
plt.show()
|
||||
|
||||
if True:
|
||||
fig.savefig(dirname + f"/shower_plane_slice_X{X}_T{max_clock_offset}.pdf")
|
||||
|
||||
plt.show()
|
|
@ -1,32 +0,0 @@
|
|||
"""
|
||||
Some preconfigured ArgumentParser
|
||||
"""
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
def MyArgumentParser(
|
||||
default_fig_dir='./figures',
|
||||
default_show_plots=False,
|
||||
default_data_dir='./ZH_airshower',
|
||||
**kwargs):
|
||||
"""
|
||||
A somewhat preconfigured ArgumentParser to be shared across
|
||||
multiple scripts.
|
||||
|
||||
Set show_plots=True to by default enable showing plots.
|
||||
Likewise, set fig_dir=None to by default disable saving figures.
|
||||
"""
|
||||
parser = ArgumentParser(**kwargs)
|
||||
|
||||
# Whether to show plots
|
||||
group1 = parser.add_mutually_exclusive_group(required=False)
|
||||
group1.add_argument('--show-plots', action='store_true', default=default_show_plots, help='Default: %(default)s')
|
||||
group1.add_argument('--no-show-plots', dest='show-plots', action='store_false')
|
||||
|
||||
# Data directory
|
||||
parser.add_argument('--data-dir', type=str, default=default_data_dir, help='Path to Data Directory. (Default: %(default)s)')
|
||||
|
||||
# Figures directory
|
||||
parser.add_argument('--fig-dir', type=str, default=default_fig_dir, help='Set None to disable saving figures. (Default: %(default)s)')
|
||||
|
||||
return parser
|
|
@ -1,116 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: fdm=indent ts=4
|
||||
|
||||
__doc__ = \
|
||||
"""
|
||||
Show the beacon amplitude per antenna.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import h5py
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
import lib
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os.path as path
|
||||
|
||||
fname = "ZH_airshower/mysim.sry"
|
||||
|
||||
plot_phase_field = True
|
||||
plot_tx = False
|
||||
|
||||
####
|
||||
fname_dir = path.dirname(fname)
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
|
||||
f_beacon, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
|
||||
pretitle = ""
|
||||
if True:
|
||||
freq_name = list(antennas[0].beacon_info.keys())[0]
|
||||
beacon_frequencies = np.array([ant.beacon_info[freq_name]['freq'] for ant in antennas])
|
||||
beacon_amplitudes = np.array([ant.beacon_info[freq_name]['amplitude'] for ant in antennas])
|
||||
beacon_phases = lib.phase_mod(np.array([ant.beacon_info[freq_name]['beacon_phase'] for ant in antennas]))
|
||||
|
||||
if False and 'clock_phase' in antennas[0].beacon_info[freq_name]:
|
||||
beacon_clock_phases = lib.phase_mod(np.array([ant.beacon_info[freq_name]['clock_phase'] for ant in antennas]))
|
||||
else:
|
||||
subtitle = " Phases from t0"
|
||||
beacon_frequencies = np.array([ f_beacon for ant in antennas ])
|
||||
beacon_amplitudes = np.array([ 1 for ant in antennas ])
|
||||
beacon_phases = np.array([ lib.phase_mod(ant.attrs['t0']*beacon_frequencies[i]*2*np.pi) for i, ant in enumerate(antennas)])
|
||||
|
||||
#####
|
||||
sizes = 64
|
||||
if True:
|
||||
vals = beacon_phases
|
||||
colorlabel = '$\\varphi$'
|
||||
sizes = 64*(beacon_amplitudes/np.max(beacon_amplitudes))**2
|
||||
elif True: # True Phases
|
||||
vals = beacon_clock_phases
|
||||
colorlabel = '$\\sigma_\\varphi$'
|
||||
plot_phase_field = False
|
||||
plot_tx = False
|
||||
else:
|
||||
vals = beacon_amplitudes
|
||||
colorlabel = "[$\\mu$V/m]"
|
||||
|
||||
x = [ a.x for a in antennas ]
|
||||
y = [ a.y for a in antennas ]
|
||||
|
||||
#####
|
||||
|
||||
fig, axs = plt.subplots()
|
||||
axs.set_title(pretitle + f"Beacon frequency at A0: {beacon_frequencies[0]:.3e}GHz")
|
||||
axs.set_aspect('equal', 'datalim')
|
||||
axs.set_xlabel('[m]')
|
||||
axs.set_ylabel('[m]')
|
||||
|
||||
if True:
|
||||
vmax, vmin = None, None
|
||||
if plot_phase_field:
|
||||
# underlie a calculate phase field
|
||||
if True: # only fill for antennas
|
||||
xs = np.linspace( np.min(x), np.max(x), 4*np.ceil(len(antennas)**0.5) -1 )
|
||||
ys = np.linspace( np.min(y), np.max(y), 4*np.ceil(len(antennas)**0.5) -1)
|
||||
else: # make field from halfway the transmitter
|
||||
xs = np.linspace( (tx.x - np.min(x))/2, np.max(x), 500)
|
||||
ys = np.linspace( (tx.y - np.min(y))/2, np.max(y), 500)
|
||||
|
||||
phases, (xs, ys) = lib.phase_field_from_tx(xs, ys, tx, f_beacon*1e9,return_meshgrid=False)
|
||||
|
||||
vmax, vmin = max(np.max(phases), np.max(vals)), min(np.min(phases), np.min(vals))
|
||||
sc2 = axs.scatter(xs, ys, c=phases, alpha=0.5, zorder=-5, cmap='Spectral_r', vmin=vmin, vmax=vmax)
|
||||
|
||||
if False:
|
||||
# do not share the same colours
|
||||
fig.colorbar(sc2, ax=axs)
|
||||
vmax, vmin = None, None
|
||||
|
||||
sc = axs.scatter(x, y, c=vals, s=sizes, cmap='Spectral_r', edgecolors='k', marker='X', vmin=vmin, vmax=vmax)
|
||||
|
||||
if plot_tx:
|
||||
axs.plot(tx.x, tx.y, marker='X', color='k')
|
||||
|
||||
#for i, freq in enumerate(beacon_frequencies):
|
||||
# axs.text(f"{freq:.2e}", (x[i], y[i]))
|
||||
|
||||
fig.colorbar(sc, ax=axs, label=colorlabel)
|
||||
else:
|
||||
phases, (xs, ys) = lib.phase_field_from_tx(x, y, tx, f_beacon*1e9, return_meshgrid=False)
|
||||
|
||||
phase_diffs = vals - lib.phase_mod(phases)
|
||||
phase_diffs = lib.phase_mod(phase_diffs)
|
||||
|
||||
print(phases)
|
||||
|
||||
sc = axs.scatter(xs, ys, c=phase_diffs, s=sizes, cmap="Spectral_r")
|
||||
axs.plot(tx.x, tx.y, marker='X', color='k')
|
||||
|
||||
fig.colorbar(sc, ax=axs, label=colorlabel)
|
||||
|
||||
if not True:
|
||||
fig.savefig(__file__ + ".pdf")
|
||||
plt.show()
|
|
@ -1,184 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy.fft as ft
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
from view_orig_ant0 import plot_antenna_geometry
|
||||
import lib
|
||||
from earsim import Antenna
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from os import path
|
||||
import sys
|
||||
import matplotlib
|
||||
import os
|
||||
if os.name == 'posix' and "DISPLAY" not in os.environ:
|
||||
matplotlib.use('Agg')
|
||||
|
||||
from scriptlib import MyArgumentParser
|
||||
parser = MyArgumentParser()
|
||||
parser.add_argument('ant_idx', default=[72], nargs='*', type=int, help='Antenna Indices')
|
||||
parser.add_argument('-p', '--polarisations', choices=['x', 'y', 'z', 'b', 'AxB', 'n', 'b+n'], action='append', help='Default: x,y,z')
|
||||
parser.add_argument('--geom', action='store_true', help='Make a figure containg the geometry from tx to antenna(s)')
|
||||
parser.add_argument('--ft', action='store_true', help='Add FT strenghts of antenna traces')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
figsize = (12,8)
|
||||
|
||||
plot_ft_amplitude = args.ft
|
||||
plot_geometry = args.geom
|
||||
|
||||
fig_dir = args.fig_dir
|
||||
show_plots = args.show_plots
|
||||
|
||||
if not args.polarisations:
|
||||
args.polarisations = ['x','y', 'z']
|
||||
|
||||
####
|
||||
fname_dir = args.data_dir
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
tx_fname = path.join(fname_dir, beacon.tx_fname)
|
||||
|
||||
f_beacon, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
_, __, txdata = beacon.read_tx_file(tx_fname)
|
||||
beacon_amp = np.max(txdata['amplitudes'])# mu V/m
|
||||
|
||||
idx = args.ant_idx
|
||||
|
||||
if not idx:
|
||||
if not True:
|
||||
idx = [0, 1, len(antennas)//2, len(antennas)//2+1, -2, -1]
|
||||
elif not True:
|
||||
idx = np.arange(1, 20, 2, dtype=int)
|
||||
elif True:
|
||||
# center 6 antennas
|
||||
names = [55, 56, 57, 65, 66, 45, 46]
|
||||
|
||||
idx = [ i for i, ant in enumerate(antennas) if int(ant.name) in names ]
|
||||
|
||||
for i_fig in range(2):
|
||||
name_dist=''
|
||||
|
||||
if i_fig == 1: #read in the raw_traces
|
||||
_, __, antennas = beacon.read_beacon_hdf5(antennas_fname, traces_key='prefiltered_traces')
|
||||
name_dist='.raw'
|
||||
|
||||
|
||||
fig1, axs = plt.subplots(1+plot_ft_amplitude*1 +0*1, figsize=figsize)
|
||||
if not plot_ft_amplitude:
|
||||
axs = [axs]
|
||||
axs[0].set_xlabel('t [ns]')
|
||||
axs[0].set_ylabel('[$\mu$V/m]')
|
||||
|
||||
if i_fig == 1:
|
||||
axs[0].set_title("UnFiltered traces")
|
||||
else:
|
||||
axs[0].set_title("Filtered traces")
|
||||
|
||||
if True:
|
||||
axs[0].set_xlim(-250, 250)
|
||||
|
||||
if plot_ft_amplitude:
|
||||
axs[1].set_xlabel('f [GHz]')
|
||||
axs[1].set_ylabel('Power')
|
||||
|
||||
if len(axs) > 2:
|
||||
axs[2].set_ylabel("Phase")
|
||||
axs[2].set_xlabel('f [GHz]')
|
||||
axs[2].set_ylim(-np.pi,+np.pi)
|
||||
|
||||
colorlist = []
|
||||
for i in idx:
|
||||
ant = antennas[i]
|
||||
|
||||
n_samples = len(ant.t)
|
||||
samplerate = (ant.t[-1] - ant.t[0])/n_samples
|
||||
|
||||
axs[0].axvline(ant.t[0], color='k', alpha=0.5)
|
||||
|
||||
mydict = {}
|
||||
for p in args.polarisations:
|
||||
pattr = 'E'+str(p)
|
||||
if p == 'b':
|
||||
pattr = 'beacon'
|
||||
elif p == 'n':
|
||||
pattr = 'noise'
|
||||
elif p == 'AxB':
|
||||
pattr = 'E_AxB'
|
||||
elif p =='b+n':
|
||||
mydict[p] = getattr(ant,'noise') + beacon_amp*getattr(ant, 'beacon')
|
||||
continue
|
||||
|
||||
mydict[p] = getattr(ant, pattr)
|
||||
|
||||
if 'b' in mydict:
|
||||
mydict['b'] *= beacon_amp
|
||||
|
||||
for j, (direction, trace) in enumerate(mydict.items()):
|
||||
l = axs[0].plot(ant.t, trace, label=f"$E_{{{direction}}}$ {ant.name}", alpha=0.7)
|
||||
|
||||
#if False and j == 0 and 't0' in ant.attrs:
|
||||
# axs[0].axvline(ant.attrs['t0'], color=l[0].get_color(), alpha=0.5)
|
||||
|
||||
colorlist.append(l[0].get_color())
|
||||
|
||||
if not plot_ft_amplitude:
|
||||
continue
|
||||
|
||||
fft, freqs = lib.get_freq_spec(trace, 1/samplerate)
|
||||
|
||||
axs[1].plot(freqs, np.abs(fft)**2, color=l[0].get_color())
|
||||
|
||||
if True:
|
||||
cft = lib.direct_fourier_transform(f_beacon, ant.t, trace)
|
||||
amp = (cft[0]**2 + cft[1]**2)
|
||||
|
||||
#axs[0].axhline(amp, color=l[0].get_color())
|
||||
|
||||
print(amp)
|
||||
phase = np.arctan2(cft[0],cft[1])
|
||||
axs[1].plot(f_beacon, amp, color=l[0].get_color(), marker='3', alpha=0.8, ms=30)
|
||||
if len(axs) > 2:
|
||||
axs[2].plot(f_beacon, phase, color=l[0].get_color(), marker='3', alpha=0.8, ms=30)
|
||||
|
||||
if plot_ft_amplitude:
|
||||
fig1.legend(loc='center right', ncol=min(2, len(idx)))
|
||||
else:
|
||||
axs[0].legend(loc='upper right', ncol=min(3, len(idx)))
|
||||
|
||||
# Keep trace plot symmetric around 0
|
||||
max_lim = max(np.abs(axs[0].get_ylim()))
|
||||
axs[0].set_ylim(-max_lim, max_lim)
|
||||
|
||||
# Keep spectrum between 0 and 100 MHz
|
||||
if len(axs) > 1:
|
||||
xlims = axs[1].get_xlim()
|
||||
axs[1].set_xlim(max(0, xlims[0]), min(0.1, xlims[1]))
|
||||
if False: # extra zoom
|
||||
axs[1].set_xlim(f_beacon - 0.01, f_beacon + 0.01)
|
||||
|
||||
if fig_dir:
|
||||
fig1.savefig(path.join(fig_dir, path.basename(__file__) + f".trace{name_dist}.pdf"))
|
||||
|
||||
if plot_geometry:
|
||||
if len(mydict) == 1:
|
||||
geom_colorlist = colorlist
|
||||
else:
|
||||
# only take the colour belonging to mydict[0]
|
||||
geom_colorlist = [ colorlist[len(mydict)*(i)] for i in range(len(colorlist)//len(mydict)) ]
|
||||
|
||||
fig2, axs2 = plt.subplots(1, figsize=figsize)
|
||||
plot_antenna_geometry(antennas, ax=axs2, plot_max_values=False, color='grey', plot_names=False)
|
||||
plot_antenna_geometry([ antennas[i] for i in idx], ax=axs2, colors=geom_colorlist, plot_max_values=False)
|
||||
|
||||
axs2.plot(tx.x, tx.y, marker='X', color='k')
|
||||
axs2.set_title("Geometry with selected antennas")
|
||||
if fig_dir:
|
||||
fig2.savefig(path.join(fig_dir, path.basename(__file__) + f".geom.pdf"))
|
||||
|
||||
if show_plots:
|
||||
plt.show()
|
|
@ -1,98 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def plot_antenna_Efields(antenna, ax=None, plot_Ex=True, plot_Ey=True, plot_Ez=True, label_append="",**kwargs):
|
||||
"""Show waveforms from an antenna"""
|
||||
if ax is None:
|
||||
ax = plt.gca()
|
||||
|
||||
default_kwargs = dict(alpha=0.6)
|
||||
|
||||
kwargs = {**default_kwargs, **kwargs}
|
||||
|
||||
i = antenna.name
|
||||
|
||||
if plot_Ex:
|
||||
ax.plot(antenna.t, antenna.Ex, label=f"E{{x}}{label_append}".format(x='x', i=i), **kwargs)
|
||||
if plot_Ey:
|
||||
ax.plot(antenna.t, antenna.Ey, label=f"E{{x}}{label_append}".format(x='y', i=i), **kwargs)
|
||||
if plot_Ez:
|
||||
ax.plot(antenna.t, antenna.Ez, label=f"E{{x}}{label_append}".format(x='z', i=i), **kwargs)
|
||||
|
||||
ax.set_xlabel("[ns]")
|
||||
ax.set_ylabel("[$\mu$V/m]")
|
||||
ax.set_title("Antenna {i}".format(i=i))
|
||||
ax.legend()
|
||||
|
||||
return ax
|
||||
|
||||
def plot_antenna_geometry(antennas, ax=None, plot_names=True, plot_max_values=True, log_max=False, colors=None,**kwargs):
|
||||
"""Show the max values at each antenna."""
|
||||
default_kwargs = dict(
|
||||
cmap='Spectral_r'
|
||||
)
|
||||
|
||||
kwargs = {**default_kwargs, **kwargs}
|
||||
|
||||
x = [ a.x for a in antennas ]
|
||||
y = [ a.y for a in antennas ]
|
||||
|
||||
if ax is None:
|
||||
ax = plt.gca()
|
||||
|
||||
if plot_max_values:
|
||||
max_vals = np.asarray([ np.max([np.max(a.Ex), np.max(a.Ey), np.max(a.Ez)]) for a in antennas ])
|
||||
|
||||
if log_max:
|
||||
max_vals = np.log10(max_vals)
|
||||
|
||||
colors = max_vals
|
||||
|
||||
sc = ax.scatter(x, y, c=colors, **kwargs)
|
||||
|
||||
if plot_max_values:
|
||||
fig = ax.get_figure()
|
||||
fig.colorbar(sc, ax=ax, label="[$\mu$V/m]")
|
||||
|
||||
if plot_names:
|
||||
[ ax.annotate(a.name, (a.x, a.y), ha='center',va='center') for a in antennas ]
|
||||
|
||||
ax.set_title("Maximum E field at each antenna")
|
||||
ax.set_ylabel("[m]")
|
||||
ax.set_xlabel("[m]")
|
||||
|
||||
|
||||
return ax, sc
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os.path as path
|
||||
|
||||
from earsim import REvent
|
||||
|
||||
import aa_generate_beacon as beacon
|
||||
|
||||
fname = "ZH_airshower/mysim.sry"
|
||||
i = 0
|
||||
|
||||
if True:
|
||||
ev = REvent(fname)
|
||||
antennas = ev.antennas
|
||||
else:
|
||||
|
||||
fname_dir = path.dirname(fname)
|
||||
antennas_fname = path.join(fname_dir, beacon.antennas_fname)
|
||||
|
||||
f_beacon, tx, antennas = beacon.read_beacon_hdf5(antennas_fname)
|
||||
|
||||
if True:
|
||||
fig, ax1 = plt.subplots()
|
||||
plot_antenna_Efields(antennas[i], ax=ax1)
|
||||
|
||||
if True:
|
||||
fig2, ax2 = plt.subplots()
|
||||
plot_antenna_geometry(antennas, ax=ax2, plot_max_values=True, plot_names=False)
|
||||
ax2.set_aspect('equal', 'datalim')
|
||||
|
||||
plt.show()
|
Loading…
Add table
Add a link
Reference in a new issue