3.1 KaltoaClockSync

KaltoaClockSync objects hold correction values that can be used to synchronize receiver clocks within an array. Additionally, it can also hold receiver position corrections.

Below is a plot of our receiver array.

We can use the function SyncTagConnectivity to tally the number of sync-tag detections between receiver pairs.

# Show connectivity 
# (number of detections between receiver pairs)
sync_conn <- SyncTagConnectivity(exdata_clocksync)
sync_conn
## $connectivity_matrix
##     detect
## emit   1   2   3   4   5   6
##    1 NaN 118 117 117 112 110
##    2 123 NaN 118  95 114 119
##    3 114 107 NaN 110 111 111
##    4 114  78 110 NaN 113 113
##    5 111 106 109 111 NaN  95
##    6  52  89 133 131  15 NaN
## 
## $array_attributes
##   name emit_id        x       y depth
## 1    1   62041 481460.3 6243492    NA
## 2    2   62042 481435.5 6243491    NA
## 3    3   62074 481449.9 6243520    NA
## 4    4   62368 481464.2 6243554    NA
## 5    5   62581 481432.0 6243530    NA
## 6    6   62584 481472.0 6243509    NA
## 
## attr(,"class")
## [1] "SyncTagConnectivityMatrix" "list"
# Plot sync-tag connectivity
plot(sync_conn, type = "map")

plot(sync_conn, type = "matrix")

plot(sync_conn, type = "matrix", connectivity = T)

The "map" plot is useful for deciding on your best controller receiver. That is, the receiver which shares the most sync-tag emissions/detections with all other receivers.

The "matrix" plot is great for identifying weak links in your sync_order. If one receiver has poor connectivity with your controller, it might be a good idea to add a second controller that has better connectivity to that receiver.

Next, we’ll need to specify a data.frame providing the order for the pairwise clock drift corrections, sync_order. You can string together calls of the sync_pair function to create a correctly formatted sync_order object.

# Create a data.frame holding the order of paired clock synchronizations
sync_order <-  
  sync_pair(
    controller = "3",
    target = c("1", "2", "4", "5")) +
  sync_pair(
    controller = "4", target = "6")
sync_order
##   controller target direction_a direction_b
## 1          3      1        TRUE        TRUE
## 2          3      2        TRUE        TRUE
## 3          3      4        TRUE        TRUE
## 4          3      5        TRUE        TRUE
## 5          4      6        TRUE        TRUE

Here, receiver 3 will synchronize the rest of the array except for receiver 6. Next, receiver 4 will be used as a controller to synchronize the remaining receiver 6.

For larger arrays, you can make use of the fill_sync_order function. Here, you simply specify a sync_order that only contains potential controller receivers. fill_sync_order will then attach the remaining receivers to the best connected controller from your sync _order.

# An (convoluted) example of how to specify many controllers
sync_order_alt <- 
  sync_pair(controller = "1", target = "3") +
  sync_pair(controller = "3", target = "6") |> 
  fill_sync_order(detlst = exdata_clocksync)
sync_order_alt
##   controller target direction_a direction_b
## 1          1      3        TRUE        TRUE
## 2          3      6        TRUE        TRUE
## 3          3      1        TRUE        TRUE
## 4          3      2        TRUE        TRUE
## 5          3      5        TRUE        TRUE
## 6          6      4        TRUE        TRUE

Note that you can specify which sync-tag transmissions are used for drift corrections between receiver pairs. Typically you want to use transmissions in both directions, utilizing both sync-tags in a receiver pair.

Take your time on setting up the sync_order table and make use of plot(sync_conn, type = "matrix") to verify your choices. Receivers pairs with poor sync-tag connectivity will result in bad drift corrections. If possible, it is best to have 1 single well connected receiver acting as a controller for the entire array. We’ve added a second controller above just for the sake of an example.

plot(sync_conn, type = "matrix", sync_order = sync_order)

We’ll calculate drift corrections on an hourly basis by setting appropriate clock times.

# Make a vector of times to calculate clock drift corrections for.
clock_times <- seq(
  as.POSIXct("2021-05-08 18:00:00", tz = "CET"),
  as.POSIXct("2021-05-09 06:00:00", tz = "CET"), by = 3600)
clock_times
##  [1] "2021-05-08 18:00:00 CEST" "2021-05-08 19:00:00 CEST"
##  [3] "2021-05-08 20:00:00 CEST" "2021-05-08 21:00:00 CEST"
##  [5] "2021-05-08 22:00:00 CEST" "2021-05-08 23:00:00 CEST"
##  [7] "2021-05-09 00:00:00 CEST" "2021-05-09 01:00:00 CEST"
##  [9] "2021-05-09 02:00:00 CEST" "2021-05-09 03:00:00 CEST"
## [11] "2021-05-09 04:00:00 CEST" "2021-05-09 05:00:00 CEST"
## [13] "2021-05-09 06:00:00 CEST"

Next, we’ll create the KaltoaClockSync model. This holds our parameters for clock synchronization.

To handle reflected transmissions we can use the parameter phi. A value of phi = 0.33 means that we’re expecting reflected transmissions may be detected up to 0.33 seconds later than their direct-transmission counterparts. This tells our clock-synchronization models to not be surprised if large positive outliers appear in the data set.

# Transmission are assumed to travel no farther than 500 meters.
# We can use this to set phi (maximum added latency from a reflected 
# transmission)
phi <- 500 / 1500

# Initialize model
sync_model <- KaltoaClockSync(
  sync_order = sync_order, 
  phi = phi,
  clock_times = clock_times,
  detlst = exdata_clocksync)
print(sync_model)
## KaltoaClockSync Object
## 
##  --- Parameters
## Detection error phi: 0.3 s
## Detection error beta: 32.0
## Detection-emission grouping threshold: 0.5 s
## Transmission speed: 1500.0 m s⁻¹
## 
## 13 clock times ranging: 2021-05-08 18:00:00 -- 2021-05-09 06:00:00 (CET)
## 
##  --- Clock drift ranges
## 3 ⟷ 1:   0.0000 s -- 0.0000   s
## 3 ⟷ 2:   0.0000 s -- 0.0000   s
## 3 ⟷ 4:   0.0000 s -- 0.0000   s
## 3 ⟷ 5:   0.0000 s -- 0.0000   s
## 4 ⟷ 6:   0.0000 s -- 0.0000   s
## 
##  --- Clock offsets
## 1:  0.0000 s
## 2:  0.0000 s
## 3:  0.0000 s
## 4:  0.0000 s
## 5:  0.0000 s
## 6:  0.0000 s
## 
##  --- Position offsets
## 1:  0.0 m, 0.0  m
## 2:  0.0 m, 0.0  m
## 3:  0.0 m, 0.0  m
## 4:  0.0 m, 0.0  m
## 5:  0.0 m, 0.0  m
## 6:  0.0 m, 0.0  m

The next sections will deal with using our sync-tag data to estimate the appropriate drift and offset values for this object.