Python API
Kshana提供一流的Python应用程序编程接口(API),基于PyO3和maturin构建。其abi3 wheel针对稳定的Python应用二进制接口(ABI)构建,因此每个平台只需一个wheel即可适用于CPython ≥ 3.9;wheel覆盖Linux、macOS和Windows,每种均提供x86-64与64位ARM版本(见WHEEL_TAGS.md)。随附的类型存根(kshana.pyi+py.typed)为编辑器及mypy/pyright提供完整的类型信息。
pip install kshana # from the Python Package Index, PyPI (release wheels)
# or, from a checkout:
pip install maturin && maturin develop --features python
快速入门#
请在仓库检出目录的根目录下运行这些代码片段:它们读取scenarios/下的场景文件。NumPy那一行需要pip install numpy。
import kshana
toml = open("scenarios/clock-holdover.toml").read()
# Typed result with a parsed-dict accessor:
out = kshana.run_typed(toml)
print(out.summary)
data = out.data() # a Python dict — no JSON re-parsing
fom = data["quantum"]["fom"] # figures of merit, quantum side
classical_fom = data["classical"]["fom"] # … and the classical baseline
print(out.json[:80], "...") # raw JSON also available
open("chart.svg", "w").write(out.svg) # the chart SVG
# NumPy arrays straight from the result (NumPy is imported on call; it is not a
# dependency of the package):
curve = out.columns("quantum.adev_curve") # {"tau_s": ndarray, "adev": ndarray, ...}
adev = curve["adev"]
everything = out.series() # every record series, keyed by path
界面#
| 符号 | 签名 | 返回值 |
|---|---|---|
run_typed |
(toml: str) -> RunOutput |
带类型的结果(.json、.svg、.summary、.csv、.data()、.array()、.columns()、.series()、.write_csv()) |
run |
(toml: str) -> str |
以JSON(JavaScript对象表示法)字符串形式给出的结果文档 |
run_full |
(toml: str) -> tuple[str, str, str] |
(json, svg, summary) |
scenario_kinds |
() -> list[dict] |
可用的场景类别及元数据(已解析) |
list_kinds |
() -> str |
同样的元数据,以一个JSON数组字符串给出,而非列表(为现有调用方保留;解析后的列表请使用scenario_kinds) |
validate_toml |
(toml: str) -> list[str] |
错误信息(有效时为空) |
error_kind |
(toml: str) -> str | None |
失败类别标签(invalid_input、non_convergence、unsupported或io_error),成功时为None |
version / __version__ |
() -> str / str |
引擎版本 |
receiver_trust |
(toml: str) -> RunOutput |
评估由receiver-trust场景描述的真实接收机日志:结果文档、逐历元信任度CSV、图表和摘要;[platform] kind = "vessel"表会加入海事监测器以及带原因的0至100信任度评分(咨询性,仅供参考) |
receiver_trust_replay |
(session_toml, nmea) -> dict |
按实时模式的评分方式对一段有限的NMEA摘录评分:逐历元状态、0至100的评分及原因、摘要(无套接字,无门限;咨询性,仅供参考) |
assess_vessel_log |
(session_toml, log) -> dict |
以批处理方式运行的船舶NMEA日志:评分模型以及每个历元的评分和扣分项(咨询性,仅供参考) |
jammertest_import |
(catalog_json, plans, log_start_utc, location=None, local_offset_h=2.0, year=None) -> dict |
已发布的Jammertest目录和计划,作为计划真值事件(events_toml、events);是计划时段,而非实际播发时间的记录 |
jammertest_score |
(session_toml, log, catalog_json, plans, location=None, local_offset_h=2.0, log_start_utc=None, year=None, recover_hold_s=10.0, guard_s=60.0) -> dict |
对照该时间表给接收机日志评分:逐项测试的延迟、漏检、恢复时间、虚警(MODELLED;签名证据包需使用命令行) |
evidence_create |
(session_toml, log, from_s, to_s, title=None, created_utc=None, seed_hex=None) -> dict |
针对日志某一时间窗、在内存中生成的签名证据包:files、public_key、seed_hex(请保密);这是一份技术记录,而非法律意见 |
evidence_verify |
(files, public_key=None, full_log=None, require_timestamp=False) -> dict |
验证证据包:哈希、链、签名,以及可选的受信任签名方、完整日志和时间戳;verdict为verified、intact-signer-not-pinned(未提供公钥:包完整,签名方未确认)或failed |
export_sp3, export_omm, export_oem |
(toml) -> str |
CLI的--export-sp3/-omm/-oem产物(文本形式) |
export_formats |
(toml) -> list[dict] |
某个场景适用哪些互操作格式,无需运行该场景 |
export_scenario |
(toml, format) -> dict |
在内存中生成czml、kml、geojson、stk或sigmf:{format, spec_url, files},每个文件为{suffix, bytes, sha256, encoding, content}(utf-8文本或base64) |
import_route |
(toml, geojson) -> str |
写入航点轨迹场景的GeoJSON航线(--import-route) |
animate_scenario |
(toml, format="svg", fps=None, duration_s=None, width=None) -> dict |
以动画SVG、HTML播放器或最多120个SVG帧形式给出本次运行的时间序列:{summary, files} |
list_examples, get_example |
(kind=None) -> dict, (name) -> str |
内置的参考场景及其TOML |
evidence_attach_timestamp |
(files, token, replace=False) -> dict |
在内存中把RFC 3161令牌(字节或base64)绑定到证据包:{files, notes};该包仍须通过验证;不检查授权机构的签名 |
evidence_keygen |
() -> dict |
内存中的新签名密钥:seed_hex(PRIVATE),public_key、fingerprint、warning;仅限Python |
iq_sweep |
(i, q, fs_hz, signal, prns, ..., pll_bws=None, dll_bws=None, spacings=None, coherents=None, design=None) -> dict |
用不同的环路设计回放同一份录制(iq sweep):给出每种设计和每个PRN的稳态抖动、锁定比例和C/N0;每个PRN只做一次捕获,所有通道使用同一批采样 |
iq_info, iq_inventory |
(path, hash=False) -> dict, (directory, recursive=False, hash=False) -> list |
描述一份录制,或文件夹中的每一份录制(读取文件;hash会完整读取) |
bench_export |
(toml, epoch=None) -> dict |
在内存中为实验室GNSS仿真器生成某个场景的载体运动和事件:{files: {suffix: text}, notes, notice};类别gnss-ins、jamming、gnss-sim;不写出任何信号,请将notice与这些文件放在一起 |
compliance_report |
(runs) -> dict |
由结果文本填充的公开框架映射:runs是{label, result, scenario?}字典的列表(文本,至多64个);返回{report, markdown};每一行的status表明这些运行为其各项能力提供证据支持(supports evidence for),而不表示满足某个框架;任何展示都须附带report["statement"] |
compliance_mapping |
(sources=False) -> str |
以Markdown形式给出的静态映射表(或源文档),以声明开头 |
standards_pack_list |
() -> dict |
标准包(标识、标题、框架、测试数量)及一则声明;每个包依据运行前已声明的判据来衡量建模场景 |
standards_pack_run |
(pack_id) -> dict |
运行一个包:每项测试为MET、NOT MET或NEEDS INPUT,并附实测值与期望值,另在markdown下给出Markdown格式的报告;对未知标识抛出ValueError |
lunanet_afs_check_spec |
() -> dict |
对照LSIS-AFS V1.0印出的表格和算例核对LunaNet AFS实现(判据B1至B10;B4报告一处已固定的未达标项) |
lunanet_afs_check_symbols |
(symbols, max_sp_errors=0) -> dict |
检查一段AFS符号流(由0和1组成的文本)的同步码型、SB1解码、FID、TOI连续性和间隔;子帧2至4的LDPC和CRC-24Q未经验证 |
lunanet_afs_generate |
(frames=1, toi0=0) -> str |
带占位子帧的测试符号流(不是波形) |
evidence_round_trip |
(scoring_toml, scenario_toml, conditions, log, from_s, to_s, title=None, created_utc=None, seed_hex=None) -> dict |
以哈希关联场景、测试条件(docs/spec/TEST-CONDITIONS.md)、接收机日志和评分的签名实验室往返证据包;形式为evidence_create |
bench_score |
(truth_json, predictions_json, threshold=None) -> str |
由真值文件和预测文件生成的kshana-bench结果文件(JSON文本);MODELLED |
bench_leaderboard |
(results: list[str]) -> str |
渲染为静态排行榜页面(HTML)的kshana-bench结果文件 |
osnma_verify |
(data, format="", start_gst=None, merkle_root_hex="", public_keys=None, reference_time=None, max_time_error=None) -> dict |
在内存中对I/NAV页面或UBX流进行Galileo OSNMA认证:即kshana osnma verify --json所打印的字典,其advisory字段中带有咨询性声明;仅供参考,不是导航完好性服务 |
sky_geometry |
(request) -> dict |
某站点在随方位变化的天际线下所见的卫星:每颗卫星的visible/masked、GDOP、PDOP、HDOP、VDOP、TDOP,东北天协因子与协方差,以及水平误差椭圆;request为JSON或TOML文本,或字典(site、time_s、systems、tle、satellites、mask_deg、skyline、clock、sigma_uere_m、confidence);可见性判定和椭圆已对照独立的库核对,其余部分为MODELLED,结果附带咨询性声明(sky_source、sky_statement说明天空是具代表性的,还是来自根数集) |
sky_monte_carlo |
(request, seed=0, n=1000) -> dict |
在request的可见集上做n次(1至5000)带随机种子的最小二乘误差计算,并给出其经验协方差、RMS以及落在95 % 椭圆内的比例 |
skyline_presets |
() -> list[dict] |
天际线预设(city-street、harbour-approach、fjord、container-terminal),附其REPRESENTATIVE标签、出处,以及方位角每一度的遮挡截止;是具代表性的几何形状,而非实地测绘 |
skyline_profile |
(skyline) -> dict |
将天际线部分(表格、街道峡谷、扇区、地形)归约为引擎所用的、规范化的360项表 |
skyplot_svg |
(request) -> str |
request的天空图,以静态SVG文本形式给出 |
trust_telemetry |
(input, format, host="", input_kind="jsonl", expose_position=False, syslog_all=False, unix_nano=0) -> str |
将信任度数据流(jsonl)或receiver-trust结果输出为Prometheus文本、CEF或LEEF syslog行,或OTLP JSON载荷,使用kshana trust-telemetry编码器;不发送任何内容,也不读取时钟(syslog行不带时间戳) |
interference_map |
(source, csv, dataset, cell_deg=None, licence=None, licence_url=None, attribution=None, land_geojson=None) -> list[dict] |
由ADS-B或AIS的CSV文本生成GNSS干扰地图:每个UTC日一个字典,含kshana-interference-map/v1 GeoJSON(仅为汇总;某个降级单元并不表明干扰是其成因) |
interference_emitter_regions |
(source, csv, dataset, licence=None, licence_url=None, attribution=None, land_geojson=None) -> dict |
根据ADS-B或AIS的CSV文本估计发射源区域:{stem, geojson, summary, csv, svg, sessions_published, sessions_withheld},每项都标为MODELLED;区域以所述置信度给出,带质心和不确定性椭圆,绝不是单独一个点;仅作汇总,区域不是任何人的位置,也不是对成因的结论 |
route_exposure |
(route, maps, date_from=None, date_to=None) -> str |
某条航线穿过这些地图中降级单元的占比,以JSON文本给出(不是预报;未观测到的单元不能作为航线畅通的证据) |
nmea_training |
(toml, seed=None) -> dict |
用于船员培训的合成驾驶台NMEA,以及教员日志(nmea、log_json、log_text);仅为文本,绝不用于船舶的实时导航系统 |
iq_signals |
() -> list[str] |
iq_scene、iq_acquire和iq_track所接受的GNSS IQ信号名称(gps-l1ca、galileo-e1b、glonass-l1of等) |
iq_scene |
(fs_hz, duration_s, signal, prns, **options) -> dict |
内存中的多卫星GNSS IQ场景:samples_i/samples_q以及逐历元的truth |
iq_scene_broadcast |
(fs_hz, window_s, nav_text, rx_lat, rx_lon, rx_alt, **options) -> dict |
同上,但每颗GPS卫星采用RINEX(接收机无关交换格式)导航电文中的广播星历几何 |
iq_acquire |
(i, q, fs_hz, signal, prns, **options) -> list[dict] |
对每个PRN(伪随机噪声码)的FFT(快速傅里叶变换)捕获:多普勒、码相位、统计量、门限 |
iq_acq_surface |
(i, q, fs_hz, signal, prn, **options) -> dict |
单个PRN的完整捕获曲面(kshana.acq-surface/1):rows[doppler][lag]相关功率、峰值以及两种精细多普勒细化(parabolic、fine_search) |
iq_track |
(i, q, fs_hz, signal, prns, **options) -> dict |
先捕获,再跟踪每个PRN:逐历元的多普勒、码相位、锁定指示、C/N0、即时相关器 |
iq_frontend |
(i, q, fs_hz, **options) -> dict |
对复采样依次施加的接收机前端链(带通、陷波、消隐、切除、AGC(自动增益控制)、量化器) |
iq_labfit |
(toml: str) -> dict |
将跟踪环失锁模型拟合到接收机信任度时间线(iq-labfit场景) |
iq_loop_designs |
(toml) -> list[dict] |
将kshana.loop-design/1文件(路径或TOML文本)解析为已确定的各设计,每个设计带有其name和hash;文件无效时抛出ValueError |
iq_read_epochs |
(path) -> dict |
读取二进制跟踪历元文件(kshana.track-epoch/1,由kshana iq track --epochs写出):得到header以及records中每个历元一个字典 |
iq_monitor |
(path, signal=None, prns=None, power=False, spectral=False, settings=None, ...) -> dict |
对一份录制一次流式遍历完成的IQ检测监测(iq monitor):series、events、spectra和notes;读取文件 |
iq_test_conditions |
(conditions) -> dict |
验证实验室测试条件文件(kshana.test-conditions/1,TOML或JSON,路径或文本),并返回其已确定的内容及hash |
iq_campaign |
(campaign, out_dir, workers=0, resume=True, max_cells=None, dry_run=False) -> dict |
将实验室回放测评活动(kshana.campaign/1)运行到out_dir,效果同kshana iq campaign;已完成的单元会被跳过;全部单元完成后返回单元计数、失败项和digest |
iq_campaign_report |
(out_dir) -> dict |
根据测评活动的各单元重建其评分卡、HTML报告和摘要:单元数与行数、未达判据的行以及digest |
GNSS IQ与接收机信任度的函数签名#
完整的函数签名,以kshana.pyi所述为准(必需参数之后的每个关键字参数都有默认值;存根中的文档字符串给出各自的含义)。数组请用numpy.asarray(...)包装samples_i/samples_q列表以及i/q输入。
def receiver_trust(toml: str) -> RunOutput: ...
def receiver_trust_replay(session_toml: str, nmea: str | bytes) -> dict: ...
def assess_vessel_log(session_toml: str, log: str | bytes) -> dict: ...
def jammertest_import(catalog_json: str, plans: list[str], log_start_utc: str, location: int | None = None,
local_offset_h: float = 2.0, year: int | None = None) -> dict: ...
def jammertest_score(session_toml: str, log: str | bytes, catalog_json: str, plans: list[str],
location: int | None = None, local_offset_h: float = 2.0,
log_start_utc: str | None = None, year: int | None = None,
recover_hold_s: float = 10.0, guard_s: float = 60.0) -> dict: ...
def evidence_create(session_toml: str, log: str | bytes, from_s: float, to_s: float,
title: str | None = None, created_utc: str | None = None,
seed_hex: str | None = None) -> dict: ...
def evidence_verify(files: dict[str, str | bytes], public_key: str | None = None,
full_log: str | bytes | None = None,
require_timestamp: bool = False) -> dict: ...
def interference_map(source: str, csv: str, dataset: str, cell_deg: float | None = None,
licence: str | None = None, licence_url: str | None = None,
attribution: str | None = None, land_geojson: str | None = None) -> list[dict]: ...
def route_exposure(route: str, maps: list[str], date_from: str | None = None,
date_to: str | None = None) -> str: ...
def export_sp3(toml: str) -> str: ...
def export_omm(toml: str) -> str: ...
def export_oem(toml: str) -> str: ...
def export_formats(toml: str) -> list[dict]: ...
def export_scenario(toml: str, format: str) -> dict: ...
def import_route(toml: str, geojson: str) -> str: ...
def animate_scenario(toml: str, format: str = "svg", fps: int | None = None,
duration_s: float | None = None, width: int | None = None) -> dict: ...
def list_examples(kind: str | None = None) -> dict: ...
def get_example(name: str) -> str: ...
def evidence_attach_timestamp(files: dict[str, str | bytes], token: str | bytes,
replace: bool = False) -> dict: ...
def evidence_keygen() -> dict: ...
def iq_sweep(i: list[float], q: list[float], fs_hz: float, signal: str, prns: list[int],
**options) -> dict: ...
def iq_info(path: str, hash: bool = False) -> dict: ...
def iq_inventory(directory: str, recursive: bool = False, hash: bool = False) -> list[dict]: ...
def bench_export(toml: str, epoch: str | None = None) -> dict: ...
def compliance_report(runs: list[dict[str, str]]) -> dict: ...
def compliance_mapping(sources: bool = False) -> str: ...
def standards_pack_list() -> dict[str, Any]: ...
def standards_pack_run(pack_id: str) -> dict[str, Any]: ...
def lunanet_afs_check_spec() -> dict[str, Any]: ...
def lunanet_afs_check_symbols(symbols: str, max_sp_errors: int = 0) -> dict[str, Any]: ...
def lunanet_afs_generate(frames: int = 1, toi0: int = 0) -> str: ...
def evidence_round_trip(scoring_toml: str, scenario_toml: str, conditions: str, log: str | bytes, from_s: float, to_s: float, title: Optional[str] = None, created_utc: Optional[str] = None, seed_hex: Optional[str] = None) -> dict[str, Any]: ...
def bench_score(truth_json: str, predictions_json: str, threshold: float | None = None) -> str: ...
def bench_leaderboard(results: list[str]) -> str: ...
def osnma_verify(data: bytes | str, format: str = "", start_gst: int | None = None,
merkle_root_hex: str = "", public_keys: list[str] | None = None,
reference_time: int | None = None, max_time_error: int | None = None) -> dict: ...
def sky_geometry(request: str | dict[str, Any]) -> dict[str, Any]: ...
def sky_monte_carlo(request: str | dict[str, Any], seed: int = 0, n: int = 1000) -> dict[str, Any]: ...
def skyline_presets() -> list[dict[str, Any]]: ...
def skyline_profile(skyline: str | dict[str, Any]) -> dict[str, Any]: ...
def skyplot_svg(request: str | dict[str, Any]) -> str: ...
def trust_telemetry(input: str, format: str, host: str = "", input_kind: str = "jsonl",
expose_position: bool = False, syslog_all: bool = False,
unix_nano: int = 0) -> str: ...
def nmea_training(toml: str, seed: int | None = None) -> dict[str, str]: ...
def iq_signals() -> list[str]: ...
def iq_scene(
fs_hz: float,
duration_s: float,
signal: str,
prns: list[int],
dopplers: Optional[list[float]] = ...,
cn0_dbhz: Optional[float] = ...,
center_hz: Optional[float] = ...,
if_hz: float = ...,
noise: bool = ...,
noise_figure_db: float = ...,
seed: int = ...,
data: bool = ...,
threads: int = ...,
iono_stec: Optional[float] = ...,
iono_vtec: Optional[float] = ...,
iono_klobuchar: bool = ...,
tropo: bool = ...,
tropo_doy: float = ...,
s4: Optional[float] = ...,
scint_tau0: float = ...,
sigma_phi: float = ...,
multipath_height: Optional[float] = ...,
multipath_ground: str = ...,
land_mobile: bool = ...,
nlos: bool = ...,
) -> dict[str, Any]: ...
def iq_scene_broadcast(
fs_hz: float,
window_s: float,
nav_text: str,
rx_lat: float,
rx_lon: float,
rx_alt: float,
prns: Optional[list[int]] = ...,
start_tow: float = ...,
cn0_dbhz: Optional[float] = ...,
center_hz: Optional[float] = ...,
if_hz: float = ...,
noise: bool = ...,
noise_figure_db: float = ...,
seed: int = ...,
mask_deg: float = ...,
threads: int = ...,
) -> dict[str, Any]: ...
def iq_acquire(
i: list[float],
q: list[float],
fs_hz: float,
signal: str,
prns: list[int],
if_hz: float = ...,
center_hz: Optional[float] = ...,
coherent: int = ...,
noncoherent: int = ...,
doppler_max: float = ...,
doppler_step: Optional[float] = ...,
pfa: float = ...,
) -> list[dict[str, Any]]: ...
def iq_acq_surface(
i: list[float],
q: list[float],
fs_hz: float,
signal: str,
prn: int,
if_hz: float = ...,
center_hz: Optional[float] = ...,
coherent: int = ...,
noncoherent: int = ...,
doppler_max: float = ...,
doppler_step: Optional[float] = ...,
pfa: float = ...,
) -> dict[str, Any]: ...
def iq_track(
i: list[float],
q: list[float],
fs_hz: float,
signal: str,
prns: list[int],
if_hz: float = ...,
center_hz: Optional[float] = ...,
pll_bw: Optional[float] = ...,
fll_bw: Optional[float] = ...,
dll_bw: Optional[float] = ...,
spacing: Optional[float] = ...,
coherent: Optional[int] = ...,
periods_per_bit: Optional[int] = ...,
acq_coherent: Optional[int] = ...,
acq_noncoherent: int = ...,
doppler_max: float = ...,
max_seconds: Optional[float] = ...,
) -> dict[str, Any]: ...
def iq_frontend(
i: list[float],
q: list[float],
fs_hz: float,
bandpass_lo: Optional[float] = ...,
bandpass_hi: Optional[float] = ...,
bandpass_transition: Optional[float] = ...,
bandpass_atten: float = ...,
notch: bool = ...,
notch_r: float = ...,
notch_mu: float = ...,
blank: Optional[float] = ...,
blank_hold: int = ...,
excise: bool = ...,
excise_fft: int = ...,
excise_pfa: float = ...,
agc: bool = ...,
agc_tau: float = ...,
bits: Optional[int] = ...,
quant_step: Optional[float] = ...,
no_agc: bool = ...,
) -> dict[str, Any]: ...
def iq_labfit(toml: str) -> dict[str, Any]: ...
def iq_loop_designs(toml: str) -> list[dict[str, Any]]: ...
def iq_read_epochs(path: str) -> dict[str, Any]: ...
def iq_monitor(path: str, signal: Optional[str] = ..., prns: Optional[list[int]] = ...,
power: bool = ..., spectral: bool = ..., settings: Optional[str] = ...,
**options) -> dict[str, Any]: ...
def iq_test_conditions(conditions: str) -> dict[str, Any]: ...
def iq_campaign(campaign: str, out_dir: str, workers: int = 0, resume: bool = True,
max_cells: Optional[int] = None, dry_run: bool = False) -> dict[str, Any]: ...
def iq_campaign_report(out_dir: str) -> dict[str, Any]: ...
通过Python运行实验室回放测评活动,然后生成其报告(测评活动文件及其录制由你自己提供;已完成的单元在下次调用时会被跳过;iq_read_epochs读取由kshana iq track --epochs运行写出的跟踪历元文件):
import kshana
summary = kshana.iq_campaign("lab.campaign.toml", "campaign-out", workers=4)
report = kshana.iq_campaign_report("campaign-out")
print(report["digest"]) # None until every cell is done
iq_track的acq_coherent设定交接捕获相干积分多少个码周期。自0.33.0起,其默认值为None,表示自动:约4 ms(对1 ms码如GPS L1 C/A为4个周期,对4 ms或更长的码为1个周期),使通道的起点足够接近,以便频率环牵引入锁;acq_coherent=1则保留0.32的单周期搜索。
类型#
kshana.pyi为检查器(mypy、pyright)给出封闭词汇表的类型:ScenarioKind(所有类别名称,一个Literal)、ErrorKind(error_kind返回的四种标签)、ProvenanceClass,以及TypedDict类型的KindMeta(scenario_kinds()返回其列表)和FieldUnit(结果units块中的一项,它扩展了必需键基类_FieldUnitBase)。它们仅供类型检查器使用,运行时不可导入;tests/typed_api_sync.rs使它们与引擎的列表保持一致。
from typing import TYPE_CHECKING
import kshana
if TYPE_CHECKING:
from kshana import ScenarioKind
names: "list[ScenarioKind]" = [k["name"] for k in kshana.scenario_kinds()]
RunOutput#
| 成员 | 类型 | 备注 |
|---|---|---|
.json |
str |
完整结果文档(JSON) |
.svg |
str |
独立的图表SVG(可缩放矢量图形) |
.summary |
str |
一行式人类可读摘要 |
.csv |
str | None |
可复现性表,适用于会输出该表的类别(见下文) |
.data() |
dict |
解析为Python字典的结果(见下文关于结构的说明) |
.array(path) |
numpy.ndarray |
path处的数值列表(点分路径"points.0.coords",或JSON Pointer "/points/0/coords"):数字为1维,等长数值列表为2维 |
.columns(path) |
dict[str, numpy.ndarray] |
path处的记录列表(时间序列),对每个在所有记录中均为数字的字段给出一个数组 |
.series() |
dict[str, dict[str, numpy.ndarray]] |
每个含数值字段的记录列表,以点分路径为键,每个均为.columns |
.write_csv(path) |
int |
将该表写入path;返回写入的字节数;若该类别不输出表,则返回0(且不写入任何内容) |
可复现性表#
realtime-frame-eop、lunar-time-budget、lunar-jamming、telecom-timing和leo-navmsg总会发布一张表;moonlight-service-volume在配置了导出站点(export_site_lat_deg+export_site_lon_deg)时发布一张。其他每个类别都返回csv = None。文本与CLI(命令行界面)写出的<scenario>.table.csv字节完全相同,因此审阅者从wheel复现已发布的表时无需退回到命令行:
import kshana
out = kshana.run_typed(open("scenarios/realtime-frame-eop.toml").read())
if out.csv is not None:
print(out.write_csv("table.csv"), "bytes written")
结果结构#
性能指标和时间序列位于各运行侧,而不在顶层。对于一次时钟运行,其文档为:
schema_version engine_version scenario_hash seed threshold_ns units figure_tiers
quantum → spec · series · fom · adev_curve · filter_health
classical → spec · series · fom · adev_curve · filter_health
因此性能指标是data["quantum"]["fom"],绝不是data["figures_of_merit"]。其他类别输出各自的数据包;包含单位和来源指针的完整逐字段参考是field-units-schema.json,读者指南是SCHEMA.md。
备注#
validate_toml和error_kind会执行该场景,因此能暴露解析、配置以及运行时错误。它们从不抛出异常。- 场景无效时,
run/run_typed抛出ValueError。 - 结果是可复现的:场景带有其
seed,引擎记录一个scenario_hash,因此在同一平台上相同输入产生字节级相同的输出(见REPRODUCIBILITY.md)。 .array、.columns和.series返回的恰好是.data()所给出的同一批数值的numpy.asarray(...)(相同dtype,逐位一致;tests/python/test_numpy_runoutput.py)。它们在被调用时才导入NumPy,没有NumPy时抛出ImportError;NumPy不属于该包的运行时依赖。KeyError表示路径不存在,ValueError表示该处的值不是数值数组(或不是记录列表)。可运行的notebook位于notebooks/。
不在Python中:长时间运行的进程#
kshana receiver-trust live(带门限和可选--listen TCP服务器的流式进程)、遥测导出器(Prometheus、OTLP、syslog;docs/TRUST-TELEMETRY.md)以及kshana nmea-scenario --tcp/--udp流式传输仅限命令行:绑定在调用返回时即返回,不会保持套接字打开。Python涵盖其中每一项的批处理形式:日志用receiver_trust,流摘录用receiver_trust_replay(给出评分和状态;不应用门限),生成的文本用nmea_training。