chronaxis.core.rate_transforms
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""为三类时序变化率核对数值输入和单位,并选择逐点或数组后端。23时间线调用方提供有效边界值或窗口中的真实样本,以及实际/周期口径的相对4纳秒计量。此处不创建网格或驱动帧,不推断TTL、窗口完整性或max_gap。5输出为FLOAT64 ScalarValue,单位从输入的当前数值尺度和温度角色推导。6"""78from fractions import Fraction9from . import unit_registry as units10from .numeric import ScalarValue11from .types import QualityFlag as Q, SignalDType as D121314def rate_unit(input_unit):15 """确定当前数值尺度的每秒自然单位,绝对温度先变为温差。1617 参数: input_unit为已编译输入表达式的单位标签。18 返回: 可重新解析的单位,如V/s、mV/s、delta_K/s或Hz。19 异常: ValueError为未登记或非法单位,不以未知标签证明量纲。20 """21 source = units.resolve_unit(input_unit)22 if source is None:23 raise ValueError('变化率需要可推导的输入单位')24 # 先相减得到温差,摄氏/K之间的常量偏移不参与变化率。此目录中的两者温差倍率均为1。25 if source.temperature_role == 'absolute':26 source = units.resolve_unit('delta_K')27 input_unit = 'delta_K'28 natural = units.divide(source, units.resolve_unit('s'))29 return units.output_label(natural, input_unit + '/s')303132def _quality(backend, samples):33 """检查已绑定的同型数值样本,并汇总全部必要输入的无效原因。3435 参数: backend为reference或numpy,samples为有限样本序列。36 返回: 合并的QualityFlag。异常: TypeError/ValueError为模型或静态dtype不符。37 """38 if backend not in ('reference','numpy'):39 raise ValueError('变化率后端需要reference或numpy')40 combined = Q.NONE41 dtype = None42 for value in samples:43 if not isinstance(value, ScalarValue) or value.dtype not in (D.INT64,D.UINT64,D.FLOAT64):44 raise TypeError('变化率只接受有类型的数值样本')45 if dtype is not None and value.dtype is not dtype:46 raise ValueError('同一变化率序列的输入类型必须一致')47 dtype = value.dtype48 combined |= value.quality49 return combined505152def _position(value):53 """校验内部实际纳秒或精确周期坐标,防止把大纪元时间先转浮点。5455 参数: value为原生int或Fraction。返回: 原坐标。异常: TypeError为单位/类型不符。56 """57 if type(value) not in (int,Fraction):58 raise TypeError('变化率计量坐标须为精确int/Fraction纳秒')59 return value606162def rate_difference(backend, left, right, elapsed_ns):63 """用两个边界值之差除以已选实际时间或折算周期跨度。6465 参数: backend为数值后端,left/right为ScalarValue,elapsed_ns为精确纳秒。66 返回: FLOAT64数值或带原因的无效值,合法负斜率不受原无符号dtype限制。67 异常: 非数值、后端或坐标类型错误直接拒绝。非正跨度属于DOMAIN_ERROR。68 """69 quality = _quality(backend,(left,right))70 if _position(elapsed_ns) <= 0:71 quality |= Q.DOMAIN_ERROR72 if quality:73 return ScalarValue(None,D.FLOAT64,False,quality)74 if backend == 'reference':75 from .rate_reference import difference_reference76 return difference_reference(left,right,elapsed_ns)77 from .rate_numpy import difference_numpy78 return difference_numpy(left,right,elapsed_ns)798081def rate_fit(backend, positions_ns, samples):82 """在至少两个不同时间的真实样本上求等权最小二乘斜率。8384 参数: backend为数值后端,positions_ns为所选实际/周期口径纳秒序列,85 samples为同行序的ScalarValue。调用方已经完成同刻原子归组。86 返回: FLOAT64每秒斜率;少于两个样本为MISSING,非递增位置为DOMAIN_ERROR。87 异常: ValueError为长度不符,类型错误原样传播。88 """89 if len(positions_ns) != len(samples):90 raise ValueError('拟合坐标与真实样本数必须相等')91 quality = _quality(backend,samples)92 previous = None93 for position in positions_ns:94 if previous is not None and _position(position) <= previous:95 quality |= Q.DOMAIN_ERROR96 previous = _position(position)97 if len(samples) < 2:98 quality |= Q.MISSING99 if quality:100 return ScalarValue(None,D.FLOAT64,False,quality)101 if backend == 'reference':102 from .rate_reference import fit_reference103 return fit_reference(positions_ns,samples)104 from .rate_numpy import fit_numpy105 return fit_numpy(positions_ns,samples)106