Check for a valid pos array and transform it to a more usable form.
(pos, coord_frame, raw, st_fixed)
| 1215 | |
| 1216 | |
| 1217 | def _check_pos(pos, coord_frame, raw, st_fixed): |
| 1218 | """Check for a valid pos array and transform it to a more usable form.""" |
| 1219 | _validate_type(pos, (np.ndarray, None), "head_pos") |
| 1220 | if pos is None: |
| 1221 | pos = np.empty((0, 10)) |
| 1222 | elif coord_frame != "head": |
| 1223 | raise ValueError('positions can only be used if coord_frame="head"') |
| 1224 | if not st_fixed: |
| 1225 | warn("st_fixed=False is untested, use with caution!") |
| 1226 | _validate_type(pos, np.ndarray, "head_pos") |
| 1227 | if pos.ndim != 2 or pos.shape[1] != 10: |
| 1228 | raise ValueError("pos must be an array of shape (N, 10)") |
| 1229 | t = pos[:, 0] |
| 1230 | if not np.array_equal(t, np.unique(t)): |
| 1231 | raise ValueError("Time points must unique and in ascending order") |
| 1232 | # We need an extra 1e-3 (1 ms) here because MaxFilter outputs values |
| 1233 | # only out to 3 decimal places |
| 1234 | if len(pos) > 0: |
| 1235 | if not _time_mask( |
| 1236 | t, tmin=raw._first_time - 1e-3, tmax=None, sfreq=raw.info["sfreq"] |
| 1237 | ).all(): |
| 1238 | raise ValueError( |
| 1239 | "Head position time points must be greater than " |
| 1240 | f"first sample offset, but found {t[0]:0.4f} < {raw._first_time:0.4f}" |
| 1241 | ) |
| 1242 | t = t - raw._first_time |
| 1243 | if len(t) == 0 or t[0] >= 0.5 / raw.info["sfreq"]: |
| 1244 | # Prepend the existing dev_head_t to make movecomp easier |
| 1245 | t = np.concatenate([[0.0], t]) |
| 1246 | trans = raw.info["dev_head_t"] |
| 1247 | trans = np.eye(4) if trans is None else trans["trans"] |
| 1248 | dev_head_pos = np.concatenate( |
| 1249 | [t[[0]], rot_to_quat(trans[:3, :3]), trans[:3, 3], [0, 0, 0]] |
| 1250 | ) |
| 1251 | pos = np.concatenate([dev_head_pos[np.newaxis], pos]) |
| 1252 | # now that we've either prepended dev_head_t or know it's zero-like, make it zero |
| 1253 | t[0] = 0 |
| 1254 | max_dist = np.sqrt(np.sum(pos[:, 4:7] ** 2, axis=1)).max() |
| 1255 | if max_dist > 1.0: |
| 1256 | warn( |
| 1257 | f"Found a distance greater than 1 m ({max_dist:0.3g} m) from the device " |
| 1258 | "origin, positions may be invalid and Maxwell filtering could " |
| 1259 | "fail" |
| 1260 | ) |
| 1261 | t[0] = 0 |
| 1262 | dev_head_ts = np.zeros((len(t), 4, 4)) |
| 1263 | dev_head_ts[:, 3, 3] = 1.0 |
| 1264 | dev_head_ts[:, :3, 3] = pos[:, 4:7] |
| 1265 | dev_head_ts[:, :3, :3] = quat_to_rot(pos[:, 1:4]) |
| 1266 | t = raw.time_as_index(t, use_rounding=True) |
| 1267 | pos = [dev_head_ts, t, pos[:, 1:]] |
| 1268 | assert all(len(p) == len(pos[0]) for p in pos) |
| 1269 | return pos |
| 1270 | |
| 1271 | |
| 1272 | def _get_decomp( |
no test coverage detected