Global Trigger. More...
#include <GlobalTrigger.h>
Public Member Functions | |
GlobalTrigger (Settings *settings1, Anita *anita1) | |
void | GetArrivalTimes (int inu, Anita *anita1, const Vector &rf_direction) |
void | PassesTrigger (Settings *settings1, Anita *anita1, int discones_passing, int mode, int *l3trig, int l2trig[Anita::NPOL][Anita::NTRIGGERLAYERS_MAX], int l1trig[Anita::NPOL][Anita::NTRIGGERLAYERS_MAX], int antennaclump, int loctrig[Anita::NPOL][Anita::NLAYERS_MAX][Anita::NPHI_MAX], int loctrig_nadironly[Anita::NPOL][Anita::NPHI_MAX], int inu, int *thispasses, bool noiseOnly=false) |
Evaluate the full trigger simulation for a given payload configuration. More... | |
void | PassesTrigger (Settings *settings1, Anita *anita1, int discones_passing, int mode, int *l3trig, int l2trig[Anita::NPOL][Anita::NTRIGGERLAYERS_MAX], int l1trig[Anita::NPOL][Anita::NTRIGGERLAYERS_MAX], int antennaclump, int loctrig[Anita::NPOL][Anita::NLAYERS_MAX][Anita::NPHI_MAX], int loctrig_nadironly[Anita::NPOL][Anita::NPHI_MAX], int inu, double this_threshold, int *thispasses, bool noiseOnly=false) |
void | PassesTriggerBasic (Settings *settings1, Anita *anita1, int discones_passing, int mode, int *l3trig, int l2trig[Anita::NPOL][Anita::NTRIGGERLAYERS_MAX], int l1trig[Anita::NPOL][Anita::NTRIGGERLAYERS_MAX], int antennaclump, int loctrig[Anita::NPOL][Anita::NLAYERS_MAX][Anita::NPHI_MAX], int loctrig_nadironly[Anita::NPOL][Anita::NPHI_MAX], int *thispasses, int inu, bool noiseOnly=false) |
void | PassesTriggerCoherentSum (Settings *settings1, Anita *anita1, int inu, int *thispasses) |
void | PassesTriggerSummedPower (Settings *settings1, Anita *anita1) |
void | PassesTriggerScheme5 (Anita *anita1, double this_threshold, int *thispasses) |
void | L3Trigger (Settings *settings1, Anita *anita1, int loctrig[Anita::NPOL][Anita::NLAYERS_MAX][Anita::NPHI_MAX], int loctrig_nadironly[Anita::NPOL][Anita::NPHI_MAX], int discones_passing, int *l3trigy, int *thispasses) |
Level 3 Trigger Function. More... | |
int | GetPhiSector (Settings *settings1, int i, int j) |
Provides a mapping between the 4 layers and 16 phi sectors physically to the 3 layers and 16 sectors logically. More... | |
void | GetAnitaLayerPhiSector (Settings *settings1, int i, int j, int &whichlayer, int &whichphisector) |
Provides a mapping between the 4 layers and 16 phi sectors physically to the 3 layers and 16 sectors logically. More... | |
void | FillInNadir (Anita *anita1, int *ant) |
Virtual nadir antennas had effective L2 triggers based on neighbor antennas. More... | |
void | FillInNadir (Settings *settings1, Anita *anita1, int ant) |
Virtual nadir antennas had effective L2 triggers based on neighbor antennas. More... | |
double | three_bit_round (double input, bool round_zero_up=true, bool allow_zero=false) |
Three bit rounding function. More... | |
void | convert_wfm_to_3_bit (const vector< double > &wfm, double rms, vector< double > &output) |
Converts a waveform by sampling it into 3 bits, after it is normalized to the RMS. | |
void | delay_align_antenna_waveforms (const vector< vector< vector< double > > > &waveforms, const vector< vector< unsigned int > > &delays, vector< vector< double > > &output) |
Calculate the difference in each arrival time due to propagation delay of the signal. More... | |
void | sum_aligned_waveforms (const vector< vector< double > > &waveforms, vector< double > &output) |
Given a number of waveforms (usually 3) which are delay-aligned, it sums them. More... | |
void | square_waveform_elements (const vector< double > &waveform, vector< double > &output) |
Performs an element-wise squaring of the values of the input array. More... | |
double | summed_power_window (const vector< double > &waveform, unsigned int start_index, unsigned int length) |
Sum a window from the specified starting index. More... | |
int | findahit (vector< int > myvector, int first, int last) |
int | findanl3 (int *l3, int NPHISECTORS) |
int | L1Anita3_OnePhiSector (int IZERO, vector< int > &vl0_realtime_bottom, vector< int > &vl0_realtime_middle, vector< int > &vl0_realtime_top, vector< int > &vl1_realtime_bottom, vector< int > &vl1_realtime_middle, vector< int > &vl1_realtime_top) |
void | L1Anita3_AllPhiSectors (Anita *anita1, std::array< std::array< std::vector< int >, 16 >, 2 > &l1trig) |
int | L1Anita4_OnePhiSector (int IZERO, vector< int > &vl0_realtime_bottom, vector< int > &vl0_realtime_middle, vector< int > &vl0_realtime_top, vector< int > &vl1_realtime_bottom, vector< int > &vl1_realtime_middle, vector< int > &vl1_realtime_top) |
void | L1Anita4_AllPhiSectors (Anita *anita1, std::array< std::array< std::vector< int >, 16 >, 2 > &l1trig) |
void | L2Anita3and4 (Anita *anita1, std::array< std::array< std::vector< int >, 16 >, 2 > l1trig, std::array< std::array< std::vector< int >, 16 >, 2 > &l2trig) |
void | L3Anita3and4 (Anita *anita1, std::array< std::array< std::vector< int >, 16 >, 2 > vl2trig, int vl3trig[2][16], int *thispasses) |
int | PartofL1Anita4LR_ScA_TwoPhiSectors (int ilayerreverse, int IZERO, int ipolar, vector< int > &v1l0_realtime_left, vector< int > &v2l0_realtime_left, vector< int > &v1l0_realtime_right, vector< int > &v2l0_realtime_right, vector< int > &vl1_realtime) |
int | L1Anita4LR_ScA_TwoPhiSectors (int IZERO, int ipolar, vector< int > &vl0_realtime_bottomleft, vector< int > &v2l0_realtime_bottomleft, vector< int > &vl0_realtime_bottomright, vector< int > &v2l0_realtime_bottomright, vector< int > &vl0_realtime_middleleft, vector< int > &v2l0_realtime_middleleft, vector< int > &vl0_realtime_middleright, vector< int > &v2l0_realtime_middleright, vector< int > &vl0_realtime_topleft, vector< int > &v2l0_realtime_topleft, vector< int > &vl0_realtime_topright, vector< int > &v2l0_realtime_topright, vector< int > &vl1_realtime_bottom, vector< int > &vl1_realtime_middle, vector< int > &vl1_realtime_top) |
void | L1Anita4LR_ScA_AllPhiSectors (Anita *anita1, std::array< std::array< std::vector< int >, 16 >, 2 > &vl1trig) |
void | L3Anita4LR_ScA (Anita *anita1, std::array< std::array< std::vector< int >, 16 >, 2 > vl2trig, int *thispasses) |
void | L1Anita4LR_ScB_AllAntennas_OneBin (int IZERO, Anita *anita1, std::array< std::array< vector< int >, 16 >, 3 > &vl1trig_anita4lr_scb, int &npassesl1) |
void | L1Anita4LR_ScB_OneBin (int IZERO, vector< int > vleft, vector< int > vright, vector< int > &vl1trig) |
void | L2Anita4LR_ScB_AllPhiSectors_OneBin (int IZERO, Anita *anita1, std::array< std::array< vector< int >, 16 >, 3 > vl1trig_anita4lr_scb, std::array< std::array< vector< int >, 3 >, 16 > &vl2_realtime_anita4_scb, int &npassesl2, int &npassesl2_type0) |
void | L2Anita4LR_ScB_OnePhiSector_OneBin (int IZERO, vector< int > vl1_bottom, vector< int > vl1_middle, vector< int > vl1_top, std::array< vector< int >, 3 > &vl2_realtime_anita4_scb, int &npassesl2, int &npassesl2_type0) |
int | L3or30Anita4LR_ScB_TwoPhiSectors_OneBin (int IZERO, std::array< vector< int >, 3 > vl2_realtime_anita4_scb, std::array< vector< int >, 3 > vl2_realtime_anita4_scb_other, int npass1, int npass2) |
void | L3Anita4LR_ScB_OneBin (int IZERO, Anita *anita1, std::array< std::array< vector< int >, 3 >, 16 > vl2_realtime_anita4_scb, std::array< vector< int >, 16 > &vl3trig_type0, std::array< vector< int >, 16 > &vl3trig_type1, int &thispasses_l3type0, int &thispasses_l3type1) |
void | delayL0 (vector< int > &vl0, double delay) |
void | delay_AllAntennas (Anita *anita1) |
Public Attributes | |
double | TRIGTIMESTEP |
int | nstepback |
double | L1_COINCIDENCE_ANITA3 [3] |
double | LASTTIMETOTESTL1_ANITA3 |
double | L3_COINCIDENCE |
double | L1_COINCIDENCE_MOREGENERAL [3][2] |
double | LASTTIMETOTESTL1_ANITA4 |
double | LASTTIMETOTESTL1_ANITA4LR_SCA |
double | L1_COINCIDENCE_LR_SCA [2] |
double | WHICHLAYERSLCPRCP [Anita::NTRIGGERLAYERS_MAX] |
double | L1_COINCIDENCE_ANITA4LR_SCB |
double | LASTTIMETOTESTL1_ANITA4LR_SCB |
double | L2_COINCIDENCE_ANITA4LR_SCB [3] |
double | LASTTIMETOTESTL2_ANITA4LR_SCB |
double | L3_COINCIDENCE_ANITA4LR_SCB |
double | DELAYS [3] |
vector< int > | flag_e_L1 [Anita::NPHI_MAX] |
vector< int > | flag_h_L1 [Anita::NPHI_MAX] |
UShort_t | phiTrigMask [Anita::NPOL] |
UShort_t | l1TrigMask [Anita::NPOL] |
UShort_t | thresholds_eachant [2][48] |
double | volts [2][Anita::NLAYERS_MAX][Anita::NPHI_MAX] |
double | volts_em [2][Anita::NLAYERS_MAX][Anita::NPHI_MAX] |
double | volts_original [2][Anita::NLAYERS_MAX][Anita::NPHI_MAX] |
int | nchannels_perrx_triggered [48] |
int | nchannels_perband_triggered [48][8] |
int | channels_passing [Anita::NLAYERS_MAX][Anita::NPHI_MAX][2][Anita::NBANDS_MAX] |
int | channels_passing_justNoise [Anita::NLAYERS_MAX][Anita::NPHI_MAX][2][Anita::NBANDS_MAX] |
vector< int > | vchannels_passing [Anita::NLAYERS_MAX][Anita::NPHI_MAX][2] |
std::array< std::array< std::array< std::array< std::vector< int >, 5 >, 2 >, 16 >, 3 > | arrayofhits |
std::array< std::array< std::array< std::array< std::vector< int >, 5 >, 2 >, 16 >, 3 > | arrayofhitsnoise |
std::array< std::array< std::array< std::array< std::vector< int >, 5 >, 2 >, 16 >, 3 > | arrayofhitsall |
int | triggerbits [Anita::NTRIG] |
vector< vector< vector< double > > > | volts_rx_rfcm_trigger |
int | first_phi_sector_hit |
Global Trigger.
Definition at line 12 of file GlobalTrigger.h.
void GlobalTrigger::delay_align_antenna_waveforms | ( | const vector< vector< vector< double > > > & | waveforms, |
const vector< vector< unsigned int > > & | delays, | ||
vector< vector< double > > & | output | ||
) |
Calculate the difference in each arrival time due to propagation delay of the signal.
Method void GetArrivalTimes: input: direction of rf propagation when it arrives at balloon (earth frame), balloon location (earth frame) rotation of balloon around axis of symmetry
output: array of doubles giving time at which rf reaches antenna feedpoint, where the first antenna is hit at t=0.
This method takes as input the rf direction, the location of the balloon, the phi spin of the balloon, and an array of vectors initialized to point to the location of the antennas, assuming the balloon is upright at the south pole, with no spin.
The method transforms the antenna location vectors to point from the current center of the balloon (actually the center of the top ring of antennas) to the antennas, assuming that the balloon is vertical over the surface of the ice, and taking into account a possible phi spin.
The method projects the antenna direction vector onto the rf direction to find the distance between the center of the balloon and each antenna, along the direction of rf propagation.
Finally, arrival times are shifted so that the first antenna triggered is at time 0.Shifts waveforms in time to simulate relative signal delays caused by propagation
This function accepts nested vectors of waveforms along with nested vectors of delays and then iterates through nested for-loops whose bounds iterate with the surrounding scope.
The output is assembled and then truncated to prevent uneven array lengths post-shifting.
Something to keep in mind is that RVO (Return Value Optimization) can make it actually faster to return a large object by value if it can be used to immediately construct another object. Also, instead of worrying about resizing the arrays it'd probably be better to store the time index of the last signal bin, and then simply pass that bin as the end iterator offset for the truncated array. The use of vector<>::push_back may cause performance issues but more importantly the use of clear() and element-by-element assignment causes more concern than they're worth, so they should be replaced with std::copy() for the temporaries which need it and just use functions from the standard library's #include <algorithm>. Realistically though, the delays should just be used to advance the iterators.
Definition at line 1713 of file GlobalTrigger.cc.
void GlobalTrigger::FillInNadir | ( | Anita * | anita1, |
int * | ant | ||
) |
Virtual nadir antennas had effective L2 triggers based on neighbor antennas.
the nadir layer only has 8 antennas but there are 16 slots in the "trigger layer" ant[][] is 1 if the l1 trigger is fired for each antenna fill the slots in between the actual antennas with the "or" of the neighboring antennas
Definition at line 1395 of file GlobalTrigger.cc.
Virtual nadir antennas had effective L2 triggers based on neighbor antennas.
the nadir layer only has 8 antennas but there are 16 slots in the "trigger layer" ant[][] is 1 if the l1 trigger is fired for each antenna fill the slots in between the actual antennas with the "or" of the neighboring antennas
Definition at line 1352 of file GlobalTrigger.cc.
void GlobalTrigger::GetAnitaLayerPhiSector | ( | Settings * | settings1, |
int | i, | ||
int | j, | ||
int & | whichlayer, | ||
int & | whichphisector | ||
) |
Provides a mapping between the 4 layers and 16 phi sectors physically to the 3 layers and 16 sectors logically.
Because every payload had a different number of antennas, this provides a relation from where the antennas were located physically and how they were considered to by positioned logically by the triggering system.
Definition at line 1457 of file GlobalTrigger.cc.
int GlobalTrigger::GetPhiSector | ( | Settings * | settings1, |
int | i, | ||
int | j | ||
) |
Provides a mapping between the 4 layers and 16 phi sectors physically to the 3 layers and 16 sectors logically.
Because the top two layers of antennas had only 8 antennas each and were rotated perfectly out of phase of one another, such a conversion was needed to keep the trigger sane.
Definition at line 1426 of file GlobalTrigger.cc.
void GlobalTrigger::L3Trigger | ( | Settings * | settings1, |
Anita * | anita1, | ||
int | loctrig[Anita::NPOL][Anita::NLAYERS_MAX][Anita::NPHI_MAX], | ||
int | loctrig_nadironly[Anita::NPOL][Anita::NPHI_MAX], | ||
int | discones_passing, | ||
int * | l3trig, | ||
int * | thispasses | ||
) |
Level 3 Trigger Function.
Given a trigger scheme (represented via the Settings::WHICH value), the results of the previous trigger (the L2 trigger) are compared against one of the various combinatoric triggers.
For Anita 2, the trigger required two layers out of the three L2 triggers in a phi sector, but for sectors which did not have a nadir antennas, these "phantom nadirs" were a boolean "OR" of the two nadir antennas closest to that phi sector. Finally, two neighboring phi sectors must have accomplished this in order to produce a triggered L3.
Along this topic, the values for settings should be either strings, values mapped to strings (such as boost::variable_map), or enumerations with a proper descriptive declared name. That way when settings1->WHICH would have a value of 9, it would be written settings1->WHICH==ANITA3. Lastly, the boolean functions which are chained together to represent the full state machine of the trigger electronics are an impossible-to-find bug waiting to happen. "Short circuit evaluation" and less-than-obvious operator fixity rules make the given representation one of the most difficult to manage. The use of standard library functions "all_of", "any_of", "none_of", "count", and "count_if" on an intelligent container like boost::multi_array or PayloadArray would make the expression of the trigger requirements much more clear and less prone to error. Finally, all modern compilers will automatically optimize power-of-two multiplication of integers into a bit shift, so nothing is lost by switching from explicit shifts to multiplication, and readability is gained.
Definition at line 1540 of file GlobalTrigger.cc.
void GlobalTrigger::PassesTrigger | ( | Settings * | settings1, |
Anita * | anita1, | ||
int | discones_passing, | ||
int | mode, | ||
int * | l3trig, | ||
int | l2trig[Anita::NPOL][Anita::NTRIGGERLAYERS_MAX], | ||
int | l1trig[Anita::NPOL][Anita::NTRIGGERLAYERS_MAX], | ||
int | antennaclump, | ||
int | loctrig[Anita::NPOL][Anita::NLAYERS_MAX][Anita::NPHI_MAX], | ||
int | loctrig_nadironly[Anita::NPOL][Anita::NPHI_MAX], | ||
int | inu, | ||
int * | thispasses, | ||
bool | noiseOnly = false |
||
) |
Evaluate the full trigger simulation for a given payload configuration.
PassesTrigger handles the logistics for the triggering of all trigger systems.
The triggering system begins with the calculations to determine which channels will pass the "L0" trigger. Each antenna on Anita 2 had two polarizations, and each polarization was divided up into five frequency bands. The frequency bands would be independently measured to see if the signal was over the threshold. If 3 of the 8 bands for an antenna (in some experiments, at least) exceeded the threshold then that antenna would have triggered an "L1", or antenna-level trigger.
From there, the different triggering systems start to diverge, each requiring some different combinatoric trigger to be satisfied before escalating to the next-higher-level trigger.
The trigger system using TRIGGERSCHEME==3 is a good deal different from the other triggers, because of a few thing:
The antenna trigger clusters have been different configurations in the past, with early Anita3 designs using the "Coherent Sum Trigger", which uses 9 antennas per cluster. More current trigger designs use 3 antennas per coherent-summing-group, though this more recent trigger is referred to as the "Summed Power Trigger"
The longer a function gets, the less confidence can be had in it because instead of many small, well-tested modular functions, functions of this length develop into massive hacks which may appear to perform the same but no such guarantee can be made. There are a lot of functions and code snippets which could be very easily replaced by standard library functions, or by embracing "RAII" ("Resource Acquisition Is Initialization") and using fewer C arrays and more of the standard library functions (particularly those in "algorithm", "functional", and "numeric" and above all the container libraries. Those libraries will help (along with the refactor) alleviate the difficult-to-follow nesting of for-loops within conditional statements. Many of the combinatoric triggers can have a logical mask made in order to very clearly define and later comprehend the requirements of the triggers, and less nesting of loops is necessary. Using scoped accumulators for calculating statistics is also a good idea here, as it reduces the number of functions and the number of objects needed to produce a distribution of values to just one object, making mistakes/errors much less likely. * There is a decent amount of dead code which should be pruned, as well.
Definition at line 211 of file GlobalTrigger.cc.
void GlobalTrigger::square_waveform_elements | ( | const vector< double > & | waveform, |
vector< double > & | output | ||
) |
Performs an element-wise squaring of the values of the input array.
std::transform(wfm.begin(), wfm.end(), result.begin(), [](auto& x){x *= x}); or by using the boost library: result = boost::transform(wfm, [](auto& x){x *= x});
Definition at line 1778 of file GlobalTrigger.cc.
void GlobalTrigger::sum_aligned_waveforms | ( | const vector< vector< double > > & | waveforms, |
vector< double > & | output | ||
) |
Given a number of waveforms (usually 3) which are delay-aligned, it sums them.
Definition at line 1750 of file GlobalTrigger.cc.
double GlobalTrigger::summed_power_window | ( | const vector< double > & | waveform, |
unsigned int | start_index, | ||
unsigned int | length | ||
) |
Sum a window from the specified starting index.
double sum = std::accumulate(wfm.begin(), wfm.end(), 0.);
Definition at line 1795 of file GlobalTrigger.cc.
double GlobalTrigger::three_bit_round | ( | double | input, |
bool | round_zero_up = true , |
||
bool | allow_zero = false |
||
) |
Three bit rounding function.
This function takes an input and digitizes it into one of 8 (2^3 == 8) intervals, with unit spacing from -3.5 to +3.5.
This function takes a number and will round it to the closest integer multiple plus 0.5, using randomness to get distribute exact integers.
Definition at line 1812 of file GlobalTrigger.cc.