Chronaxis用户手册English
本页目录

chronaxis.core.affine

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""将一个已校验数值换到目标单位,执行一次完整的乘法与偏移转换。23输入为 ScalarValue、编译期确定的倍率/偏移和目标类型;输出仍为 ScalarValue。4整数在 Python 精确整数域计算最终结果,再检查目标定宽;浮点先检查整数5输入的可表示性,再计算并检查有限性与纯倍率下溢。未知值保持原质量原因,6不会因为乘零或加偏移变成正常数据。本模块不依赖 NumPy,不读取文件,7不改变输入,也不保存转换前后副本或跨批次状态。单位关系由编译器验证。8"""910# 只复用标量路径已有的数值模型和精度检查,不调用数组实现。11from math import isfinite1213from .numeric import INTEGER_BOUNDS, ScalarValue, _exact_float14from .types import QualityFlag, SignalDType151617def _validate_affine(source_dtype, dtype, scale, offset) -> None:18    """检查编译器传入的仿射转换结构,数值合法性仍逐样本处理。1920    参数: source_dtype、dtype分别为输入和输出数值类型;scale、offset为21        原生整数或有限浮点数,不接受bool。整数输出要求输入和系数均为整数。22    返回: None,无副作用。23    异常: TypeError为非数值类型/系数;ValueError为非有限系数或错误类型提升。24    """25    # 逻辑值和枚举不能借单位转换隐式进入数值计算。26    numeric_types = (*INTEGER_BOUNDS, SignalDType.FLOAT64)27    if source_dtype not in numeric_types or dtype not in numeric_types:28        raise TypeError('仿射转换仅接受明确的数值类型')29    # 系数来自静态编译,坏配置不能伪装为所有样本缺失。30    if any(type(item) not in (int, float) for item in (scale, offset)):31        raise TypeError('仿射系数必须为原生int或float,不能为bool')32    if any(type(item) is float and not isfinite(item) for item in (scale, offset)):33        raise ValueError('仿射系数必须有限')34    # 需要小数的转换应在编译时提升,不随样本碰巧整除而改变输出类型。35    if dtype in INTEGER_BOUNDS and (source_dtype not in INTEGER_BOUNDS36                                   or type(scale) is not int or type(offset) is not int):37        raise ValueError('整型仿射目标需要整数输入及整数系数;请先确定float64提升')383940def affine_reference(value: ScalarValue, scale: int | float, offset: int | float,41                     dtype: SignalDType) -> ScalarValue:42    """按value*scale+offset完成标量单位转换,并保留精度及有效性。4344    参数: value为已校验数值;scale、offset为有限编译期系数;dtype为静态45        目标数值类型。整数目标只接整数输入和系数,浮点目标检查大整数精度。46    返回: ScalarValue;超定宽为OVERFLOW,浮点非有限为NONFINITE,不能精确47        转为浮点或纯倍率下溢到零为PRECISION_LOSS,输入无效则保留原原因。48    异常: TypeError或ValueError为声明结构错误;不将配置错误变成样本质量。49    边界: -273.15乘1再加273.15得到正常0;整数中间乘积可以超过64位,50        只要完整仿射结果仍在目标范围。无副作用,不保留转换历史。51    """52    # 公共入口不接受裸数或逻辑值;静态系数检查先于逐样本运算。53    if not isinstance(value, ScalarValue):54        raise TypeError('仿射参考转换需要ScalarValue')55    _validate_affine(value.dtype, dtype, scale, offset)56    # 无效输入不计算,偏移不能把缺失变成一个看似正常的温度。57    if not value.valid:58        return ScalarValue(None, dtype, False, value.quality)59    # 完整整数仿射使用无界中间整数,最后再核对目标定宽。60    if dtype in INTEGER_BOUNDS:61        result = value.value * scale + offset62        lower, upper = INTEGER_BOUNDS[dtype]63        if not lower <= result <= upper:64            return ScalarValue(None, dtype, False, QualityFlag.OVERFLOW)65        return ScalarValue(result, dtype)66    # 三个操作数分别检查精度;整数2**53+1不能因换单位而默默舍入。67    number, number_quality = _exact_float(value.value)68    factor, factor_quality = _exact_float(scale)69    shift, shift_quality = _exact_float(offset)70    quality = number_quality | factor_quality | shift_quality71    if quality != QualityFlag.NONE:72        return ScalarValue(None, dtype, False, quality)73    # 对整个仿射结果检查;零偏移时才用非零输入判断下溢,避免误伤温度抵消。74    result = number * factor + shift75    if not isfinite(result):76        return ScalarValue(None, dtype, False, QualityFlag.NONFINITE)77    if shift == 0 and result == 0 and number != 0 and factor != 0:78        return ScalarValue(None, dtype, False, QualityFlag.PRECISION_LOSS)79    return ScalarValue(result, dtype)80
Chronaxis 用户手册 · 离线阅读