Chronaxis用户手册English
本页目录

chronaxis.core.window_delta_numpy

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""用数组掩码计算窗口覆盖、首尾位置和整窗单调性。23输入和输出与独立参考一致;实际使用searchsorted、区间裁剪、质量掩码和4相邻数组比较,不调用参考核。时间在整数域裁剪后才建立数组,避免下限回绕。5数值保留int64/uint64/float64,不将大整数转换成浮点。无文件和状态副作用。6"""78import numpy as np9from .types import QualityFlag as Q, SignalDType as D, Truth10from .window_delta import WindowDeltaResult, validate_delta_input111213def window_delta_numpy(spec, spans, time_ns, dtype):14    """通过真实数组运算计算一个窗口,不复用参考算法的数值函数。1516    参数: spec配置、spans有序DeltaSpan tuple、time_ns纳秒、dtype类型。17    返回: WindowDeltaResult。异常: 输入错误;数值失败记录质量。18    """19    time_ns = validate_delta_input(spec, spans, time_ns, dtype)20    left = time_ns - spec.window_ns21    starts = np.asarray([item.start_ns for item in spans], dtype=np.int64)22    ends = np.asarray([item.end_ns for item in spans], dtype=np.int64)23    flags = np.asarray([int(item.quality) for item in spans], dtype=np.uint16)24    points = np.asarray([int(item.point_quality) for item in spans], dtype=np.uint16)25    # 每个交叠长度不超过window_ns,求和不超过同一窗口,定宽时间运算安全。26    lower = np.maximum(starts, max(left, -(2**63)))27    upper = np.minimum(ends, time_ns)28    overlap = lower < upper29    lengths = np.zeros(len(spans), dtype=np.int64)30    np.subtract(upper, lower, out=lengths, where=overlap)31    duration = int(np.sum(lengths, where=flags == 0, initial=0, dtype=np.int64))32    quality = Q(int(np.bitwise_or.reduce(flags[overlap], initial=0)))33    indices = []34    for boundary in (left, time_ns):35        # left可能低于int64下限,先处理后再交给searchsorted,防隐式浮点比较。36        index = -1 if boundary < -(2**63) else int(np.searchsorted(starts, boundary, side='right')) - 137        if index < 0 or not (starts[index] == boundary or boundary < ends[index]):38            quality |= Q.MISSING39            indices.append(None)40        else:41            indices.append(index)42            quality |= Q(int(points[index] if starts[index] == boundary else flags[index]))43    middle = (starts > max(left, -(2**63))) & (starts < time_ns)44    # 当left低于最小时间时,最小时间处仍属于窗口内观测。45    if left < -(2**63):46        middle = starts < time_ns47    quality |= Q(int(np.bitwise_or.reduce(points[middle], initial=0)))48    if duration != spec.window_ns:49        quality |= Q.MISSING50    if quality != Q.NONE:51        return WindowDeltaResult(time_ns, left, None, Truth.UNKNOWN, quality,52                                 duration, duration / spec.window_ns, None)53    first, last = (spans[index].value for index in indices)54    values = np.asarray([first, *(item.value for item, include in zip(spans, middle) if include), last],55                        dtype=dtype.value)56    nondecreasing = bool(np.all(values[1:] >= values[:-1]))57    nonincreasing = bool(np.all(values[1:] <= values[:-1]))58    monotonic = (nondecreasing if spec.direction == 'rise' else nonincreasing59                 if spec.direction == 'fall' else nondecreasing or nonincreasing)60    a, b = (values[0], values[-1]) if spec.direction == 'fall' else (values[-1], values[0])61    if spec.direction == 'any' and a < b:62        a, b = b, a63    # 减法前用范围不等式证明安全,防止numpy先回绕;无隐藏float提升。64    if dtype is D.INT64:65        aa, bb = int(a), int(b)66        if (bb > 0 and aa < -(2**63) + bb) or (bb < 0 and aa > 2**63 - 1 + bb):67            quality = Q.OVERFLOW68    elif dtype is D.UINT64 and a < b:69        quality = Q.OVERFLOW70    if quality != Q.NONE:71        return WindowDeltaResult(time_ns, left, None, Truth.UNKNOWN, quality, duration, 1.0, monotonic)72    with np.errstate(over='ignore', invalid='ignore'):73        value = np.subtract(a, b).item()74    if dtype is D.FLOAT64 and not np.isfinite(value):75        return WindowDeltaResult(time_ns, left, None, Truth.UNKNOWN, Q.NONFINITE, duration, 1.0, monotonic)76    satisfied = value >= spec.threshold and (not spec.monotonic or monotonic)77    return WindowDeltaResult(time_ns, left, value, Truth.TRUE if satisfied else Truth.FALSE,78                             Q.NONE, duration, 1.0, monotonic)79
Chronaxis 用户手册 · 离线阅读