chronaxis.core.conditional_integral_terms_reference
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""独立标量生成有限条件积分面积,分别保存值覆盖与BOOL条件覆盖。23输入为有限CalculationSeries和原integral请求,输出原序(N-1,)面积/掩码及冻结事实。4每个值先通过标量浮点精度检查;只有TRUE且有效值才乘裁剪后的整数纳秒时长。5面积溢出或非零下溢使该位置值和真实样本失效;FALSE、UNKNOWN不做面积乘法。6不把UNKNOWN补零,不归约面积或转换最终单位,不读取来源、不修改输入。7只依赖标准库及typed模型,不调用NumPy;有限临时列须由调用方owner预约。8"""910# 标量数值与覆盖判据独立于数组核,仅复用已校验模型和结构门槛。11from math import isfinite12from .conditional_integral_terms import ConditionalIntegralFacts, ReferenceConditionalIntegralTerms, require_conditional_integral_terms13from .calculations import merge_ranges14from .models import Interval15from .numeric import ScalarValue, to_float_reference16from .types import QualityFlag as Q17from .record_intervals import clipped_record_seconds181920def compute_conditional_integral_terms_reference(series, spec, *, step_ns=None, valid_until_ns=None,21 condition_valid_until_ns=None, retain_unknown_ranges=True):22 """逐正区间生成未转换原序面积与独立值、条件覆盖事实。2324 参数: series为有限数值CalculationSeries及显式BOOL条件,spec为原integral请求。25 step_ns为可选所选周期;两个until列是实际有效截止;范围明细可显式关闭。26 返回: ReferenceConditionalIntegralTerms;面积为输入单位乘秒,无效槽位0配False。27 异常: 输入、单位、时间与分配错误传播;精度、面积溢出/下溢写入质量及未知。28 """29 # 结构先校验,裁剪保留精确整数ns;没有交集不凭空创建观察域。30 require_conditional_integral_terms(series, spec, step_ns=step_ns, valid_until_ns=valid_until_ns,31 condition_valid_until_ns=condition_valid_until_ns)32 if type(retain_unknown_ranges) is not bool:33 raise TypeError('未知范围保留选项需要bool')34 start = max(series.observation.start_ns, spec.window.start_ns)35 end = min(series.observation.end_ns, spec.window.end_ns)36 actual = Interval(start, end) if start <= end else None37 # 所有值都接受原完整积分的精度门槛,包括FALSE与UNKNOWN未选择的值。38 values = [to_float_reference(value) for value in series.values]39 conditions = series.conditions if condition_valid_until_ns is None else list(series.conditions)40 # 到期点本身已失效;未到期的部分区间在下方独立裁剪。41 for rows, deadlines in ((values, valid_until_ns), (conditions, condition_valid_until_ns)):42 if deadlines is not None:43 for index, deadline in enumerate(deadlines):44 if deadline is not None and series.times_ns[index] >= deadline:45 old = rows[index]46 rows[index] = ScalarValue(None, old.dtype, False, old.quality | Q.STALE, old.labels)47 areas, valid, value_unknown, condition_unknown = [], [], [], []48 value_duration, known_duration, selected_duration = 0, 0, 049 selected_unknown_duration, false_duration, sample_count, quality = 0, 0, 0, Q.NONE50 # 原N-1槽位顺序不变;数值未跨块归约,条件单独变化只改变选择覆盖。51 for index in range(len(series.times_ns) - 1):52 left, right = max(start, series.times_ns[index]), min(end, series.times_ns[index + 1])53 area, keep = 0.0, False54 if left < right:55 value, condition = values[index], conditions[index]56 quality |= series.diagnostics[index] | value.quality | condition.quality57 value_end = right if valid_until_ns is None or valid_until_ns[index] is None else max(left, min(right, valid_until_ns[index]))58 condition_end = right if condition_valid_until_ns is None or condition_valid_until_ns[index] is None else max(left, min(right, condition_valid_until_ns[index]))59 selected_end = min(value_end, condition_end)60 if value_end < right or condition_end < right:61 quality |= Q.STALE62 # 只有明确TRUE才计算面积;FALSE不因未执行的溢出丢掉值覆盖。63 if value.valid and condition.valid and condition.value and selected_end > left:64 seconds = ((selected_end - left) / 1_000_000_000 if step_ns is None else65 clipped_record_seconds(series.times_ns[index], series.times_ns[index + 1],66 spec.window if selected_end == right else Interval(left, selected_end), step_ns=step_ns))67 term = value.value * seconds68 failure = Q.NONFINITE if not isfinite(term) else Q.PRECISION_LOSS if term == 0 and value.value != 0 else Q.NONE69 if failure == Q.NONE:70 area, keep = term, True71 else:72 # 局部转换列同时更新样本有效性;原ScalarValue不被改写。73 value = ScalarValue(value.value, value.dtype, False, value.quality | failure, value.labels)74 values[index] = value75 quality |= failure76 # 值和条件各自完整分区;TRUE值未知与条件UNKNOWN分别登记。77 if value.valid:78 value_duration += value_end - left79 if retain_unknown_ranges and value_end < right:80 value_unknown.append(Interval(value_end, right))81 elif retain_unknown_ranges:82 value_unknown.append(Interval(left, right))83 if condition.valid:84 known_duration += condition_end - left85 if not condition.value:86 false_duration += condition_end - left87 elif value.valid:88 selected_duration += selected_end - left89 selected_unknown_duration += condition_end - selected_end90 else:91 selected_unknown_duration += condition_end - left92 if retain_unknown_ranges and condition_end < right:93 condition_unknown.append(Interval(condition_end, right))94 elif retain_unknown_ranges:95 condition_unknown.append(Interval(left, right))96 # 未观察槽位也保留原位置,但不形成UNKNOWN或正常积分项。97 areas.append(area)98 valid.append(keep)99 # 只计半开范围内原值真实更新且有效/TRUE;条件更新与末点不能计样本。100 for index, time in enumerate(series.times_ns):101 if start <= time < end and series.actual_value_updates[index]:102 value, condition = values[index], conditions[index]103 quality |= series.diagnostics[index] | value.quality | condition.quality104 if value.valid and condition.valid and condition.value:105 sample_count += 1106 # 两未知元组仅合并相邻范围;完整来源子类和联合绑定身份原样保留。107 facts = ConditionalIntegralFacts(spec, actual, value_duration, known_duration, selected_duration,108 selected_unknown_duration, false_duration, sample_count, merge_ranges(value_unknown),109 merge_ranges(condition_unknown), quality, series.unit, series.binding_identity, series.source_refs,110 ranges_retained=retain_unknown_ranges)111 return ReferenceConditionalIntegralTerms(tuple(areas), tuple(valid), facts)112