2022-11-14 20:49:35 +01:00
#!/usr/bin/env python3
# vim: fdm=indent ts=4
2022-11-22 11:14:53 +01:00
"""
Find beacon phases in antenna traces
And save these to a file
"""
2022-11-14 20:49:35 +01:00
import h5py
2022-11-18 16:27:20 +01:00
import matplotlib . pyplot as plt
import numpy as np
2022-11-14 20:49:35 +01:00
import aa_generate_beacon as beacon
2022-11-18 16:27:20 +01:00
import lib
2023-02-20 15:17:56 +01:00
from lib import figlib
2022-11-14 20:49:35 +01:00
if __name__ == " __main__ " :
from os import path
import sys
2022-12-05 17:48:58 +01:00
import matplotlib
2022-12-08 14:41:33 +01:00
import os
if os . name == ' posix ' and " DISPLAY " not in os . environ :
matplotlib . use ( ' Agg ' )
2022-11-18 19:31:24 +01:00
2023-01-12 14:31:21 +01:00
from scriptlib import MyArgumentParser
parser = MyArgumentParser ( )
2023-02-03 11:56:11 +01:00
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 ) ' )
2023-01-12 14:31:21 +01:00
args = parser . parse_args ( )
2022-11-14 20:49:35 +01:00
f_beacon_band = ( 49e-3 , 55e-3 ) #GHz
2022-11-18 19:31:24 +01:00
allow_frequency_fitting = False
2022-11-14 20:49:35 +01:00
read_frequency_from_file = True
2023-02-03 11:56:11 +01:00
N_mask = int ( args . N_mask )
2022-11-14 20:49:35 +01:00
2023-02-03 11:56:11 +01:00
use_only_AxB_trace = args . use_AxB_trace
use_only_beacon_trace = args . use_beacon_trace # only applicable if AxB = False
2022-11-24 14:48:01 +01:00
2023-01-12 14:31:21 +01:00
show_plots = args . show_plots
2022-11-18 19:31:24 +01:00
2023-02-02 08:57:03 +01:00
figsize = ( 12 , 8 )
2022-11-14 20:49:35 +01:00
2023-02-03 11:56:11 +01:00
print ( " use_only_AxB_trace: " , use_only_AxB_trace , " use_only_beacon_trace: " , use_only_beacon_trace )
2022-12-02 19:06:44 +01:00
2022-11-14 20:49:35 +01:00
####
2023-02-02 17:55:37 +01:00
fname_dir = args . data_dir
2022-11-14 20:49:35 +01:00
antennas_fname = path . join ( fname_dir , beacon . antennas_fname )
2023-04-13 15:04:45 +02:00
beacon_snr_fname = path . join ( fname_dir , beacon . beacon_snr_fname )
2022-11-14 20:49:35 +01:00
2023-01-12 14:49:54 +01:00
fig_dir = args . fig_dir # set None to disable saving
2022-12-05 17:48:58 +01:00
2022-11-14 20:49:35 +01:00
if not path . isfile ( antennas_fname ) :
print ( " Antenna file cannot be found, did you try generating a beacon? " )
sys . exit ( 1 )
2023-04-13 15:04:45 +02:00
beacon_snrs = beacon . read_snr_file ( beacon_snr_fname )
2023-04-28 17:14:49 +02:00
snr_str = f " $ \\ langle SNR \\ rangle$ = { beacon_snrs [ ' mean ' ] : .1g } "
2023-04-12 22:42:59 +02:00
2022-11-14 20:49:35 +01:00
# 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
2023-02-20 15:17:56 +01:00
found_data = np . zeros ( ( N_antennas , 3 ) ) # freq, phase, amp
noise_data = np . zeros ( ( N_antennas , 2 ) ) # phase, amp
2022-11-14 20:49:35 +01:00
# Determine frequency and phase
for i , name in enumerate ( group . keys ( ) ) :
2022-11-22 11:14:53 +01:00
h5ant = group [ name ]
2022-11-14 20:49:35 +01:00
2022-11-22 10:22:23 +01:00
# use E_AxB only instead of polarisations
2023-02-03 11:56:11 +01:00
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 } " )
2022-11-22 10:22:23 +01:00
sys . exit ( 1 )
2022-11-14 20:49:35 +01:00
2023-02-03 11:56:11 +01:00
traces = h5ant [ traces_key ]
2022-11-22 10:22:23 +01:00
t_trace = traces [ 0 ]
test_traces = [ traces [ 1 ] ]
orients = [ ' E_AxB ' ]
2022-11-18 19:31:24 +01:00
2023-02-03 11:56:11 +01:00
# 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 )
2022-12-08 12:02:48 +01:00
2023-02-03 11:56:11 +01:00
traces = h5ant [ traces_key ]
t_trace = traces [ 0 ]
test_traces = [ traces [ 4 ] ]
orients = [ ' B ' ]
2022-12-08 12:02:48 +01:00
2022-11-22 10:22:23 +01:00
# use separate polarisations
else :
2023-02-03 11:56:11 +01:00
traces_key = ' filtered_traces '
if traces_key not in h5ant . keys ( ) :
print ( f " Antenna file corrupted? no ' { traces_key } ' in { name } " )
2022-11-22 10:22:23 +01:00
sys . exit ( 1 )
2023-02-03 11:56:11 +01:00
traces = h5ant [ traces_key ]
2022-11-22 10:22:23 +01:00
t_trace = traces [ 0 ]
2023-02-03 11:56:11 +01:00
test_traces = [ traces [ i ] for i in range ( 1 , 4 ) ]
orients = [ ' Ex ' , ' Ey ' , ' Ez ' ]
2022-11-22 10:22:23 +01:00
2023-02-03 11:56:11 +01:00
# Really only select the first component
2023-02-03 14:37:20 +01:00
if True :
2023-02-03 11:56:11 +01:00
test_traces = [ test_traces [ 0 ] ]
orients = [ orients [ 0 ] ]
2022-11-22 10:22:23 +01:00
2023-02-03 11:56:11 +01:00
# TODO: refine masking
# use beacon but remove where E_AxB-Beacon != 0
# Uses the first traces as reference
2023-02-20 15:17:56 +01:00
t_mask = 0
2023-02-03 11:56:11 +01:00
if N_mask and orients [ 0 ] != ' B ' :
N_pre , N_post = N_mask / / 2 , N_mask / / 2
2022-11-22 10:22:23 +01:00
2023-02-03 11:56:11 +01:00
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 '
2022-11-25 11:31:19 +01:00
2022-11-22 10:22:23 +01:00
# Do Fourier Transforms
# to find phases and amplitudes
2022-11-18 19:31:24 +01:00
if True :
2023-01-17 18:17:12 +01:00
freqs , beacon_phases , amps = lib . find_beacon_in_traces (
2022-11-18 19:31:24 +01:00
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 ]
2022-11-22 11:14:53 +01:00
t0 = h5ant . attrs [ ' t0 ' ]
2022-11-18 19:31:24 +01:00
2023-01-17 18:17:12 +01:00
beacon_phases = [ 2 * np . pi * t0 * f_beacon ]
2022-11-18 19:31:24 +01:00
amps = [ 3e-7 ]
2022-11-14 20:49:35 +01:00
2023-02-20 15:17:56 +01:00
# 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
2022-11-18 19:31:24 +01:00
# choose highest amp
2023-02-03 11:56:11 +01:00
idx = np . argmax ( amps )
2023-01-17 18:17:12 +01:00
if False and len ( beacon_phases ) > 1 :
2022-11-22 10:22:23 +01:00
#idx = np.argmax(amplitudes, axis=-1)
raise NotImplementedError
2022-11-14 20:49:35 +01:00
2022-11-18 19:31:24 +01:00
frequency = freqs [ idx ]
2023-01-17 18:17:12 +01:00
beacon_phase = beacon_phases [ idx ]
2022-11-18 19:31:24 +01:00
amplitude = amps [ idx ]
orientation = orients [ idx ]
2022-11-14 20:49:35 +01:00
2022-12-12 19:52:34 +01:00
# 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
2023-01-17 18:17:12 +01:00
beacon_phase = lib . phase_mod ( beacon_phase + corr_phase )
2022-12-12 19:52:34 +01:00
2022-11-22 11:40:00 +01:00
# for reporting using plots
2023-01-17 18:17:12 +01:00
found_data [ i ] = frequency , beacon_phase , amplitude
2022-11-22 11:40:00 +01:00
2023-02-03 12:00:32 +01:00
if ( show_plots or fig_dir ) and ( i == 0 or i == 72 ) :
2022-12-12 19:52:34 +01:00
p2t = lambda phase : phase / ( 2 * np . pi * f_beacon )
2023-02-01 14:13:26 +01:00
fig , ax = plt . subplots ( figsize = figsize )
2023-04-28 17:14:49 +02:00
ax . set_title ( f " Beacon at antenna { h5ant . attrs [ ' name ' ] } \n F: { frequency : .2g } GHz, $ \\ varphi$: { beacon_phase : .4f } rad " )
2022-11-25 11:31:19 +01:00
ax . set_xlabel ( " t [ns] " )
ax . set_ylabel ( " Amplitude " )
2022-11-18 19:31:24 +01:00
2022-12-12 19:52:34 +01:00
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
2023-01-17 18:17:12 +01:00
ax . plot ( myt , lib . sine_beacon ( frequency , myt , amplitude = amplitude , t0 = 0 , phase = beacon_phase + extra_phase ) , ls = ' dotted ' , label = ' simulated beacon ' )
2022-12-12 19:52:34 +01:00
2023-01-17 18:17:12 +01:00
ax . axvline ( p2t ( lib . phase_mod ( - 1 * ( beacon_phase + extra_phase ) , low = 0 ) ) , color = ' r ' , ls = ' dashed ' , label = ' $t_ \\ varphi$ ' )
2022-12-02 19:06:44 +01:00
2022-12-12 19:52:34 +01:00
ax . axvline ( 0 , color = ' grey ' , alpha = 0.5 )
ax . axhline ( 0 , color = ' grey ' , alpha = 0.5 )
2022-12-02 19:06:44 +01:00
2023-04-12 22:42:59 +02:00
ax . legend ( title = snr_str )
2022-11-14 20:49:35 +01:00
2022-12-05 17:48:58 +01:00
if fig_dir :
2022-12-12 19:52:34 +01:00
old_xlims = ax . get_xlim ( )
ax . set_xlim ( min ( t_trace ) - t_0 - 10 , min ( t_trace ) - t_0 + 40 )
2023-01-04 11:05:20 +01:00
fig . savefig ( path . join ( fig_dir , path . basename ( __file__ ) + f " .A { h5ant . attrs [ ' name ' ] } .zoomed.pdf " ) )
2022-12-12 19:52:34 +01:00
ax . set_xlim ( * old_xlims )
2023-01-04 11:05:20 +01:00
fig . savefig ( path . join ( fig_dir , path . basename ( __file__ ) + f " .A { h5ant . attrs [ ' name ' ] } .pdf " ) )
2022-12-05 17:48:58 +01:00
2022-11-22 11:40:00 +01:00
# save to file
2022-11-22 14:38:56 +01:00
h5beacon_info = h5ant . require_group ( ' beacon_info ' )
2022-11-14 20:49:35 +01:00
2022-11-22 11:40:00 +01:00
# only take n_sig significant digits into account
# for naming in hdf5 file
2022-11-22 14:38:56 +01:00
n_sig = 3
2022-11-22 11:40:00 +01:00
decimal = int ( np . floor ( np . log10 ( abs ( frequency ) ) ) )
freq_name = str ( np . around ( frequency , n_sig - decimal ) )
# delete previous values
2022-11-22 14:38:56 +01:00
if freq_name in h5beacon_info :
del h5beacon_info [ freq_name ]
2022-11-22 11:40:00 +01:00
2022-11-22 14:38:56 +01:00
h5beacon_freq_info = h5beacon_info . create_group ( freq_name )
2022-11-22 11:40:00 +01:00
2022-11-22 14:38:56 +01:00
h5attrs = h5beacon_freq_info . attrs
2022-11-22 11:40:00 +01:00
h5attrs [ ' freq ' ] = frequency
2023-01-17 18:17:12 +01:00
h5attrs [ ' beacon_phase ' ] = beacon_phase
2022-11-22 11:40:00 +01:00
h5attrs [ ' amplitude ' ] = amplitude
h5attrs [ ' orientation ' ] = orientation
2022-11-14 20:49:35 +01:00
2023-02-20 15:17:56 +01:00
if noise_phase :
h5attrs [ ' noise_phase ' ] = noise_phase
h5attrs [ ' noise_amp ' ] = noise_amp
2022-11-18 19:31:24 +01:00
print ( " Beacon Phases, Amplitudes and Frequencies written to " , antennas_fname )
2022-11-14 20:49:35 +01:00
# show histogram of found frequencies
2022-12-05 17:48:58 +01:00
if show_plots or fig_dir :
2023-02-20 15:17:56 +01:00
2022-11-14 20:49:35 +01:00
if True or allow_frequency_fitting :
2023-02-01 14:13:26 +01:00
fig , ax = plt . subplots ( figsize = figsize )
2022-11-14 20:49:35 +01:00
ax . set_xlabel ( " Frequency " )
ax . set_ylabel ( " Counts " )
2022-11-18 19:31:24 +01:00
ax . axvline ( f_beacon , ls = ' dashed ' , color = ' g ' )
ax . hist ( found_data [ : , 0 ] , bins = ' sqrt ' , density = False )
2023-04-12 22:42:59 +02:00
ax . legend ( title = snr_str )
2022-12-05 17:48:58 +01:00
if fig_dir :
2023-01-04 11:05:20 +01:00
fig . savefig ( path . join ( fig_dir , path . basename ( __file__ ) + f " .hist_freq.pdf " ) )
2022-11-14 20:49:35 +01:00
if True :
2023-04-12 22:42:59 +02:00
fig , _ = figlib . fitted_histogram_figure ( found_data [ : , 2 ] , fit_distr = [ ' rice ' ] )
2023-02-20 15:17:56 +01:00
ax = fig . axes [ 0 ]
ax . set_xlabel ( " Amplitude " )
2022-11-14 20:49:35 +01:00
ax . set_ylabel ( " Counts " )
2022-11-18 19:31:24 +01:00
ax . hist ( found_data [ : , 2 ] , bins = ' sqrt ' , density = False )
2023-04-12 22:42:59 +02:00
ax . legend ( title = snr_str )
2022-12-05 17:48:58 +01:00
if fig_dir :
2023-01-04 11:05:20 +01:00
fig . savefig ( path . join ( fig_dir , path . basename ( __file__ ) + f " .hist_amp.pdf " ) )
2022-11-14 20:49:35 +01:00
2023-02-20 15:17:56 +01:00
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 )
2023-04-12 22:42:59 +02:00
ax . legend ( title = snr_str )
2023-02-20 15:17:56 +01:00
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 :
2023-04-12 22:42:59 +02:00
fig , _ = figlib . fitted_histogram_figure ( noise_data [ : , 1 ] , fit_distr = [ ' rice ' , ' rayleigh ' ] )
2023-02-20 15:17:56 +01:00
ax = fig . axes [ 0 ]
ax . set_title ( " Noise Amplitudes " )
ax . set_xlabel ( " Amplitude [a.u.] " )
ax . set_ylabel ( " # " )
2023-04-12 22:42:59 +02:00
ax . legend ( title = snr_str )
2023-02-20 15:17:56 +01:00
if fig_dir :
fig . savefig ( path . join ( fig_dir , path . basename ( __file__ ) + f " .noise.hist_amp.pdf " ) )
2022-12-05 17:48:58 +01:00
if show_plots :
plt . show ( )