chronaxis.core.rate_reference
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""用独立标量差分和中心化等权回归计算有效真实样本的每秒变化率。23相邻/窗口的两个端点只做一次精确差,再转浮点输出。拟合使用局部时间和按4二进制指数缩放的值,避免绝对时间精度损失及大温度/电压背景造成的相消。5没有跨调用状态,窗口、真实间隔有效性及临时预算由时间线调用者提供。6"""78from fractions import Fraction9from math import frexp, fsum, ldexp10from .numeric import ScalarValue, _exact_float11from .types import QualityFlag as Q, SignalDType as D121314def _result(exact):15 """将已经得到的有限有理数转为一个每秒FLOAT64斜率。1617 参数: exact为最终斜率。返回: ScalarValue,真溢出或下溢有独立原因。18 异常: 内存不足原样传播。19 """20 try:21 value = float(exact)22 except OverflowError:23 return ScalarValue(None,D.FLOAT64,False,Q.NONFINITE)24 if not value and exact:25 return ScalarValue(None,D.FLOAT64,False,Q.PRECISION_LOSS)26 return ScalarValue(value,D.FLOAT64)272829def difference_reference(left, right, elapsed_ns):30 """按原值精确相减,再除以秒数,免去巨大相近整数的绝对值舍入。3132 参数: 两个同型有效标量与正的精确纳秒跨度。返回: FLOAT64 ScalarValue。33 异常: 内部调用需先校验模型。不能精确进入浮点的整数差量报PRECISION_LOSS。34 """35 delta = Fraction(right.value) - Fraction(left.value)36 if left.dtype is not D.FLOAT64:37 _, reason = _exact_float(delta.numerator)38 if reason:39 return ScalarValue(None,D.FLOAT64,False,reason)40 # 数学凸/差值仅用于两个端点,避免极大异号值先相减溢出但最终斜率可表示。41 return _result(delta * 1_000_000_000 / elapsed_ns)424344def fit_reference(positions, samples):45 """用局部时间、真实样本等权及补偿求和计算最小二乘斜率。4647 参数: 严格递增的精确纳秒与至少两个同型有效样本。48 返回: FLOAT64 ScalarValue。异常: 内部结构错误传播,数值失效转为质量。49 """50 first, span = positions[0], positions[-1] - positions[0]51 # 先在精确坐标域去掉纪元,再缩到[0,1],最大64位绝对时间不影响相邻差。52 x = [float(Fraction(t-first,span)) for t in positions]53 if samples[0].dtype is D.FLOAT64:54 exponent = frexp(max(abs(sample.value) for sample in samples))[1]55 base = ldexp(samples[0].value, -exponent)56 y = [ldexp(sample.value,-exponent) - base for sample in samples]57 else:58 # 精确相减后才提升,uint64也允许相对首值为负。59 exponent, y = 0, []60 for sample in samples:61 value, reason = _exact_float(sample.value - samples[0].value)62 if reason:63 return ScalarValue(None,D.FLOAT64,False,reason)64 y.append(value)65 mean_x, mean_y = fsum(x)/len(x), fsum(y)/len(y)66 cross = fsum((t-mean_x)*(v-mean_y) for t,v in zip(x,y))67 spread = fsum((t-mean_x)**2 for t in x)68 # 还原纵轴二进制倍率及横轴真实跨度时只做一次最终浮点舍入。69 return _result(Fraction(cross) * Fraction(2)**exponent * 1_000_000_000 / (Fraction(spread)*span))70