数据布局

本页描述 sqzc3d 在 materialize(内存化)时使用的默认数组布局。

目标是让 shape 与内存顺序对下游代码“可预测”。

30 秒版本:

  • points:(T, P, 3),并且永远搭配同索引的 points_valid (T, P)

  • analogs:默认 (C, N),并且永远搭配同布局的 analogs_valid (C, N)

  • layout="tcs" 更像“看起来方便”的视图;底层连续存储还是 layout="CN"

形象化:把 C3D 当成两张表(points 表 + analogs 表),你关心的首先是“表的形状”和“如何索引”。

点轨迹

这里的 points 指的是 marker 的三维轨迹,也就是“点轨迹”。

Materialize 后 points 的约定:

  • Layout:frame-major(按帧优先)

  • Pack:AoS XYZ,并搭配独立的 valid mask

在 Python 中,默认 Chunk.points(...) 返回:

  • points:shape (T, P, 3),dtype float64

  • points_valid:shape (T, P),dtype uint8

import sqzc3d as sq

v = sq.read("trial.c3d")
points = v.points
valid = v.points_valid

# 例:对单个 marker 过滤 invalid samples
p = v.point["LANK"]                 # (T, 3)
pv = v.point_valid["LANK"]          # (T,)
p_clean = p[pv != 0]

在 C API 中,sqzc3d_points_view_frames(...) 以 view 的形式暴露同一块内存:

  • view.points_xyz(T, P, 3),frame-major,连续(contiguous)

  • view.points_valid(T, P),连续(contiguous)

模拟通道

这里的 analogs 指的是“模拟通道”,比如地反力/力矩、EMG 等。

Materialize 后 analogs 默认是 channel-major(按通道优先):

  • Layout:(C, N),其中 N = T * S

  • S = n_analog_by_frame(每帧的 subframes 数)

在 Python 中:

import sqzc3d

dec = sqzc3d.Decoder("trial.c3d")
chunk = dec.read()
dec.close()

values_cn, valid_cn = chunk.analogs(layout="CN")   # (C, N)
values_tcs, valid_tcs = chunk.analogs(layout="tcs")  # (T, C, S) (strided view helper)

备注:

  • layout="CN" 是连续(contiguous)的。

  • layout="tcs" 是一个 strided view:它基于底层 (C, N) 存储提供更方便的 frame 视角。

拷贝 vs 视图

这里的 view 指“共享同一块底层内存的视角”,不发生额外拷贝。

sqzc3d 会避免隐式的 gathers/copies:

  • 对连续选择可以返回 view(copy=False)。

  • 对非连续选择必须 copy=True

这样可以让性能开销显式化,并保持内存行为可预测。