基于16位硬件时间戳的溢出处理及连续时间向量生成优化
解决16位时间戳溢出问题,生成连续时间向量
我用的硬件输出16位时间戳,最低有效位是50微秒,单量程约3.25秒。现在要把这些时间戳转成量程更大的连续时间向量,但处理溢出时总觉得现有代码不够严谨,而且我是Swift新手,对字节级操作不太熟。
现有代码的问题
当前实现逻辑绕,硬写了魔法数字,还有强制解包的风险,容易出问题:
let timeVectorRaw: [UInt16] = <time values> // First timestamp will not necessarily be zero, so need to record the value of the first entry which will be subtracted later so the time vector starts at zero timeOffsetInt = Int(timeVectorRaw[0]) // Last timestamp (Uint16) (not scaled/no offset) var lastRawValue: UInt16 = 0 var lastWholeNumberValue: Int = 0 for timeValue in timeVectorRaw { // if time vector is empty or if timestamp hasn't overflowed yet, no adjustment necessary if timeVectorWrapped.isEmpty || timeVectorWrapped.last! < timeValue { timeVectorWrapped.append(Int(timeValue)) } else if timeValue < lastRawValue { // Essentially floor(last time value / Uint16 max value) lastWholeNumberValue = timeVectorWrapped.last! + 65536 - ((timeVectorWrapped.last!) % 65536) timeVectorWrapped.append(Int(timeValue) + lastWholeNumberValue) } else { timeVectorWrapped.append(Int(timeValue) + lastWholeNumberValue) } lastRawValue = timeValue } for timeValueWrap in timeVectorWrapped { // subtract offset and multiply by scale factor (50us/lsb) timeVector.append(Float((timeValueWrap - timeOffsetInt)) * 0.000050) }
优化后的实现
用溢出计数的方式处理更直观,代码也更严谨,适合Swift新手理解:
// 定义常量,避免魔法数字,提升可读性 let microsecondsPerLSB: Double = 50 let uInt16Range = Int(UInt16.max) + 1 // 65536,UInt16的总取值数 let timeVectorRaw: [UInt16] = <time values> var timeVector: [Double] = [] // 处理空数组的边界情况,避免崩溃 guard !timeVectorRaw.isEmpty else { print("时间戳数组为空") return } // 基准偏移量,让时间向量从0开始 let baseOffset = Int(timeVectorRaw[0]) var overflowCount = 0 var previousRawValue = timeVectorRaw[0] // 遍历计算包裹后的时间值 var wrappedTimes: [Int] = [baseOffset] for currentRaw in timeVectorRaw.dropFirst() { // 判断是否溢出:当前值比上一个小,说明翻过了UInt16的最大值 if currentRaw < previousRawValue { overflowCount += 1 } // 计算实际的累计时间值 let wrappedTime = Int(currentRaw) + overflowCount * uInt16Range wrappedTimes.append(wrappedTime) // 更新上一个值 previousRawValue = currentRaw } // 转换为实际时间(秒),并减去基准偏移量 timeVector = wrappedTimes.map { wrappedTime in let relativeTicks = wrappedTime - baseOffset return Double(relativeTicks) * microsecondsPerLSB / 1_000_000 }
关键逻辑说明
- 溢出判断:当当前时间戳
currentRaw小于上一个值previousRawValue,说明硬件的16位计数器从65535溢出回0了,此时溢出计数加1。 - 包裹时间计算:每次溢出相当于额外增加了一个完整的UInt16量程(65536个刻度),所以实际时间值是当前刻度值加上
溢出次数 × 65536。 - 时间转换:减去基准偏移量让时间从0开始,再把刻度数转成秒(50微秒/刻度 = 50×10^-6秒/刻度)。
- 安全处理:用
guard判断空数组,避免强制解包,代码更稳健。
内容的提问来源于stack exchange,提问作者awk_leg
相关产品推荐
相关产品推荐

