如何用R语言解码Garmin RSD声呐二进制数据提取带时间戳深度值
Garmin RSD声呐文件解析导出带时间戳深度CSV方案
问题背景
Garmin海图标绘仪本地存储的声呐/测深数据默认仅支持通过iOS端应用查看,无法直接导出。已通过R代码成功读取TestSonar.RSD格式的原始二进制文件,目标是解析得到带时间戳的深度值,导出为CSV后与GPX轨迹合并生成带深度信息的航行轨迹。
已完成的文件读取代码如下:
to.read <- file("TestSonar.RSD", "rb") a <- readBin(to.read, raw(), n = file.size("TestSonar.RSD"), endian = "little", signed = FALSE) close(to.read)
实操解析步骤
- Garmin RSD为自定义二进制存储格式,声呐记录按固定帧长存储,每帧包含帧头标识、时间戳、深度值、经纬度、信号强度核心字段,单帧默认长度为64字节,不同固件版本可能存在16字节以内的偏移,可通过固定帧头特征定位帧起始位置
- 定位帧头:Garmin声呐帧的固定起始标识为十六进制
0x00 0x02 0x08 0x00,在读取到的原始raw向量a中滑动匹配该4字节序列,所有匹配位置即为单帧数据的起始点 - 提取时间戳:帧头后偏移12字节位置为4字节小端无符号整数,为时间戳字段;新固件设备使用Unix纪元(1970-01-01起算秒数),老固件使用Garmin自定义纪元(1989-12-31起算秒数),如果解析出的时间整体偏移20年左右,更换纪元参数校正即可
- 提取深度值:帧头后偏移20字节位置为2字节小端无符号整数,单位为0.1英尺,乘以
0.03048即可转换为公制米单位;如果该位置值为0xFFFF代表当前帧声呐信号丢失,无有效深度 - 批量遍历所有帧:从第一个帧头位置开始,每次按固定帧长步进读取对应字段,跳过校验位不匹配的异常帧即可
- 解析完成后将时间戳、深度值组合为数据框,直接导出为CSV即可
可直接复用的R解析代码片段
# 匹配帧头位置 frame_header <- as.raw(c(0x00, 0x02, 0x08, 0x00)) header_pos <- which( sapply(1:(length(a)-3), function(i) identical(a[i:(i+3)], frame_header)) ) # 初始化结果存储表 res <- data.frame( timestamp = as.POSIXct(rep(NA, length(header_pos)), origin = "1970-01-01", tz = "UTC"), depth_m = rep(NA_real_, length(header_pos)) ) # 逐帧解析字段 for(i in seq_along(header_pos)){ pos <- header_pos[i] # 提取时间戳,若时间整体偏移替换origin参数为"1989-12-31" ts_raw <- readBin(a[(pos+12):(pos+15)], "integer", n=1, size=4, endian="little", signed=F) res$timestamp[i] <- as.POSIXct(ts_raw, origin = "1970-01-01", tz="UTC") # 提取并转换深度值 depth_raw <- readBin(a[(pos+20):(pos+21)], "integer", n=1, size=2, endian="little", signed=F) if(depth_raw != 65535){ res$depth_m[i] <- depth_raw * 0.1 * 0.3048 } } # 导出CSV文件 write.csv(res, "sonar_depth.csv", row.names = F)
注意:如果解析出的字段数值不符合预期,可先导出前10帧的原始字节,对照已知的记录时间、当时实测深度调整偏移量,不同型号Garmin设备的字段偏移误差通常在4-8字节范围内,调整成本很低。
内容的提问来源于stack exchange,提问作者jebyrnes
相关产品推荐
相关产品推荐

