2022-09-26 17:18:07 +02:00
|
|
|
#!/usr/bin/env python3
|
2022-11-25 12:08:00 +01:00
|
|
|
# vim: fdm=marker ts=4
|
2022-11-14 20:49:35 +01:00
|
|
|
|
|
|
|
"""
|
|
|
|
Add a beacon measurement on top of the
|
|
|
|
simulated airshower.
|
|
|
|
"""
|
2022-09-26 17:18:07 +02:00
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
import json
|
|
|
|
import h5py
|
2022-09-28 13:21:41 +02:00
|
|
|
import os.path as path
|
2022-11-22 14:38:56 +01:00
|
|
|
from copy import deepcopy
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-11-22 09:40:58 +01:00
|
|
|
from earsim import REvent, Antenna, block_filter
|
2022-09-26 17:18:07 +02:00
|
|
|
import lib
|
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
# {{{ vim marker
|
2022-09-26 17:18:07 +02:00
|
|
|
tx_fname = 'tx.json'
|
2022-09-28 13:21:41 +02:00
|
|
|
antennas_fname = 'antennas.hdf5'
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
def write_tx_file(fname, tx, f_beacon, **kwargs):
|
2022-09-26 17:18:07 +02:00
|
|
|
with open(fname, 'w') as fp:
|
|
|
|
return json.dump(
|
2022-11-25 12:08:00 +01:00
|
|
|
{
|
|
|
|
**kwargs,
|
|
|
|
**dict(
|
|
|
|
f_beacon=f_beacon,
|
|
|
|
tx=dict(
|
|
|
|
x=tx.x,
|
|
|
|
y=tx.y,
|
|
|
|
z=tx.z,
|
|
|
|
name=tx.name
|
2022-09-26 17:18:07 +02:00
|
|
|
)
|
2022-11-25 12:08:00 +01:00
|
|
|
)
|
|
|
|
},
|
2022-09-26 17:18:07 +02:00
|
|
|
fp
|
2022-11-25 12:08:00 +01:00
|
|
|
)
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-09-28 13:21:41 +02:00
|
|
|
def read_tx_file(fname):
|
2022-09-26 17:18:07 +02:00
|
|
|
with open(fname, 'r') as fp:
|
|
|
|
data = json.load(fp)
|
|
|
|
|
|
|
|
f_beacon = data['f_beacon']
|
|
|
|
tx = Antenna(**data['tx'])
|
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
del data['f_beacon']
|
|
|
|
del data['tx']
|
|
|
|
|
|
|
|
return tx, f_beacon, data
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-11-22 11:06:15 +01:00
|
|
|
def read_beacon_hdf5(fname, **h5ant_kwargs):
|
2022-09-26 17:18:07 +02:00
|
|
|
with h5py.File(fname, 'r') as h5:
|
2022-11-22 11:06:15 +01:00
|
|
|
tx = Antenna_from_h5ant(h5['tx'], traces_key=None)
|
|
|
|
f_beacon = tx.attrs['f_beacon']
|
2022-09-28 13:21:41 +02:00
|
|
|
|
2022-09-26 17:18:07 +02:00
|
|
|
antennas = []
|
2022-11-22 09:40:58 +01:00
|
|
|
for k, h5ant in h5['antennas'].items():
|
2022-11-22 11:06:15 +01:00
|
|
|
ant = Antenna_from_h5ant(h5ant, **h5ant_kwargs)
|
2022-11-22 09:40:58 +01:00
|
|
|
|
|
|
|
antennas.append(ant)
|
2022-09-26 17:18:07 +02:00
|
|
|
|
|
|
|
return f_beacon, tx, antennas
|
|
|
|
|
2022-11-22 11:40:00 +01:00
|
|
|
def Antenna_from_h5ant(h5ant, traces_key='traces', raise_exception=True, read_AxB=True, read_beacon_info=True):
|
2022-11-22 11:06:15 +01:00
|
|
|
mydict = { k:h5ant.attrs.get(k) for k in ['x', 'y', 'z', 'name'] }
|
|
|
|
ant = Antenna(**mydict)
|
2022-11-22 11:40:00 +01:00
|
|
|
if h5ant.attrs:
|
|
|
|
ant.attrs = {**h5ant.attrs}
|
2022-11-22 11:06:15 +01:00
|
|
|
|
2022-11-22 11:40:00 +01:00
|
|
|
# Traces
|
2022-11-22 11:06:15 +01:00
|
|
|
if traces_key is None:
|
|
|
|
pass
|
|
|
|
elif traces_key not in h5ant:
|
|
|
|
if raise_exception:
|
|
|
|
raise ValueError("Traces_key not in file")
|
|
|
|
else:
|
2022-11-22 14:38:56 +01:00
|
|
|
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])
|
2022-11-22 11:06:15 +01:00
|
|
|
if len(h5ant[traces_key]) > 4:
|
2022-11-22 14:38:56 +01:00
|
|
|
ant.beacon = deepcopy(h5ant[traces_key][4])
|
2022-11-22 11:06:15 +01:00
|
|
|
|
2022-11-22 11:40:00 +01:00
|
|
|
# E_AxB
|
|
|
|
if read_AxB and 'E_AxB' in h5ant:
|
2022-11-22 14:38:56 +01:00
|
|
|
ant.t_AxB = deepcopy(h5ant['E_AxB'][0])
|
|
|
|
ant.E_AxB = deepcopy(h5ant['E_AxB'][1])
|
2022-11-22 11:06:15 +01:00
|
|
|
|
2022-11-22 11:40:00 +01:00
|
|
|
# Beacons
|
2022-11-22 14:38:56 +01:00
|
|
|
if read_beacon_info and 'beacon_info' in h5ant:
|
|
|
|
h5beacon = h5ant['beacon_info']
|
2022-11-22 11:40:00 +01:00
|
|
|
|
|
|
|
beacon_info = {}
|
|
|
|
for name in h5beacon.keys():
|
2022-11-22 14:38:56 +01:00
|
|
|
beacon_info[name] = dict(h5beacon[name].attrs)
|
2022-11-22 11:40:00 +01:00
|
|
|
|
|
|
|
ant.beacon_info = beacon_info
|
2022-11-22 11:06:15 +01:00
|
|
|
|
|
|
|
return ant
|
|
|
|
|
|
|
|
|
2022-09-28 13:21:41 +02:00
|
|
|
def init_antenna_hdf5(fname, tx = None, f_beacon = None):
|
2022-09-26 17:18:07 +02:00
|
|
|
with h5py.File(fname, 'w') as fp:
|
2022-09-28 13:21:41 +02:00
|
|
|
if tx is not None or f_beacon is not None:
|
|
|
|
tx_group = fp.create_group('tx')
|
|
|
|
tx_attrs = tx_group.attrs
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-09-28 13:21:41 +02:00
|
|
|
if f_beacon is not None:
|
|
|
|
tx_attrs['f_beacon'] = f_beacon
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-09-28 13:21:41 +02:00
|
|
|
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
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-09-28 13:21:41 +02:00
|
|
|
return fname
|
|
|
|
|
2022-11-18 11:02:41 +01:00
|
|
|
def append_antenna_hdf5(fname, antenna, columns = [], name='traces', prepend_time=True, overwrite=True, attrs_dict={}):
|
2022-09-28 15:54:11 +02:00
|
|
|
if not overwrite:
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2022-09-26 17:18:07 +02:00
|
|
|
with h5py.File(fname, 'a') as fp:
|
2022-09-28 15:54:11 +02:00
|
|
|
if 'antennas' in fp.keys():
|
|
|
|
if not overwrite:
|
|
|
|
raise NotImplementedError
|
2022-09-26 17:18:07 +02:00
|
|
|
group = fp['antennas']
|
2022-09-28 15:54:11 +02:00
|
|
|
else:
|
|
|
|
group = fp.create_group('antennas')
|
2022-09-26 17:18:07 +02:00
|
|
|
|
|
|
|
|
2022-09-28 15:54:11 +02:00
|
|
|
if antenna.name in group:
|
|
|
|
if not overwrite:
|
|
|
|
raise NotImplementedError
|
2022-11-22 11:14:53 +01:00
|
|
|
h5ant = group[antenna.name]
|
2022-09-28 15:54:11 +02:00
|
|
|
else:
|
2022-11-22 11:14:53 +01:00
|
|
|
h5ant = group.create_group(antenna.name)
|
2022-09-28 15:54:11 +02:00
|
|
|
|
2022-11-22 11:14:53 +01:00
|
|
|
h5ant_attrs = h5ant.attrs
|
|
|
|
h5ant_attrs['x'] = antenna.x
|
|
|
|
h5ant_attrs['y'] = antenna.y
|
|
|
|
h5ant_attrs['z'] = antenna.z
|
|
|
|
h5ant_attrs['name'] = antenna.name
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-11-18 11:02:41 +01:00
|
|
|
for k,v in attrs_dict.items():
|
2022-11-22 11:14:53 +01:00
|
|
|
h5ant_attrs[k] = v
|
2022-11-18 11:02:41 +01:00
|
|
|
|
2022-11-22 11:14:53 +01:00
|
|
|
if name in h5ant:
|
2022-09-28 15:54:11 +02:00
|
|
|
if not overwrite:
|
|
|
|
raise NotImplementedError
|
2022-11-22 11:14:53 +01:00
|
|
|
del h5ant[name]
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-11-22 11:14:53 +01:00
|
|
|
dset = h5ant.create_dataset(name, (len(columns) + 1*prepend_time, len(columns[0])), dtype='f')
|
2022-09-28 13:21:41 +02:00
|
|
|
|
2022-09-28 15:54:11 +02:00
|
|
|
if prepend_time:
|
|
|
|
dset[0] = antenna.t
|
2022-09-28 13:21:41 +02:00
|
|
|
|
2022-09-28 15:54:11 +02:00
|
|
|
for i, col in enumerate(columns, 1*prepend_time):
|
|
|
|
dset[i] = col
|
2022-11-22 11:06:15 +01:00
|
|
|
|
2022-11-23 16:53:33 +01:00
|
|
|
|
|
|
|
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]
|
|
|
|
|
2022-11-24 14:55:30 +01:00
|
|
|
names = group[base_dset_name][:].astype(str)
|
2022-11-23 16:53:33 +01:00
|
|
|
|
|
|
|
dset = group[dset_name]
|
2022-11-24 14:47:29 +01:00
|
|
|
time_diffs = dset[:,0]
|
|
|
|
f_beacon = dset[:,1]
|
|
|
|
true_phase_diffs = dset[:,2]
|
|
|
|
k_periods = dset[:,3]
|
2022-11-23 16:53:33 +01:00
|
|
|
|
2022-11-24 14:47:29 +01:00
|
|
|
return names, time_diffs, f_beacon, true_phase_diffs, k_periods
|
2022-11-23 16:53:33 +01:00
|
|
|
|
|
|
|
|
2022-11-24 14:47:29 +01:00
|
|
|
def write_baseline_time_diffs_hdf5(fname, baselines, true_phase_diffs, k_periods, f_beacon, time_diffs=None, overwrite=True):
|
2022-11-23 16:53:33 +01:00
|
|
|
"""
|
|
|
|
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]
|
|
|
|
true_phase_diffs = [true_phase_diffs]
|
|
|
|
k_periods = [k_periods]
|
2022-11-24 14:47:29 +01:00
|
|
|
f_beacon = np.array([f_beacon])
|
2022-11-23 16:53:33 +01:00
|
|
|
|
|
|
|
else:
|
|
|
|
N_baselines = len(baselines)
|
|
|
|
|
|
|
|
# Expand the f_beacon list
|
|
|
|
if not hasattr(f_beacon, '__len__'):
|
2022-11-24 14:47:29 +01:00
|
|
|
f_beacon = np.array([f_beacon]*N_baselines)
|
|
|
|
|
|
|
|
if time_diffs is None:
|
|
|
|
time_diffs = k_periods/f_beacon + true_phase_diffs/(2*np.pi*f_beacon)
|
2022-11-23 16:53:33 +01:00
|
|
|
|
|
|
|
assert len(baselines) == len(true_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)
|
|
|
|
|
2022-11-24 14:47:29 +01:00
|
|
|
data = np.vstack( (time_diffs, f_beacon, true_phase_diffs, k_periods) ).T
|
2022-11-23 16:53:33 +01:00
|
|
|
dset = group.create_dataset(dset_name, data=data)
|
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
# }}} vim marker
|
2022-11-23 16:53:33 +01:00
|
|
|
|
2022-09-26 17:18:07 +02:00
|
|
|
if __name__ == "__main__":
|
|
|
|
from os import path
|
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
fname = "ZH_airshower/mysim.sry"
|
|
|
|
|
|
|
|
# Transmitter
|
2022-11-14 20:49:35 +01:00
|
|
|
remake_tx = True
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
tx = Antenna(x=-2e3,y=0,z=0,name='tx') # m
|
|
|
|
if False:
|
|
|
|
# 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
|
|
|
|
|
|
|
|
# Beacon properties
|
|
|
|
if False: # slowest beacon to be found:
|
2022-11-22 15:57:00 +01:00
|
|
|
f_beacon = 10e-3 # GHz
|
|
|
|
low_bp = 5e-3 # GHz
|
|
|
|
high_bp = 80e-3 # GHz
|
|
|
|
else: # original wanted beacon
|
|
|
|
f_beacon = 51.53e-3 # GHz
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-11-22 15:57:00 +01:00
|
|
|
# Bandpass for E field blockfilter
|
|
|
|
low_bp = 30e-3 # GHz
|
|
|
|
high_bp = 80e-3 # GHz
|
|
|
|
|
2022-12-05 14:35:35 +01:00
|
|
|
beacon_amplitudes = 1e-6*np.array([1e3, 0, 0]) # mu V/m
|
2022-11-25 12:08:00 +01:00
|
|
|
beacon_radiate_rsq = True # beacon_amplitude is repaired for distance to 0,0,0
|
2022-11-14 20:49:35 +01:00
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
# modify beacon power to be beacon_amplitude at 0,0,0
|
2022-11-14 20:49:35 +01:00
|
|
|
if beacon_radiate_rsq:
|
|
|
|
dist = lib.distance(tx, Antenna(x=0, y=0, z=0))
|
|
|
|
|
2022-11-18 11:02:41 +01:00
|
|
|
ampl = max(1, dist**2)
|
2022-11-14 20:49:35 +01:00
|
|
|
|
|
|
|
beacon_amplitudes *= ampl
|
2022-09-28 15:54:11 +02:00
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
# Disable block_filter
|
|
|
|
if False:
|
|
|
|
block_filter = lambda x, dt, low, high: x
|
|
|
|
|
2022-09-26 17:18:07 +02:00
|
|
|
####
|
|
|
|
fname_dir = path.dirname(fname)
|
|
|
|
tx_fname = path.join(fname_dir, tx_fname)
|
2022-09-28 13:21:41 +02:00
|
|
|
antennas_fname = path.join(fname_dir, antennas_fname)
|
2022-09-26 17:18:07 +02:00
|
|
|
|
2022-11-25 12:08:00 +01:00
|
|
|
# read/write tx properties
|
2022-09-26 17:18:07 +02:00
|
|
|
if not path.isfile(tx_fname) or remake_tx:
|
2022-11-25 12:08:00 +01:00
|
|
|
write_tx_file(tx_fname, tx, f_beacon, amplitudes=beacon_amplitudes.tolist(), radiate_rsq=beacon_radiate_rsq)
|
2022-09-26 17:18:07 +02:00
|
|
|
else:
|
2022-11-25 12:08:00 +01:00
|
|
|
tx, f_beacon, _ = read_tx_file(tx_fname)
|
|
|
|
|
|
|
|
|
2022-11-25 12:17:08 +01:00
|
|
|
print("Beacon amplitude at tx [muV/m]:", beacon_amplitudes)
|
2022-11-25 12:08:00 +01:00
|
|
|
print("Tx location:", [tx.x, tx.y, tx.z])
|
2022-09-26 17:18:07 +02:00
|
|
|
|
|
|
|
# read in antennas
|
|
|
|
ev = REvent(fname)
|
|
|
|
N_antennas = len(ev.antennas)
|
|
|
|
|
2022-09-28 13:21:41 +02:00
|
|
|
# initialize hdf5 file
|
|
|
|
init_antenna_hdf5(antennas_fname, tx, f_beacon)
|
2022-09-26 17:18:07 +02:00
|
|
|
|
|
|
|
# make beacon per antenna
|
|
|
|
for i, antenna in enumerate(ev.antennas):
|
2022-12-05 14:35:35 +01:00
|
|
|
if False: # modify trace lengths
|
|
|
|
N_samples = len(antenna.t)
|
|
|
|
new_N = 2*N_samples
|
|
|
|
|
|
|
|
dt = antenna.t[1] - antenna.t[0]
|
|
|
|
new_t = np.arange(0, new_N)*dt + antenna.t[0]
|
|
|
|
|
|
|
|
antenna.t = new_t
|
|
|
|
|
|
|
|
# TODO:trace extrapolation?
|
|
|
|
antenna.Ex = np.pad(antenna.Ex, (0, new_N-N_samples), mode='constant', constant_values=0)
|
|
|
|
antenna.Ey = np.pad(antenna.Ey, (0, new_N-N_samples), mode='constant', constant_values=0)
|
|
|
|
antenna.Ez = np.pad(antenna.Ez, (0, new_N-N_samples), mode='constant', constant_values=0)
|
|
|
|
|
|
|
|
t0 = 0
|
|
|
|
c_light = 3e8*1e-9 # m/ns
|
2022-12-02 19:06:44 +01:00
|
|
|
if False:
|
2022-12-05 14:35:35 +01:00
|
|
|
# precalculate t0
|
|
|
|
# set c_light=np.inf to suppress the time delay
|
|
|
|
# in the function call
|
|
|
|
t0 = lib.distance(tx, antenna)/c_light
|
2022-12-02 19:06:44 +01:00
|
|
|
c_light = np.inf
|
2022-11-14 20:49:35 +01:00
|
|
|
|
2022-12-02 19:06:44 +01:00
|
|
|
beacon = lib.beacon_from(tx, antenna, f_beacon, antenna.t, t0=t0, c_light=c_light, radiate_rsq=beacon_radiate_rsq)
|
2022-11-22 14:38:56 +01:00
|
|
|
traces = np.array([antenna.Ex, antenna.Ey, antenna.Ez, beacon])
|
2022-09-28 13:21:41 +02:00
|
|
|
|
|
|
|
# add to relevant polarisation
|
2022-11-22 09:40:58 +01:00
|
|
|
# and apply block filter
|
|
|
|
dt = antenna.t[1] - antenna.t[0]
|
2022-11-22 15:57:00 +01:00
|
|
|
for j, amp in enumerate(beacon_amplitudes):
|
|
|
|
traces[j] = block_filter(traces[j] + amp*beacon, dt, low_bp, high_bp)
|
2022-09-28 13:21:41 +02:00
|
|
|
|
2022-11-22 14:38:56 +01:00
|
|
|
append_antenna_hdf5( antennas_fname, antenna, traces, name='traces', prepend_time=True, attrs_dict=dict(t0=t0))
|
2022-09-28 13:21:41 +02:00
|
|
|
|
2022-11-22 09:40:58 +01:00
|
|
|
# Save E field in E_AxB
|
2022-12-05 14:35:35 +01:00
|
|
|
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
|
2022-11-22 09:40:58 +01:00
|
|
|
|
2022-12-05 14:35:35 +01:00
|
|
|
append_antenna_hdf5( antennas_fname, antenna, [t_AxB, E_AxB], name='E_AxB', prepend_time=False)
|
2022-11-22 09:40:58 +01:00
|
|
|
|
2022-09-28 13:21:41 +02:00
|
|
|
print("Antenna HDF5 file written as " + str(antennas_fname))
|