读取分析结果
默认输出:直接看区间和数值
普通配置不用填写outputs。运行后先打开中文命名的CSV:同一事件或窗口的计算结果已经放在同一行,不必手动关联ID,也不用把纳秒换算成秒。文件是UTF-8带BOM编码,方便Windows表格软件识别中文;原始数值没有为了显示而舍入。
例如连续条件能量示例只产生一段合格区间:
| 区间 | 规则 | 开始时间(s) | 结束时间(s) | 区间状态 | energy_kwh(kWh) | energy_kwh:状态 | energy_kwh:说明 |
|---|---|---|---|---|---|---|---|
| 1 | eligible | 61 | 122 | 正常结束 | 0.06777777777777777 | 完整 |
直接读作:第1段活动从61秒开始,到122秒结束,能量为0.06777777777777777kWh,计算完整。区间是左闭右开[61,122)。普通整事件积分不额外显示确认时刻;独立事件、窗口、配对或其他计算有此用途时才显示“确认时间(s)”。起止时间仍是实际时间,未额外计算持续时间。
| 实际请求的结果 | 默认文件 | 读法 |
|---|---|---|
| 整个会话的统计 | 会话结果.csv | 同会话多项统计合并一行;各项有自己的单位、状态和说明。 |
| 事件及事件内统计 | 事件结果.csv | 起止、规则和区间编号只出现一次,各指标横向排列。 |
| 窗口及窗口内统计 | 窗口结果.csv | “父事件区间”对应事件表编号;多个编号表示多个父事件。 |
| 请求与响应 | 配对结果.csv | 请求/响应编号对应事件表;判定时间和延迟单位都是秒。 |
| select明细 | 选择结果.csv | 每次更新的值、单位、有效性及满足/未知状态。 |
| v4 结果聚合 | 聚合结果.csv | 一行对应一个组,列出数值、单位、候选数、参与数及排除原因。文件名带本次运行的时间后缀。 |
| 明确请求贡献或输入追溯 | 贡献明细.csv、输入追溯.csv | 保留所需定位和原因,普通任务不产生。 |
共同的数据集、对象和会话名称只在本次运行清单的presentation.common_identity保存;出现多个值时,对应身份列才加入表中。区间编号只在本次输出内有效,不能用来跨次运行关联。信号CSV及ASC/BLF原帧导出保持各自的数据格式,不使用这套中文结果表结构。
时间列用精确十进制秒,例如922.346858001,不丢纳秒精度。时间保留分析原点,既不从首个结果重新归零,也不猜测日期或时区。绝对时间坐标仍按实际数值显示,不能把没有日期的信息解释成某天的钟表时间。
每项指标分别看状态:“完整”表示本项计算完整;“部分有效”只包含能计算的部分;“无法确定”表示不能给出可用数值。空单元格不等于0。“数据中断”与“观测结束,活动尚未确认结束”是不同的区间状态。说明列将缺失、过期、解码失败等质量位翻译成文字;空说明不证明输入在现实中绝对正确。
没有事件时保留空表和清单中的result_messages,例如“条件曾成立,但持续时间不满足要求”;不会补一行能量0。全局存在条件未知可以与某个已输出区间的完整计算并存。多个指标中一项缺失,不会把其他项一起标为完整或失败。
聚合结果怎样读
结果聚合说明配置、来源与分组。默认“聚合结果”表逐行提供名称、分组、数值、单位、状态、原因及候选/参与/排除数。候选数=参与数+定义排除数+质量排除数;这些是行数,不是时间覆盖率。
included_partial_count是参与数中允许纳入的部分值数量。配对结果另有matched_count、timeout_count、insufficient_observation_count、pending_count,分别表示成功、确认超时、观测不足和未决请求。discovery_complete说明是否有足够观测确认所有候选均被识别。例如条件中断期间可能漏掉事件,此值就不能等同于“已有数值完整”。
同时看status、reason、quality。功率示例load_mean_p95为19.5W,候选2、参与2;完整实际表见统计结果示例。
为程序选择交换格式
默认格式名是readable_csv,无需手填。程序若依赖原表字段,在配置根部增加以下内容;已有outputs时在原映射内增加tables,不再写第二个outputs:
outputs: # 只在程序需要原交换字段时增加这段
tables: csv # 保留原平坦表、字段名和整数纳秒可选值只有readable_csv、csv、jsonl。csv使用events.csv、calculations.csv等原表;jsonl使用对应逐行JSON(包含row_schema_version和row)。选择一种只输出一套结果,不同时生成可读和交换副本。Python的iter_events、iter_calculations等始终返回原类型化行,不受输出格式影响;低层AnalysisResult构造器仍保留csv默认,AnalysisRunner跟随计划默认readable_csv。
可读导出只读已计算结果,不重读原始日志。事件与指标的排序不同,需要临时关联索引;该索引受内存/磁盘预算约束并在发布前删除。它会增加少量导出时间;大量结果需要以具体规模实测。只有逐条明细时直接写出,不创建关联索引。
以下字段说明用于显式csv/jsonl与类型化API;普通可读表用上面的中文列。
想先看输出长什么样,请打开示例运行结果与解析:每个完整配置都能找到运行命令、实际结果表和数值解释。本页用于查字段含义,配置文件和运行后的结果文件是两种不同结构。
普通计算的一行直接包含calculation_id、operation、scope、value、unit、status、reason和quality,以及数据集、实体、会话、父事件/片段和序号。可直接通过row.value等属性读取,完整字段见下表关联的结果模型。
本页未另行说明的秒数例子采用默认actual。配置intervals为fixed或dbc时,持续确认、等待到期、变化窗口和配对delay_ns使用所选周期依据;原时间坐标和信号到期仍按实际记录时间。先看三种时间依据对照。
| 表/API | 每行回答的问题 |
|---|---|
| calculations / iter_calculations | 某个计算项在会话、事件或片段内的值、单位、覆盖和质量如何 |
| events / iter_events | 哪条规则在何时开始、确认和结束;状态和触发原因是什么 |
| segments / iter_segments | 哪个窗口得到什么起止范围,与哪些事件有关 |
| sequences / iter_sequences | 哪个请求匹配了哪个响应,何时作出决定,延迟多少 |
| selections / iter_selections | select明确选择的样本时刻、值、类型、单位和有效状态 |
| input_trace / iter_input_trace | 明确请求详细追溯时的输入位置和记录种类 |
| contributions / iter_contributions | outputs.contributions=full时的逐消息贡献与跳过原因 |
计算行按实际操作返回SummaryCalculationRow或带coverage_status的SummaryCoverageCalculationRow;普通信号计算integral、duration、min_time、max_time、time_weighted_mean、sample_minimum、sample_maximum和sample_mean,以及 v4 的样本计数、方差、标准差、RMS 和样本分位数,在 minimum_coverage 大于 0 时返回 coverage_status。sufficient表示所需的观测、值有效性和条件已知范围均达到门槛;indeterminate表示不足或无法确定。这个字段不是数值覆盖率,也不会把样本统计改成时间加权统计。select明细和逐消息累计不属于这组标量结果。显式填0与省略不会因此增加coverage_status。各类完整字段均列在摘要行模型。公开表的相同字段在CSV和JSONL中表示同一事实。
显式csv输出带时间后缀的CSV结果表和运行清单;jsonl每行包含版本与row字段对象。清单记录本次运行和实际写出的表;可读模式的row_counts按合并后的文件行数计数。配置标识不是输入文件内容的哈希,不能据此认定两次数据相同。
结果怎样发布
结果目录可以重复使用。一次输出的表、清单和请求的导出目录共用一个时间后缀,例如:
results/
会话结果_20261103_091500_123456.csv
run_manifest_20261103_091500_123456.json
会话结果_20261103_092000_654321.csv
run_manifest_20261103_092000_654321.json后缀使用本机时间,格式为年月日、时分秒、微秒;同刻或并发冲突时再加序号。它表示这批输出的命名时间,不改变报文时间、结果起止或能量。已有文件不会被覆盖,未请求的表和导出也不会生成。
程序先完成本次临时文件并关闭,再逐项发布,最后发布完成清单。只有清单存在且状态为completed,才表示这批输出已齐全。普通失败会清理本次拥有的文件;进程被强杀或断电可能留下没有完成清单的文件,不能把它们当成已完成结果。下次运行不会扫描或删除旧结果。本页结果发布流程已在 Windows 和安装说明列出的 Linux 环境验证。Linux 发布需要 renameat2、目标文件系统支持 RENAME_NOREPLACE,且移动位于同一文件系统;其他系统和文件系统的支持范围以安装说明为准。
CLI完成摘要的manifest、API返回的OutputManifest.manifest_path指向本次实际清单;从清单outputs读取本次表文件。不要拼固定run_manifest.json,也不要在同目录内随意挑一个同类CSV或“最新文件”。同一AnalysisResult在关闭前可再次write到同一目录或其他目录,无需重读输入。显式work_dir仍须为新目录,与可复用的最终结果目录不同。
本章表格中的事件结果.csv、会话结果.csv等是文件用途名称;实际运行均在扩展名前增加时间后缀。随手册保存的教学结果保留生成时的文件名,下载链接不代表新运行使用固定文件名。
缺失不是零
value为空时要结合status、reason和quality看原因。无效更新覆盖前值,过期产生未知,程序不会把缺口补成0。minimum_coverage只判断是否达到所需覆盖;partial_policy=report保留可以说明的部分结果,strict按现有规则拒绝不足覆盖的数值,不能把未观测的时段当成已知。
用实际输出理解partial
在入门配置中,为power显式设置valid_for: 1s,覆盖DBC周期1s所推导的默认有效期3s,并在energy计算项设置partial_policy。其他输入和[0,6)秒分析范围保持相同。[2,3)和[5,6)内旧功率已到期,又没有新值,因此只有4秒能计算能量:2W×1s+4W×1s+8W×1s+10W×1s=24J。
| energy的partial_policy | value | status | reason | 如何使用结果 |
|---|---|---|---|---|
| report | 24.0 | partial | partial_coverage | 24J仅代表已知4秒的能量,不能当作完整6秒的总能量。 |
| strict | 空值 | indeterminate | insufficient_coverage | 数据不足,无法按完整范围给出数值;不能把空值换成0。 |
本例两行的quality均包含STALE,表示有效期已过。应按真实采集规律核对valid_for、数据时间和遗漏记录,不能仅为消除partial就调大有效期。完整数据可以得到complete;partial表示已有可用的部分值,indeterminate表示当前策略或证据不足以给出数值。具体原因仍以相应计算项的reason为准。
事件与配对
事件的start_ns是活动起点,confirmed_ns是达到确认门槛的时刻,end_ns是结束时刻或空值。所有_ns字段使用整数纳秒,不代表“秒数的浮点值”。
配对行直接提供request_id、response_id、decided_ns、delay_ns和status。matched表示找到响应;no_response表示完整等待期间可判断但没有响应;indeterminate表示缺数据或观测提前结束,不能下无响应结论。没有请求就没有配对行。
quality:把数字还原为质量原因
CSV/JSONL的quality是整数位标记,可以同时包含多个原因,不是严重程度分数,也不是单个错误编号。0表示没有记录这些原因,仍须看status、reason或valid;例如缺少插值右端时可以是quality=0、status=missing、reason=missing_right。
| 数值 | 名称 | 意思与排查方向 |
|---|---|---|
| 1 | MISSING | 缺少需要的观测或值;核对输入列和缺失标记。 |
| 2 | STALE | 最近值超过valid_for;核对真实更新间隔和漏帧。 |
| 4 | DECODE_ERROR | 来源解码错误;核对DBC与报文结构。 |
| 8 | NONFINITE | NaN或无穷;核对输入值。 |
| 16 | OUT_OF_RANGE | 超出允许范围或编码映射;核对范围及编码表。 |
| 32 | ESTIMATED | 估计值标志;基础信号质量策略不把它当实际有效观测。 |
| 64 | OVERFLOW | 运算超出数值范围;检查数量级和表达式。 |
| 128 | PRECISION_LOSS | 转换无法精确表示;检查整数大小和目标类型。 |
| 256 | DOMAIN_ERROR | 除零等数学值域错误;检查公式。 |
例如3=1+2,表示MISSING与STALE都出现过。不能写quality == 1来判断是否含缺失,否则会漏掉3;应检查quality & 1。Python可直接使用枚举:
from chronaxis.core.types import QualityFlag
quality = QualityFlag(3) # CSV文字须先int转换;未知位或负数会报ValueError
names = [flag.name for flag in QualityFlag if quality & flag]
print(names) # ['MISSING', 'STALE']可运行对照:quality.yaml读取合成quality.asc与teaching.dbc。0秒Power为10W,1秒解码值为-1e100,2秒恢复为10W,4秒收到不含Power的报文并结束观测。配置明确将-1e100列入invalid_values,并选择valid_for: 1s。
只有[0,1)及[2,3)有有效功率,因此energy=20J、status=partial、reason=partial_coverage。当前CAN例的quality=18,即OUT_OF_RANGE(16)加STALE(2):[1,2)命中无效码,替换此前有效值;[3,4)功率已过期。程序没有补0或继续沿用无效值。运行chronaxis run quality.yaml --output quality-result核对。
本例1秒时出现显式无效码,产生OUT_OF_RANGE(16);2秒恢复的10W在3秒到期,产生STALE(2)。只有[0,1)和[2,3)可积分,共20J,status为partial,quality=16+2=18。上面的quality=3是质量位读法示意,不是本例输出。
各种结果的状态字段
不同表的字段集合不同,不要统一索引status/reason;先确认正在读哪种结果。下面的入口链接到实际行模型,包含完整参数与约束。
| 结果 | 判断字段与含义 | 模型 |
|---|---|---|
| 普通/逐消息汇总计算 | status=complete/partial/indeterminate:完整、部分可用、无法确定;reason说明原因 | SummaryCalculationRow |
| 有覆盖门槛的计算 | 还含coverage_status=sufficient/indeterminate,表示门槛判定;不是数值覆盖率 | SummaryCoverageCalculationRow |
| 事件 | status=point为点事件;closed正常结束;interrupted因未知中断;truncated观测结束;timeout超时。trigger是触发类型,事件没有reason列 | SummaryEventRow |
| 窗口片段 | status=complete/partial/empty;empty没有实际起止范围;没有reason列 | SummarySegmentRow |
| 请求响应 | status=matched/no_response/indeterminate;没有reason列,结合quality及关联事件 | SummarySequenceRow |
| 样本选择 | valid说明值是否有效;selection=true/unknown说明选择条件;没有status/reason列 | SummarySelectionRow |
| 消息贡献 | reason=contributed表示计入;missing_input缺值;condition_false方向条件不满足;evaluation_error表达式失败;nonfinite_input输入非有限;没有status列 | SummaryContributionRow |
| 信号插值导出 | status=observed/estimated/missing;reason如missing_right说明没有可用的右端记录 | 信号导出 |
普通时间计算的reason按下表处理,不应把所有空值都叫“缺数据”:
| reason | 含义 | 处理 |
|---|---|---|
| ok | 计算满足当前要求 | 连同单位、范围和quality读取 |
| partial_coverage | report保留已有部分 | 核对缺失范围,不能当全程总量 |
| insufficient_coverage | strict不接受不足覆盖 | 补数据或重新确认业务接受标准 |
| zero_length_window | 计算窗口长度为0 | 核对窗口起止和事件 |
| no_observation | 没有观测 | 核对输入与请求时间范围 |
| calculation_failed | 数值计算失败 | 解读quality,检查公式和数值范围 |
| empty_selection | 条件可判断但未选中数据 | 积分/时长可为0;均值等不伪造0 |
| unknown_selection | 无法判断选择条件 | 检查条件信号缺失或过期 |
| no_samples / no_valid_selected_data | 没有可参与所需运算的样本/有效数据 | 核对样本选择、类型和质量 |
用实例ID关联三张结果表
同一个hot规则可能产生很多次事件,因此rule_id=hot只是配置定义名称,不能唯一定位某次活动。关联时使用同一运行清单关联文件中的event_id/segment_id;不要按表的行顺序拼接,也不要只按sequence跨表拼接。
结果行的sequence是本次写入序号,不是跨运行稳定的业务标识,也不是原始报文序号。比较不同批大小或进程设置的结果时,按规则、窗口、计算项名称、实际时间及本次父事件关联匹配,并核对重复项数量、数值、单位、状态和质量;逐消息明细还需保留原消息顺序。不要把运行ID、生成时间或写入序号的变化当作数值差异。
以下来自activity.yaml的一次真实运行。为了表格可读,E1、S1仅是这里的显示缩写,实际字段保存下列完整字符串;使用时读取自己这次输出中的ID,不硬编码本例字符串。
- E1(event_id):
3d7375484e46c0da41755d73629db92c3f87b98da58891b2c238c5a6517b848f - S1(segment_id):
127695a43e932e2ceeb70f0319294829572ba84c9af8fb793e9b41eb40013de9
| 表 | 配置定义名称 | 本次实例/父引用 | 业务值 |
|---|---|---|---|
| events | rule_id=hot | event_id=E1 | start=1秒,confirmed=3秒,end=6秒 |
| segments | window_id=hot_context | segment_id=S1;parent_event_ids=[E1] | [0,7)秒 |
| calculations | calculation_id=event_energy | scope=event;parent_id=E1 | 50J |
| calculations | calculation_id=context_energy | scope=segment;parent_id=S1 | 70J |
合并窗口可能对应多个事件,因此parent_event_ids是列表,不是一个事件ID。session范围的计算parent_id为None;CSV中是空单元格,JSONL中是null。Python使用如下关联步骤;放在仍然打开的AnalysisResult上下文内,仅适用于能装入内存的小型结果,完整关闭示例见复核脚本。
events = {row.event_id: row for row in result.iter_events()}
segments = {row.segment_id: row for row in result.iter_segments()}
for row in result.iter_calculations():
if row.scope == "event":
event = events[row.parent_id]
print(event.rule_id, event.start_ns, row.value, row.unit)
elif row.scope == "segment":
segment = segments[row.parent_id]
parent_events = [events[event_id] for event_id in segment.parent_event_ids]
print(segment.window_id, len(parent_events), row.value, row.unit)
else:
print("session", row.value, row.unit)大结果应将三表按完整ID导入数据库或分批索引;不要为了关联把整份数据都list化。跨多次运行汇总时还需保留运行目录/运行身份,防止将不同运行的实例混在一起。
独立导出
信号CSV与CAN报文导出由outputs单独请求,实际索引路径和导出目录分别由本次 manifest 的 exports.index_file、exports.directory 给出;它们带本次运行的时间后缀。原值和插值后的估计值有各自文件;CAN原帧与重建帧不混称原始输入。导出网格不改变分析积分间隔,见导出。
运行清单的摘要与详细字段
RunMetadata保存运行信息,to_dict()决定哪些字段写入JSON。省略software_version时,每次构造RunMetadata才读取当前这份源码或安装包的发行版本;已经创建的对象和显式传入的历史版本不随之改写。这不表示已加载的Python代码会自动更新。默认detailed_diagnostics=False输出run_id、plan_hash、backend、config_version、started_at、device_label、software_version、source_time_interpretation、parsing_policy、worker_config、retain_work和detailed_diagnostics;输入身份、会话边界、限制等仅在满足对应条件时补充。开启trace/integrity还会输出相应诊断信息。
| 模型状态 | 默认摘要模式 | detailed_diagnostics=True |
|---|---|---|
| signal_bindings含一条信号定义 | 字典中没有signal_bindings键 | 字典展开该信号定义 |
| 存有preset_bindings或CAN来源详情 | 不因非空自动输出 | 按详细序列化分支输出,空可选项仍可能省略 |
因此不能用某个详细键缺失推断模型从未持有该信息。普通读取清单时先确认输出模式,再查看键是否存在;不要为读取不存在的明细盲目索引字典。当前AnalysisRunner生成摘要模式元数据;配置diagnostics只接受trace、integrity、retain_work,不存在detailed或detailed_diagnostics配置开关。上表说明RunMetadata模型的序列化分支,不代表公开运行会填充所有模型字段。可用诊断设置见执行设置。
当前公开Runner的metadata.can_sources和metadata.text_can_sources均为空元组。这两个字段用于接收调用方明确提供的来源明细,不能根据字段名假定运行后一定有值。需要核对实际输入诊断时,使用当前支持的diagnostics配置和对应结果,见运行参数;仅将元数据转换为详细模式不会补出缺失明细。
为什么运行成功却没有事件
命令完成只表示任务没有执行错误。CLI 的 analysis_outcome 和运行清单的
run.analysis_outcome 说明业务结果;Python 可读
result.metadata.analysis_outcome.to_dict()。这些信息随原有计算累计,不另扫输入。
| 规则状态 | 含义与检查方向 |
|---|---|
no_observation |
没有规则所需观测;检查输入、通道、ID和信号,unobserved_signals列出未见到的信号 |
insufficient_data |
有数据,但未知或失效区间妨碍判断;检查缺值、无效码和有效期 |
condition_not_met |
有可判断的数据,条件没有成立 |
duration_not_met |
条件曾成立,但没有达到所选的持续时间要求 |
events_found |
已生成事件;仍需查看计算结果的状态,不能据此认为全部数据完整 |
no_event |
其他规则没有形成事件,例如没有出现所需边沿 |
event_count 是实际事件数;has_unknown 表示规则处理过程中出现过未知,
它可以与已有事件并存。calculations 中的 complete、partial、indeterminate
分别计数已写出的计算行,no_observation 是其中无观测行的数量,不是第四类互斥状态。
概况用于定位问题,不替代各行的 reason 和 quality。
事件起止与能量通过本页前述 event_id / parent_id 关联;不在每行计算结果中
重复保存事件时间。可直接运行的例子见条件持续超过60秒后积分。