Correct TOF timing for using local clock

Assuming that the BunchCrossingNumber is something that resets with the start of each fill, here's some pseudocode:
double BunchCrossingRolloverTime = pow(2,32) / RHIC_clock_frequency;

// We need to be careful with getting the bunch crossing number correct near
// the 2^32 rollover of BunchCrossingNumber. If we're within +/-10% of the time
// to start a new cycle, determine whether we really have a new cycle by whether
// BunchCrossingNumber is low or high.
double BunchCrossingCycleGuess = (Event_unix_time - FillStartTime) / BunchCrossingRolloverTime;
double BunchCrossingCycleNearestInt = round(BunchCrossingCycleGuess);
int LowerBunchCrossingCycleGuess = floor(BunchCrossingCycleGuess);
int UpperBunchCrossingCycleGuess = LowerBunchCrossingCycleGuess;
if (BunchCrossingCycleNearestInt > BunchCrossingCycleGuess && BunchCrossingCycleNearestInt - BunchCrossingCycleGuess < 0.1)
  UpperBunchCrossingCycleGuess++;
else if (BunchCrossingCycleNearestInt < BunchCrossingCycleGuess && BunchCrossingCycleGuess - BunchCrossingCycleNearestInt < 0.1)
  LowerBunchCrossingCycleGuess--;
// else we are confident about the cycle number from using floor()
long long BunchCrossingCycle = (BunchCrossingNumber > (2U << 30) ?
                                LowerBunchCrossingCycleGuess     :
                                UpperBunchCrossingCycleGuess     );

long long FullBunchCrossingNumber = (BunchCrossingCycle << 32) + ((long long) BunchCrossingNumber);

double one_Local_clock_tick = 1.0 / Local_clock_frequency;
double one_RHIC_clock_tick = 1.0 / RHIC_clock_frequency;
double time_drift_per_BunchCrossing = fmod(one_RHIC_clock_tick - one_Local_clock_tick, one_Local_clock_tick);

double event_offset = fmod((time_drift_per_BunchCrossing * FullBunchCrossingNumber) + phase, one_Local_clock_tick);
if (event_offset > event_offset_max) event_offset -= one_Local_clock_tick;
We can obtain something to use as a FillStartTime for each fill from some database or even some data files, I'm sure. I can help with this. It is important that it's within about a half minute of the start of a cycle for BunchCrossingNumber so that we properly determine rollovers to new cycles, which means it isn't fully degenerate with the phase parameter. It isn't critical that we get it at the start of the true first cycle of a fill, though getting it reasonably close prevents potential computation errors from unnecessarily using large numbers too.

The calibration pass just needs to determine phase for each fill, constrained to be in the range [0,one_Local_clock_tick). And I'm guessing that a single value of event_offset_max, which is also in the range [0,one_Local_clock_tick), can be determined and assigned for the entire dataset as this is a function of the electronics.

The other parameters are all known.



Simple example with a local clock slightly faster than the RHIC clock:

RHIC clock frequency = 1.0 Hz
Local clock frequency = 1.25 Hz

So the Local clock ticks are at 0.0, 0.8, 1.6, 2.4, 3.2, 4.0 seconds, while the RHIC clock ticks are at 0.0, 1.0, 2.0, 3.0, 4.0 seconds and is when the events are (potentially) actually recorded.



At event 0, the time measured from the Local clock will be off by 0.0 seconds
At event 1, the time measured from the Local clock will be off by 0.2 seconds.
At event 2, the time measured from the Local clock will be off by 0.4 seconds.
At event 3, the time measured from the Local clock will be off by 0.6 seconds, or -0.2 seconds depending on which clock tick is referenced.
At event 4, the time measured from the Local clock will be off by 0.0 seconds.

So the drift in measured time between events is 0.2 seconds. This is the time difference between the RHIC clock ticks and the Local clock ticks: fmod((1.0/1.0 Hz) - (1.0/1.25 Hz), (1.0/1.25 Hz)) = fmod(1.0 - 0.8, 0.8) = fmod(0.2,0.8) = 0.2 seconds.

The offset will rollover every time it grows by 0.8 seconds, which is the value of the Local clock tick: (1.0/1.25 Hz) = 0.8 seconds.

The maximum event offset could be somewhere in the 0.5-0.7 second range and would determine whether we use an offset of 0.6 seconds or -0.2 seconds at event 3.


Simple example with a local clock much faster than the RHIC clock:

RHIC clock frequency = 1.0 Hz
Local clock frequency = 6.66667 Hz

So the Local clock ticks are at 0.00, 0.15, 0.30, 0.45, 0.60, 0.75, 0.90, 1.05, 1.20, etc. seconds, while the RHIC clock ticks are at 0.0, 1.0, 2.0, 3.0, 4.0 seconds and is when the events are (potentially) actually recorded.



At event 0, the time measured from the Local clock will be off by 0.00 seconds.
At event 1, the time measured from the Local clock will be off by 0.10 seconds, or -0.05 seconds depending on which clock tick is referenced.
At event 2, the time measured from the Local clock will be off by 0.05 seconds.
At event 3, the time measured from the Local clock will be off by 0.00 seconds
At event 4, the time measured from the Local clock will be off by 0.10 seconds, or -0.05 seconds depending on which clock tick is referenced.

So the drift in measured time between events is 0.10 seconds. This is the time difference between the RHIC clock ticks and the Local clock ticks: fmod((1.0/1.0 Hz) - (1.0/6.66667 Hz), (1.0/6.66667 Hz)) = fmod(1.0 - 0.15, 0.15) = fmod(0.85, 0.15) = 0.10 seconds.

The offset will rollover every time it grows by 0.15 seconds, which is the value of the Local clock tick: (1.0/6.66667 Hz) = 0.15 seconds.

The maximum event offset could be somewhere in the 0.07-0.14 second range and would determine whether we use an offset of 0.10 seconds or -0.05 seconds at events 1 and 4.


-Gene