Skip to content

Instantly share code, notes, and snippets.

@anamariaelek
Created April 1, 2023 11:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anamariaelek/171b9a237ac97f42344ee78539b5c0a6 to your computer and use it in GitHub Desktop.
Save anamariaelek/171b9a237ac97f42344ee78539b5c0a6 to your computer and use it in GitHub Desktop.
Modify HR zone boundaries for existing Garmin activity (export .fit file from Garmin Connect and convert it to .csv file using fitcsvtool)
#!/usr/bin/env Rscript
library(data.table)
library(stringr)
# run example:
# Rscript --vanilla hr.R 99,119,139,158,178,198 ACTIVITY.csv
# params:
# new upper boundaries for HR zones
# it should be a vector of 6 integers separated by commas, e.g.
# "99,119,139,158,178,198"
# input csv file as exported by fitcsvtool,
# e.g. ACTIVITY.csv generated by:
# java -jar FitCSVTool.jar ACTIVITY.fit ACTIVITY.csv
# (optional) output filename, if not specified, it will use original file name
# with ".mod" suffix, e.g. ACTIVITY.mod.csv
# Returns the new csv file whch you can then convert to fit binary file
# using fitcsvtool, e.g.
# java -jar FitCSVTool.jar -c ACTIVITY.mod.csv ACTIVITY.mod.fit
# test if there is at least two arguments
args <- commandArgs(trailingOnly = TRUE)
if (length(args) < 2) {
stop(
"At least two arguments must be supplied:
upper HR zone boundaries and input csv file\n",
call. = FALSE
)
}
if (length(args) == 2) {
# default output file file
args[3] <- stringr::str_replace(args[1], ".csv", ".mod.csv")
}
hv <- args[1]
fn <- args[2]
fo <- args[3]
# import csv file
dt <- fread(fn, fill = TRUE)
# set new boundaries
hr_bounds_v <- as.integer(strsplit(hv, split = ",")[[1]])
hr_bounds <- paste(hv, collapse = "|")
dt[Type == "Data" & Message == "time_in_zone", `Value 5` := hr_bounds]
# get time stamps
ts <- dt[Type == "Data"][Message == "time_in_zone"]$`Value 1`
# update time in zones per timestamps
for (i in seq_along(ts)[-length(ts)]) {
message(i)
tst <- ts[i]
ten <- ts[i + 1]
x <- dt[Type == "Data"][Message == "record"][`Field 1` == "timestamp"][
`Value 1` >= tst & `Value 1` <= ten
]$`Value 1`
t <- as.integer(x[-1]) - as.integer(x[-length(x)])
h <- dt[Type == "Data"][Message == "record"][`Field 1` == "timestamp"][
`Value 1` >= tst & `Value 1` < ten
]$`Value 8`
z <- cut(h, c(0, hv, Inf))
s <- tapply(c(t, rep(1, pmax(0, length(z) - length(t)))), z, sum)
s[is.na(s)] <- 0
dt[Type == "Data" & Message == "time_in_zone" & `Value 1` == tst,
`Value 2` := paste(s, collapse = "|")
]
}
# uppdate total time in zones
zs <- dt[Type == "Data" & Message == "time_in_zone"]$`Value 2`
zm <- sapply(zs, function(x) {
sapply(strsplit(x, split = "\\|")[[1]], as.integer)
}, USE.NAMES = FALSE)
rownames(zm) <- NULL
zt <- paste(apply(zm, 1, sum), collapse = "|")
dt[Type == "Data" & Message == "time_in_zone" & `Value 1` == ts[length(ts)],
`Value 2` := paste(s, collapse = "|")
]
# save new csv file
fwrite(dt, fo, sep = ",", col.names = TRUE)
message("Done, saved file ", fo)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment