chronaxis.core.moments
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""声明 v4 样本与时间二阶统计的操作、自由度和输出量纲。23这里只校验静态契约。归约器使用实际有效更新或选中区间的权重,4其标量算法与数组算法各自实现,不在本模块累计任何历史。5"""67SAMPLE_MOMENTS = ('sample_variance', 'sample_stddev', 'sample_rms')8TIME_MOMENTS = ('time_variance', 'time_stddev', 'time_rms')9MOMENTS = SAMPLE_MOMENTS + TIME_MOMENTS10WITH_DDOF = ('sample_variance', 'sample_stddev', 'time_variance', 'time_stddev')111213def moment_ddof(operation, value):14 """检查显式自由度。参数: 操作及原生整数或None。返回: 适用的整数或None。异常: 不适用或越界。"""15 if operation not in WITH_DDOF:16 if value is not None:17 raise ValueError('ddof仅用于方差或标准差')18 return None19 if value is None:20 return 021 if type(value) is not int or value not in ((0, 1) if operation in SAMPLE_MOMENTS else (0,)):22 raise ValueError('样本方差/标准差ddof为整数0或1,时间统计仅接受整数0')23 return value242526def moment_source_unit(operation, unit):27 """推导归约数值的自然单位。参数: 操作及已登记输入Unit。返回: Unit。异常: 未知单位或偏移RMS。"""28 from .unit_registry import resolve_unit, square29 if unit is None:30 raise ValueError('二阶统计需要已登记单位,无法推导未知量纲')31 if operation.endswith('_rms'):32 if unit.offset:33 raise ValueError('摄氏绝对温度RMS须先显式to_unit(...,"K")')34 return unit35 if unit.temperature_role == 'absolute':36 # 绝对温度的离均差是温差,不在差的平方或标准差上加回摄氏偏移。37 unit = resolve_unit('delta_degC' if unit.offset else 'delta_K')38 return square(unit) if operation.endswith('_variance') else unit394041def compute_moment_series(series, spec, sample_kernel, time_kernel, conditioned_kernel, step_ns):42 """让内存入口沿同后端的分块归约协议执行一次,返回完整数值和覆盖。4344 参数: 已验证序列、请求、对应后端的三种归约类和记录周期。45 返回: CalculationResult。异常: 与分块公开执行相同的类型、单位和时间错误。46 """47 from .calculations import make_calculation_result48 args = spec, series.unit, series.values[0].dtype49 sample = spec.operation in SAMPLE_MOMENTS50 if sample:51 reducer = sample_kernel(*args)52 else:53 factory = conditioned_kernel if series.conditions is not None else time_kernel54 reducer = factory(*args, step_ns=step_ns)55 facts = reducer.push(series)56 number = reducer.finish()57 actual = facts.actual_window58 span = 0 if actual is None else actual.end_ns - actual.start_ns59 if sample or series.conditions is not None:60 known = facts.condition_known_duration_ns61 unknown = facts.selected_value_unknown_duration_ns62 missing_conditions = facts.condition_unknown_ranges63 all_false = actual == spec.window and span > 0 and facts.false_duration_ns == span64 else:65 known, unknown, missing_conditions, all_false = span, span - facts.value_valid_duration_ns, (), False66 return make_calculation_result(spec, series, number.value, number.unit, actual, facts.value_valid_duration_ns,67 known, facts.selected_duration_ns, unknown, facts.valid_sample_count, facts.value_unknown_ranges,68 missing_conditions, facts.quality | number.quality, all_false=all_false, calculation_failed=number.calculation_failed)69