import json from pathlib import Path import numpy as np class HapticFeatureExtractor: def __init__(self, config): self.config = config self.window_size = int(config["window_size"]) self.padding_value = float(config.get("padding_value", 0.0)) self.return_attention_mask = bool(config.get("return_attention_mask", True)) normalization = config.get("normalization", {}) self.mean = np.asarray(normalization.get("mean", []), dtype=np.float32) self.std = np.asarray(normalization.get("std", []), dtype=np.float32) @classmethod def from_pretrained(cls, root): root_path = Path(root) config_path = root_path / "preprocessor" / "preprocessor_config.json" with config_path.open("r", encoding="utf-8") as handle: config = json.load(handle) return cls(config) def _normalize(self, values): if not self.config.get("normalize", True): return values if self.mean.size == 0 or self.std.size == 0: return values denom = np.where(self.std == 0, 1.0, self.std) return (values - self.mean) / denom def __call__(self, values): values = np.asarray(values, dtype=np.float32) if values.ndim != 2: raise ValueError("Expected input shape [sequence_length, num_channels].") values = self._normalize(values) length, channels = values.shape if length >= self.window_size: trimmed = values[: self.window_size] attention_mask = np.ones(self.window_size, dtype=np.int64) else: pad_amount = self.window_size - length padding = np.full((pad_amount, channels), self.padding_value, dtype=np.float32) trimmed = np.concatenate([values, padding], axis=0) attention_mask = np.concatenate( [ np.ones(length, dtype=np.int64), np.zeros(pad_amount, dtype=np.int64), ] ) result = {"input_values": trimmed} if self.return_attention_mask: result["attention_mask"] = attention_mask return result