Skip to content

Instantly share code, notes, and snippets.

@zeyus
Created June 18, 2025 11:15
Show Gist options
  • Select an option

  • Save zeyus/cab8049b898e489b30566bd536779bde to your computer and use it in GitHub Desktop.

Select an option

Save zeyus/cab8049b898e489b30566bd536779bde to your computer and use it in GitHub Desktop.
FSR -> Photodiode latency data analysis
library("conflicted")
library("tidyverse")
# Define data sources with file paths and names
data_sources <- list(
list(
file_path = "timing_log_simplified_5091.csv",
name = "iPadM3Pro|Flutter|Comprehensive"
),
list(
file_path = "timing_log_simplified_9987.csv",
name = "iPadM3Pro|Swift|Basic"
),
list(
file_path = "timing_log_simplified_1542.csv",
name = "iPadM3Pro|Flutter|Basic"
),
list(
file_path = "timing_log_simplified_7802.csv",
name = "Pixel7a|Flutter|Comprehensive"
),
list(
file_path = "timing_log_simplified_3362.csv",
name = "Pixel7a|Flutter|Basic"
)
)
# example:
# frame_number,pin_number,pin_state,is_start_pin,trigger_active,pin_states
# 0,2,1,0,0,0;0;0;1
# 322577,0,1,1,1,1;0;0;1
# 324950,0,0,1,0,0;0;0;1
# 325307,1,1,0,0,0;0;1;1
# 327530,1,0,0,1,0;0;0;1
# 534245,0,1,1,1,1;0;0;1
# 537016,0,0,1,0,0;0;0;1
# 537362,1,1,0,0,0;0;1;1
# 539586,1,0,0,1,0;0;0;1
# 554218,0,1,1,1,1;0;0;1
# 557208,1,1,0,0,1;0;1;1
# 557309,0,0,1,0,0;0;1;1
# Function to find previous FSR event for each photodiode event
calculate_latencies <- function(fsr_events, photodiode_events) {
latencies <- numeric(nrow(photodiode_events))
for (i in 1:nrow(photodiode_events)) {
photo_frame <- photodiode_events$frame_number[i]
# Find the most recent FSR event before this photodiode event
previous_fsr <- fsr_events %>%
dplyr::filter(frame_number < photo_frame) %>%
slice_max(frame_number, n = 1)
if (nrow(previous_fsr) > 0) {
latencies[i] <- photo_frame - previous_fsr$frame_number
} else {
latencies[i] <- NA
}
}
return(latencies)
}
# Function to process a single data file
process_data_file <- function(file_path, data_name) {
cat("Processing:", data_name, "\n")
# Read the data
bela_data <- read_csv(file_path, show_col_types = FALSE)
# Filter FSR events (input events)
fsr_events <- bela_data %>%
dplyr::filter(pin_number == 0, is_start_pin == 1, trigger_active == 1) %>%
arrange(frame_number)
# Filter photodiode events (display events)
photodiode_events <- bela_data %>%
dplyr::filter(pin_number == 1, is_start_pin == 0, trigger_active == 1) %>%
arrange(frame_number)
# Calculate latencies in frames
latency_frames <- calculate_latencies(fsr_events, photodiode_events)
# Convert to milliseconds (44.1 kHz = 44100 samples per second)
sampling_rate <- 44100
latency_ms <- latency_frames / sampling_rate * 1000
# Remove NA values and create data frame
valid_latencies <- latency_ms[!is.na(latency_ms)]
if (length(valid_latencies) > 0) {
return(data.frame(
latency_ms = valid_latencies,
source = data_name
))
} else {
cat("Warning: No valid latencies found for", data_name, "\n")
return(data.frame(latency_ms = numeric(0), source = character(0)))
}
}
# Process all data files
all_latency_data <- map_dfr(data_sources, function(source) {
process_data_file(source$file_path, source$name)
})
summary_stats <- all_latency_data %>%
group_by(source) %>%
summarise(
n_events = n(),
mean_ms = round(mean(latency_ms), 2),
median_ms = round(median(latency_ms), 2),
min_ms = round(min(latency_ms), 2),
max_ms = round(max(latency_ms), 2),
sd_ms = round(sd(latency_ms), 2),
.groups = 'drop'
)
# order sources by lowest to highest mean latency
summary_stats <- summary_stats %>%
arrange(mean_ms)
# set the levels of the source factor to make sure that the lowest latency source is first
all_latency_data$source <- factor(all_latency_data$source, levels = summary_stats$source)
# Create side-by-side violin plot
latency_plot <- ggplot(all_latency_data, aes(x = source, y = latency_ms, fill = source)) +
geom_violin(alpha = 0.7) +
geom_boxplot(width = 0.2, fill = "white", alpha = 0.8) +
labs(
title = "Display Latency Distribution Comparison",
subtitle = "FSR to Photodiode Response Time",
x = "Data Source",
y = "Latency (ms)"
) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
legend.position = "none"
) +
scale_fill_viridis_d() +
scale_y_continuous(breaks = seq(0, max(all_latency_data$latency_ms, na.rm = TRUE), by = 5))
# Print summary statistics for each source
cat("\n=== LATENCY SUMMARY BY SOURCE ===\n")
print(summary_stats)
# Display the plot
print(latency_plot)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment