def test_create_and_read_c3d_with_nan(): # Load an empty c3d structure c3d = ezc3d.c3d() # Fill it with random data point_names = ("point1", "point2") point_frame_rate = 100 n_second = 2 points = np.random.rand(3, len(point_names), point_frame_rate * n_second) * np.nan analog_names = ("analog1", "analog2") analog_frame_rate = 1000 analogs = np.random.rand(1, len(analog_names), analog_frame_rate * n_second) * np.nan c3d["parameters"]["POINT"]["RATE"]["value"] = [100] c3d["parameters"]["POINT"]["LABELS"]["value"] = point_names c3d["data"]["points"] = points c3d["parameters"]["ANALOG"]["RATE"]["value"] = [1000] c3d["parameters"]["ANALOG"]["LABELS"]["value"] = analog_names c3d["data"]["analogs"] = analogs # Write and read back the data c3d.write("temporary.c3d") c3d_to_compare = ezc3d.c3d("temporary.c3d") # Compare the read c3d np.testing.assert_equal(np.sum(np.isnan(c3d_to_compare["data"]["points"])), 3 * len(point_names) * point_frame_rate * n_second) np.testing.assert_equal( np.sum(np.isnan(c3d_to_compare["data"]["analogs"])), len(analog_names) * analog_frame_rate * n_second)
def test_create_and_read_c3d_with_nan(): # Load an empty c3d structure c3d = ezc3d.c3d() # Fill it with random data point_names = ('point1', 'point2') point_frame_rate = 100 n_second = 2 points = np.random.rand(3, len(point_names), point_frame_rate * n_second) * np.nan analog_names = ('analog1', 'analog2') analog_frame_rate = 1000 analogs = np.random.rand(1, len(analog_names), analog_frame_rate * n_second) * np.nan c3d['parameters']['POINT']['RATE']['value'] = [100] c3d['parameters']['POINT']['LABELS']['value'] = point_names c3d['data']['points'] = points c3d['parameters']['ANALOG']['RATE']['value'] = [1000] c3d['parameters']['ANALOG']['LABELS']['value'] = analog_names c3d['data']['analogs'] = analogs # Write and read back the data c3d.write("temporary.c3d") c3d_to_compare = ezc3d.c3d("temporary.c3d") # Compare the read c3d np.testing.assert_equal(np.sum(np.isnan(c3d_to_compare['data']['points'])), 3 * len(point_names) * point_frame_rate * n_second) np.testing.assert_equal( np.sum(np.isnan(c3d_to_compare['data']['analogs'])), len(analog_names) * analog_frame_rate * n_second)
def test_deepcopy(): # Load an empty c3d structure c3d = ezc3d.c3d() # Fill it with random data point_names = ("point1", "point2", "point3", "point4", "point5") point_frame_rate = 100 n_second = 2 points = np.random.rand(4, len(point_names), point_frame_rate * n_second) points[3, :, :] = 1 analog_names = ("analog1", "analog2", "analog3", "analog4", "analog5", "analog6") analog_frame_rate = 1000 analogs = np.random.rand(1, len(analog_names), analog_frame_rate * n_second) c3d["parameters"]["POINT"]["RATE"]["value"] = [100] c3d["parameters"]["POINT"]["LABELS"]["value"] = point_names c3d["data"]["points"] = points c3d["parameters"]["ANALOG"]["RATE"]["value"] = [1000] c3d["parameters"]["ANALOG"]["LABELS"]["value"] = analog_names c3d["data"]["analogs"] = analogs # Add a custom parameter to the POINT group point_new_param = ("POINT", "newPointParam", (1.0, 2.0, 3.0)) c3d.add_parameter(point_new_param[0], point_new_param[1], point_new_param[2]) # Add a custom parameter a new group new_group_param = ("NewGroup", "newGroupParam", ["MyParam1", "MyParam2"]) c3d.add_parameter(new_group_param[0], new_group_param[1], new_group_param[2]) # Deepcopy the c3d c3d_deepcopied = deepcopy(c3d) # Change some of its values change_new_group_param = ("NewGroup", "newGroupParam", ["MyParam3", "MyParam4"]) c3d_deepcopied.add_parameter(change_new_group_param[0], change_new_group_param[1], change_new_group_param[2]) c3d_deepcopied["data"]["points"][:3, :, :] = 0 # Write the new file and read it back c3d_deepcopied.write("temporary.c3d") c3d_loaded = ezc3d.c3d("temporary.c3d") # Check that the new value changed, but not the old one assert c3d["parameters"]["NewGroup"]["newGroupParam"]["value"] == ["MyParam1", "MyParam2"] assert c3d_deepcopied["parameters"]["NewGroup"]["newGroupParam"]["value"] == ["MyParam3", "MyParam4"] assert c3d_loaded["parameters"]["NewGroup"]["newGroupParam"]["value"] == ["MyParam3", "MyParam4"] np.testing.assert_almost_equal( c3d["data"]["points"][:3, :, :] - c3d_deepcopied["data"]["points"][:3, :, :], c3d["data"]["points"][:3, :, :] ) np.testing.assert_almost_equal(c3d["data"]["points"][3, :, :], c3d_deepcopied["data"]["points"][3, :, :]) np.testing.assert_almost_equal( c3d["data"]["points"][:3, :, :] - c3d_loaded["data"]["points"][:3, :, :], c3d["data"]["points"][:3, :, :] ) np.testing.assert_almost_equal(c3d["data"]["points"][3, :, :], c3d_loaded["data"]["points"][3, :, :])
def test_add_events(): # Add an event to a file that does not have any before c3d = ezc3d.c3d("test/c3dTestFiles/Optotrak.c3d") c3d.add_event( [0, 0.1], label="MyNewEvent", context="Left", icon_id=2, subject="Me", description="Hey! This is new!", generic_flag=1, ) c3d.add_event([0, 0.2]) c3d.write("temporary.c3d") c3d_to_compare = ezc3d.c3d("temporary.c3d") np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["USED"]["value"][0], 2) np.testing.assert_almost_equal( c3d_to_compare["parameters"]["EVENT"]["TIMES"]["value"], [[0.0, 0.0], [0.1, 0.2]], decimal=6 ) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["CONTEXTS"]["value"], ["Left", ""]) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["LABELS"]["value"], ["MyNewEvent", ""]) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["DESCRIPTIONS"]["value"], ["Hey! This is new!", ""]) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["SUBJECTS"]["value"], ["Me", ""]) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["ICON_IDS"]["value"], [2, 0]) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["GENERIC_FLAGS"]["value"], [1, 0]) # Add an event to a file did have events before c3d = c3d_to_compare c3d.add_event( [0, 0.3], label="MySecondNewEvent", context="Right", icon_id=3, subject="You", description="Hey! This is new again!", generic_flag=2, ) c3d.add_event([0, 0.4]) c3d.write("temporary.c3d") c3d_to_compare = ezc3d.c3d("temporary.c3d") np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["USED"]["value"][0], 4) np.testing.assert_almost_equal( c3d_to_compare["parameters"]["EVENT"]["TIMES"]["value"], [[0.0, 0.0, 0.0, 0.0], [0.1, 0.2, 0.3, 0.4]], decimal=6 ) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["CONTEXTS"]["value"], ["Left", "", "Right", ""]) np.testing.assert_equal( c3d_to_compare["parameters"]["EVENT"]["LABELS"]["value"], ["MyNewEvent", "", "MySecondNewEvent", ""] ) np.testing.assert_equal( c3d_to_compare["parameters"]["EVENT"]["DESCRIPTIONS"]["value"], ["Hey! This is new!", "", "Hey! This is new again!", ""], ) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["SUBJECTS"]["value"], ["Me", "", "You", ""]) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["ICON_IDS"]["value"], [2, 0, 3, 0]) np.testing.assert_equal(c3d_to_compare["parameters"]["EVENT"]["GENERIC_FLAGS"]["value"], [1, 0, 2, 0])
def c3d_build_rebuild(request): base_folder = Path("test/c3dTestFiles") orig_file = Path(base_folder / (request.param + ".c3d")) rebuild_file = Path(base_folder / (request.param + "_after.c3d")) original = ezc3d.c3d(orig_file.as_posix()) original.write(rebuild_file.as_posix()) rebuilt = ezc3d.c3d(rebuild_file.as_posix()) yield (original, rebuilt) Path.unlink(rebuild_file)
def c3d_build_rebuild_reduced(request): base_folder = Path("test/c3dTestFiles") orig_file = Path(base_folder / (request.param + ".c3d")) rebuild_file = Path(base_folder / (request.param + "_after.c3d")) original = ezc3d.c3d(orig_file.as_posix()) original.write(rebuild_file.as_posix()) rebuilt = ezc3d.c3d(rebuild_file.as_posix()) if request.param == "C3DRotationExample": rebuilt["parameters"]["ROTATION"]["DATA_START"]["value"][0] = 6 yield (original, rebuilt) Path.unlink(rebuild_file)
def Get_Event(file): # Find event from c3d file : heel strike (HS) and toe off (TO) # Determine the indexes of the beginning and end of each phases measurements = c3d(file) time = np.reshape( np.reshape(measurements['parameters']['EVENT']['TIMES']['value'], (7 * 2, 1)), (7, 2))[:, 1] labels_time = measurements['parameters']['EVENT']['LABELS']['value'] freq = measurements['parameters']['POINT']['RATE']['value'][0] get_indexes = lambda x, xs: [ i for (y, i) in zip(xs, range(len(xs))) if x == y ] RHS = time[get_indexes('RHS', labels_time)] RTO = time[get_indexes('RTO', labels_time)] if len(RTO) > 1: RTO = max(RTO) else: RTO = RTO[0] start = round(RHS[0] * freq) + 1 stop_stance = round(RTO * freq) + 1 stop = round(RHS[1] * freq) + 1 return start, stop_stance, stop
def RetrieveC3dData (self, fullPath): # Create some dictionaries to store data self.Gen = {'PathName':[],'FileName':[],'SubjName':[], 'SubjMass':[],'SubjHeight':[],'ModelUsed':[], 'NumbItems':[],'Vid_FirstFrame':[],'Vid_LastFrame':[],'Vid_SampRate':[], 'Analog_FirstFrame':[],'Analog_LastFrame':[],'Analog_SampRate':[],'Analog_NumbChan':[],'AnalogUnits':[], 'PointsUnit':[], 'AnglesUnit':[], 'ForcesUnit':[], 'MomentsUnit':[],'PowersUnit':[],'ScalarsUnit':[], 'SubjLLegLength':[],'SubjRLegLength':[], 'ForcePlateOrigin':[]} self.Labels = {'PointsName':[],'Markers':[], 'Angles':[],'Scalars':[],'Powers':[], 'Forces':[],'Moments':[], 'AnalogsName':[], 'EventLabels':[], 'AnalysisNames':[]} self.Data = {'AllPoints':[], 'Markers':[], 'Angles':[],'Scalars':[],'Powers':[], 'Forces':[],'Moments':[], 'Analogs':[]} # returns a handle to RetrieveC3dData self.c3d = c3d(os.path.join(fullPath)) self.GetHeader(fullPath) self.GetSubjects() self.GetPoint() self.GetAnalog() self.GetForcePlatForm() self.GetEventContext() self.GetAnalysis() self.GetProcessing()
def from_c3d(cls, filename, idx=None, names=None, prefix=None): """ Read c3d data and convert to Vectors3d format Parameters ---------- filename : Union[str, Path] Path of file idx : list(int) Order of columns given by index names : list(str) Order of columns given by names, if both names and idx are provided, an error occurs prefix : str Prefix to remove in the header Returns ------- Data set in Vectors3d format or Data set in Vectors3d format and metadata dict if get_metadata is True """ if names and idx: raise ValueError("names and idx can't be set simultaneously, please select only one") reader = ezc3d.c3d(str(filename)) data, channel_names, metadata = cls._parse_c3d(reader, prefix) if names: metadata.update({'get_labels': names}) else: metadata.update({'get_labels': []}) names = channel_names return cls._to_vectors(data=data, idx=idx, all_names=channel_names, target_names=names, metadata=metadata)
def test_values(): c3d = ezc3d.c3d("test/c3dTestFiles/Vicon.c3d") array = c3d["data"]["points"] decimal = 6 np.testing.assert_array_equal(x=array.shape, y=(4, 51, 580), err_msg="Shape does not match") raveled = array.ravel() np.testing.assert_array_almost_equal( x=raveled[0], y=44.16278839111328, decimal=decimal, ) np.testing.assert_array_almost_equal( x=raveled[-1], y=1.0, decimal=decimal, ) np.testing.assert_array_almost_equal(x=np.nanmean(array), y=362.2979849093196, decimal=decimal) np.testing.assert_array_almost_equal(x=np.nanmedian(array), y=337.7519226074219, decimal=decimal) np.testing.assert_allclose(actual=np.nansum(array), desired=42535594.91827867, rtol=0.05) np.testing.assert_array_equal(x=np.isnan(array).sum(), y=915)
def test_force_platform_filter(): c3d = ezc3d.c3d("test/c3dTestFiles/Qualisys.c3d", extract_forceplat_data=True) all_pf = c3d["data"]["platform"] np.testing.assert_equal(len(all_pf), 2) # Frames np.testing.assert_equal(all_pf[0]["force"].shape[1], 3400) np.testing.assert_equal(all_pf[0]["moment"].shape[1], 3400) np.testing.assert_equal(all_pf[0]["center_of_pressure"].shape[1], 3400) np.testing.assert_equal(all_pf[0]["Tz"].shape[1], 3400) np.testing.assert_equal(all_pf[1]["force"].shape[1], 3400) np.testing.assert_equal(all_pf[1]["moment"].shape[1], 3400) np.testing.assert_equal(all_pf[1]["center_of_pressure"].shape[1], 3400) np.testing.assert_equal(all_pf[1]["Tz"].shape[1], 3400) # Units np.testing.assert_string_equal(all_pf[0]["unit_force"], "N") np.testing.assert_string_equal(all_pf[0]["unit_moment"], "Nmm") np.testing.assert_string_equal(all_pf[0]["unit_position"], "mm") np.testing.assert_string_equal(all_pf[1]["unit_force"], "N") np.testing.assert_string_equal(all_pf[1]["unit_moment"], "Nmm") np.testing.assert_string_equal(all_pf[1]["unit_position"], "mm") # Position of pf np.testing.assert_array_almost_equal(all_pf[0]["origin"], [1.524, -0.762, -34.036]) np.testing.assert_array_almost_equal( all_pf[0]["corners"], [[508, 508, 0, 0], [464, 0, 0, 464], [0, 0, 0, 0]], decimal=3 ) np.testing.assert_array_almost_equal(all_pf[1]["origin"], [1.016, 0, -36.322]) np.testing.assert_array_almost_equal( all_pf[1]["corners"], [[1017, 1017, 509, 509], [464, 0, 0, 464], [0, 0, 0, 0]], decimal=3 ) # Calibration matrix np.testing.assert_array_almost_equal(all_pf[0]["cal_matrix"], np.zeros((6, 6))) np.testing.assert_array_almost_equal(all_pf[1]["cal_matrix"], np.zeros((6, 6))) # Data at 3 different time expected_force = [[0.140, 106.480, -0.140], [0.046, -66.407, -0.138], [-0.184, 763.647, 0.367]] expected_moment = [[20.868, 54768.655, 51.780], [-4.623, -24103.676, 4.483], [-29.393, -12229.124, -29.960]] expected_cop = [[228.813, 285.564, 241.787], [118.296, 303.720, 373.071], [0, 0, 0]] expected_Tz = [[0, 0, 0], [0, 0, 0], [-44.141, -2496.299, -51.390]] np.testing.assert_array_almost_equal(all_pf[0]["force"][:, [0, 1000, -1]], expected_force, decimal=3) np.testing.assert_array_almost_equal(all_pf[0]["moment"][:, [0, 1000, -1]], expected_moment, decimal=3) np.testing.assert_array_almost_equal(all_pf[0]["center_of_pressure"][:, [0, 1000, -1]], expected_cop, decimal=3) np.testing.assert_array_almost_equal(all_pf[0]["Tz"][:, [0, 1000, -1]], expected_Tz, decimal=3) expected_force = [[0.046, 0.232, 0.185], [-0.185, -0.184, -0.046], [0.723, 0.361, 0.542]] expected_moment = [[49.366, 68.671, 16.708], [-96.907, -46.501, 50.403], [0.047, -19.720, 30.122]] expected_cop = [[897.0422, 891.673, 670.044], [300.283, 422.019, 262.813], [0, 0, 0]] expected_Tz = [[0, 0, 0], [0, 0, 0], [27.944, 48.016, 31.545]] np.testing.assert_array_almost_equal(all_pf[1]["force"][:, [0, 1000, -1]], expected_force, decimal=3) np.testing.assert_array_almost_equal(all_pf[1]["moment"][:, [0, 1000, -1]], expected_moment, decimal=3) np.testing.assert_array_almost_equal(all_pf[1]["center_of_pressure"][:, [0, 1000, -1]], expected_cop, decimal=3) np.testing.assert_array_almost_equal(all_pf[1]["Tz"][:, [0, 1000, -1]], expected_Tz, decimal=3)
def load_c3d_mocap(filename): import ezc3d c3d = ezc3d.c3d(os.fspath(filename)) sample_rate = c3d['parameters']['POINT']['RATE']['value'][0] skeleton_name = c3d['parameters']['POINT']['SKEL']['value'][0] joints = c3d['data']['points'].transpose(2, 1, 0)[..., :3].astype(np.float32) return Mocap(joints, skeleton_name, sample_rate)
def __init__(self, c3d_path: str): # Note that we extract the relevant parameters from c3d_obj and then it should be garbage collected - # this results in a significant savings in memory. c3d_obj = c3d(c3d_path) self.marker_names = c3d_obj['parameters']['POINT']['LABELS']['value'] self._marker_map = dict(zip(self.marker_names, range(len(self.marker_names)))) self.analog_frame_rate = c3d_obj['header']['analogs']['frame_rate'] self.marker_frame_rate = c3d_obj['header']['points']['frame_rate'] self.marker_data = c3d_obj['data']['points'] self.frames = np.arange(self.marker_data.shape[2])
def save_c3d_mocap(mocap: Mocap, filename): import ezc3d skeleton = skeleton_registry[mocap.skeleton_name] assert_plausible_skeleton(mocap.joint_positions, skeleton) c3d = ezc3d.c3d() c3d['parameters']['POINT']['RATE']['value'] = [mocap.sample_rate] c3d['parameters']['POINT']['UNITS']['value'] = ['mm'] c3d['parameters']['POINT']['LABELS']['value'] = skeleton.joint_names c3d.add_parameter('POINT', 'SKEL', [skeleton.name]) c3d['data']['points'] = mocap.joint_positions.transpose(2, 1, 0).astype( np.float64) c3d.write(os.fspath(filename))
def test_create_c3d(): c3d = ezc3d.c3d() # Test the header assert c3d['header']['points']['size'] == 0 assert c3d['header']['points']['frame_rate'] == 0.0 assert c3d['header']['points']['first_frame'] == 0 assert c3d['header']['points']['last_frame'] == 0 assert c3d['header']['analogs']['size'] == 0 assert c3d['header']['analogs']['frame_rate'] == 0.0 assert c3d['header']['analogs']['first_frame'] == 0 assert c3d['header']['analogs']['last_frame'] == -1 assert c3d['header']['events']['size'] == 18 assert c3d['header']['events']['events_time'] \ == (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) assert c3d['header']['events']['events_label'] \ == ('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '') # Test the parameters assert c3d['parameters']['POINT']['USED']['value'][0] == 0 assert c3d['parameters']['POINT']['SCALE']['value'][0] == -1 assert c3d['parameters']['POINT']['RATE']['value'][0] == 0.0 assert c3d['parameters']['POINT']['FRAMES']['value'][0] == 0 assert len(c3d['parameters']['POINT']['LABELS']['value']) == 0 assert len(c3d['parameters']['POINT']['DESCRIPTIONS']['value']) == 0 assert len(c3d['parameters']['POINT']['UNITS']['value']) == 0 assert c3d['parameters']['ANALOG']['USED']['value'][0] == 0 assert len(c3d['parameters']['ANALOG']['LABELS']['value']) == 0 assert len(c3d['parameters']['ANALOG']['DESCRIPTIONS']['value']) == 0 assert c3d['parameters']['ANALOG']['GEN_SCALE']['value'][0] == 1 assert len(c3d['parameters']['ANALOG']['SCALE']['value']) == 0 assert len(c3d['parameters']['ANALOG']['OFFSET']['value']) == 0 assert len(c3d['parameters']['ANALOG']['UNITS']['value']) == 0 assert c3d['parameters']['ANALOG']['RATE']['value'][0] == 0.0 assert len(c3d['parameters']['ANALOG']['FORMAT']['value']) == 0 assert len(c3d['parameters']['ANALOG']['BITS']['value']) == 0 assert c3d['parameters']['FORCE_PLATFORM']['USED']['value'][0] == 0 assert len(c3d['parameters']['FORCE_PLATFORM']['TYPE']['value']) == 0 assert np.all(c3d['parameters']['FORCE_PLATFORM']['ZERO']['value'] == (1, 0)) assert len(c3d['parameters']['FORCE_PLATFORM']['CORNERS']['value']) == 0 assert len(c3d['parameters']['FORCE_PLATFORM']['ORIGIN']['value']) == 0 assert len(c3d['parameters']['FORCE_PLATFORM']['CHANNEL']['value']) == 0 assert len(c3d['parameters']['FORCE_PLATFORM']['CAL_MATRIX']['value']) == 0 # Test the data assert c3d['data']['points'].shape == (4, 0, 0) assert c3d['data']['analogs'].shape == (1, 0, 0)
def __init__(self, path): self.path =path self.c = c3d() self.c = c3d(self.path) self.point_data = self.c['data']['points'] self.points_residuals = self.c['data']['meta_points']['residuals'] self.analog_data = self.c['data']['analogs'] self.labels = self.c['parameters']['POINT']['LABELS']['value'] self.length = self.point_data[0][0,:].shape[0] self.T = np.arange(0, self.length) self.frequency = 250 self.BVHTop = '' self.BVHDict = {} self.Channeldict = {} self.Offset_dict = {} self.BVH_means = {} self.BVH_variance = {} self.BVH_locale = {} self.BVH_Data = {}
def read_c3d( caller: Callable, filename: Union[str, Path], usecols: Optional[List[Union[str, int]]] = None, prefix_delimiter: Optional[str] = None, suffix_delimiter: Optional[str] = None, attrs: Optional[dict] = None, ) -> xr.DataArray: group = "ANALOG" if caller.__name__ == "Analogs" else "POINT" reader = ezc3d.c3d(f"{filename}").c3d_swig columns = [ col_spliter(label, prefix_delimiter, suffix_delimiter) for label in reader.parameters().group(group).parameter("LABELS").valuesAsString() ] get_data_function = getattr(reader, f"get_{group.lower()}s") if usecols: if isinstance(usecols[0], str): idx = [columns.index(channel) for channel in usecols] elif isinstance(usecols[0], int): idx = usecols else: raise ValueError( "usecols should be None, list of string or list of int." f"You provided {type(usecols)}") data = get_data_function()[:, idx, :] channels = [columns[i] for i in idx] else: data = get_data_function() channels = columns data_by_frame = 1 if group == "POINT" else reader.header().nbAnalogByFrame( ) attrs = attrs if attrs else {} attrs["first_frame"] = reader.header().firstFrame() * data_by_frame attrs["last_frame"] = reader.header().lastFrame() * data_by_frame attrs["rate"] = reader.header().frameRate() * data_by_frame attrs["units"] = (reader.parameters().group(group).parameter( "UNITS").valuesAsString()[0]) time = np.linspace(start=0, stop=data.shape[-1] / attrs["rate"], num=data.shape[-1], endpoint=False) return caller(data[0, ...] if group == "ANALOG" else data, channels, time, attrs=attrs)
def __init__(self, file_path): self.c3d = c3d(file_path, extract_forceplat_data=True) self.marker_names = [ "L_IAS", "L_IPS", "R_IPS", "R_IAS", "R_FTC", "R_Thigh_Top", "R_Thigh_Down", "R_Thigh_Front", "R_Thigh_Back", "R_FLE", "R_FME", "R_FAX", "R_TTC", "R_Shank_Top", "R_Shank_Down", "R_Shank_Front", "R_Shank_Tibia", "R_FAL", "R_TAM", "R_FCC", "R_FM1", "R_FMP1", "R_FM2", "R_FMP2", "R_FM5", "R_FMP5", ] self.muscle_names = [ "R_Tibialis_Anterior", "R_Soleus", "R_Gastrocnemius_Lateralis", "R_Gastrocnemius_Medialis", "R_Vastus_Medialis", "R_Rectus_Femoris", "R_Biceps_Femoris", "R_Semitendinosus", "R_Gluteus_Medius", "R_Gluteus_Maximus", ] self.trajectories = self.get_marker_trajectories( self.c3d, self.marker_names) self.forces = self.get_forces(self.c3d) self.moments = self.get_moment(self.c3d) self.cop = self.get_cop(self.c3d) self.emg = self.get_emg(self.c3d, self.muscle_names) self.indices = self.get_indices() self.phase_time = self.get_time()
def test_rotations(): c3d = ezc3d.c3d("test/c3dTestFiles/C3DRotationExample.c3d") array = c3d["data"]["rotations"] decimal = 6 np.testing.assert_array_equal(x=array.shape, y=(4, 4, 21, 340), err_msg="Shape does not match") raveled = array.ravel() np.testing.assert_array_almost_equal( x=array[2, 3, 2, 5], y=931.6382446289062, decimal=decimal, ) np.testing.assert_array_almost_equal( x=raveled[-1], y=1.0, decimal=decimal, ) np.testing.assert_array_almost_equal(x=np.nansum(array), y=9367125.137371363, decimal=decimal)
def GetGroundReactionForces(file): measurements = c3d(file) analog = measurements['data']['analogs'] labels_analog = measurements['parameters']['ANALOG']['LABELS']['value'] nbPF = measurements['parameters']['FORCE_PLATFORM']['USED']['value'][0][0] GRF = np.zeros((len(analog[0, 0, :]), 3, nbPF)) for p in range(nbPF): GRF[:, 0, p] = analog[0, labels_analog.index("Fx" + str(p + 1)), :].squeeze() # Fx GRF[:, 1, p] = analog[0, labels_analog.index("Fy" + str(p + 1)), :].squeeze() # Fy GRF[:, 2, p] = -analog[0, labels_analog.index("Fz" + str(p + 1)), :].squeeze() # Fz return GRF
def GetMoment(file): measurements = c3d(file) analog = measurements['data']['analogs'] labels_analog = measurements['parameters']['ANALOG']['LABELS']['value'] nbPF = measurements['parameters']['FORCE_PLATFORM']['USED']['value'][0][0] M = np.zeros((len(analog[0, 0, :]), 3, nbPF)) for p in range(nbPF): M[:, 0, p] = analog[0, labels_analog.index("Mx" + str(p + 1)), :].squeeze( ) * 1e-3 # Fx M[:, 1, p] = analog[0, labels_analog.index("My" + str(p + 1)), :].squeeze( ) * 1e-3 # Fy M[:, 2, p] = analog[0, labels_analog.index("Mz" + str(p + 1)), :].squeeze( ) * 1e-3 # Fz return M
def __init__(self, file_path): self.c3d = c3d(file_path, extract_forceplat_data=True) self.marker_names = [ "L_IAS", "L_IPS", "R_IPS", "R_IAS", "R_FTC", "R_Thigh_Top", "R_Thigh_Down", "R_Thigh_Front", "R_Thigh_Back", "R_FLE", "R_FME", "R_FAX", "R_TTC", "R_Shank_Top", "R_Shank_Down", "R_Shank_Front", "R_Shank_Tibia", "R_FAL", "R_TAM", "R_FCC", "R_FM1", "R_FMP1", "R_FM2", "R_FMP2", "R_FM5", "R_FMP5", ] self.trajectories = self.get_marker_trajectories( self.c3d, self.marker_names) self.forces = self.get_forces(self.c3d) self.moments = self.get_moment(self.c3d) self.cop = self.get_cop(self.c3d) self.events = self.get_event_rhs_rto(self.c3d) self.indices = self.get_indices() self.phase_time = self.get_time()
def get_events(fname, missing=np.nan): """Get events from c3d file. """ c3d = ezc3d.c3d(fname).c3d_swig events = { '0': [np.inf, ''], '1': [-np.inf, ''], 'LFS': [missing], 'LFO': [missing], 'RFS': [missing], 'RFO': [missing] } if c3d.parameters().isGroup('EVENT'): labels = c3d.parameters().group('EVENT').parameter( 'LABELS').valuesAsString() contexts = c3d.parameters().group('EVENT').parameter( 'CONTEXTS').valuesAsString() times = np.round( np.array(c3d.parameters().group('EVENT').parameter( 'TIMES').valuesAsDouble())[1::2], 6) #if times[-1] < times[0]: # delete possible out-of-order event at the end # times, labels, contexts = times[:-1], labels[:-1], contexts[:-1] evs = {} for label, context, time in zip(labels, contexts, times): key = context + ' ' + label key2 = ''.join([i[0] for i in key.strip().split(' ')]).upper() evs[key2] = np.r_[evs[key2], np.atleast_1d(time)] if \ key2 in evs.keys() else np.atleast_1d(time) if time < events['0'][0]: events['0'] = [time, key2] if time > events['1'][0]: events['1'] = [time, key2] for ev in evs: if len(ev) > 1: evs[ev] = np.sort(evs[ev]) events.update(evs) return events
def ComputeCoP(file): measurements = c3d(file) analog = measurements['data']['analogs'] nbPF = measurements['parameters']['FORCE_PLATFORM']['USED']['value'][0][0] corners = np.reshape( np.reshape( measurements['parameters']['FORCE_PLATFORM']['CORNERS']['value'] * 1e-3, (3 * 4 * 2, 1)), (2, 4, 3)) #platform x corners x coord CoP1 = np.zeros(((len(analog[0, 0, :]), 3, nbPF))) CoP = np.zeros(((len(analog[0, 0, :]), 3, nbPF))) F = GetForces(file) M = GetMoment(file) for p in range(nbPF): # Attention X et Y sont inversés sur la plaque !!! CoP1[:, 0, p] = np.divide(M[:, 0, p], F[:, 2, p]) # Mx/Fz CoP1[:, 1, p] = -np.divide(M[:, 1, p], F[:, 2, p]) # -My/Fz CoP1[:, :, p][np.isnan(CoP1[:, :, p])] = 0 # Center of the platform if p == 0: CoP[:, 0, p] = (corners[p, 1, 0] - corners[p, 2, 0]) / 2 + CoP1[:, 0, p] # xcenter + CoPx CoP[:, 1, p] = (corners[p, 0, 1] - corners[p, 1, 1]) / 2 + CoP1[:, 1, p] # ycenter + CoPy else: CoP[:, 0, p] = corners[p, 2, 0] + (corners[p, 1, 0] - corners[p, 2, 0]) / 2 + CoP1[:, 0, p] CoP[:, 1, p] = (corners[p, 0, 1] - corners[p, 1, 1]) / 2 + CoP1[:, 1, p] return CoP
def test_ezc3d(): c3d = ezc3d.c3d(f"{MARKERS_ANALOGS_C3D}") is_expected_array(xr.DataArray(c3d["data"]["points"]), **EXPECTED_VALUES[65]) is_expected_array(xr.DataArray(c3d["data"]["analogs"]), **EXPECTED_VALUES[66])
def test_create_and_read_c3d(): # Load an empty c3d structure c3d = ezc3d.c3d() # Fill it with random data point_names = ('point1', 'point2', 'point3', 'point4', 'point5') point_frame_rate = 100 n_second = 2 points = np.random.rand(3, len(point_names), point_frame_rate * n_second) analog_names = ('analog1', 'analog2', 'analog3', 'analog4', 'analog5', 'analog6') analog_frame_rate = 1000 analogs = np.random.rand(1, len(analog_names), analog_frame_rate * n_second) c3d['parameters']['POINT']['RATE']['value'] = [100] c3d['parameters']['POINT']['LABELS']['value'] = point_names c3d['data']['points'] = points c3d['parameters']['ANALOG']['RATE']['value'] = [1000] c3d['parameters']['ANALOG']['LABELS']['value'] = analog_names c3d['data']['analogs'] = analogs # Add a custom parameter to the POINT group point_new_param = ("POINT", "newPointParam", (1.0, 2.0, 3.0)) c3d.add_parameter(point_new_param[0], point_new_param[1], point_new_param[2]) # Add a custom parameter a new group new_group_param = ("NewGroup", "newGroupParam", ["MyParam1", "MyParam2"]) c3d.add_parameter(new_group_param[0], new_group_param[1], new_group_param[2]) # Write and read back the data c3d.write("temporary.c3d") c3d_to_compare = ezc3d.c3d("temporary.c3d") # Test the header assert c3d_to_compare['header']['points']['size'] == len(point_names) assert c3d_to_compare['header']['points']['frame_rate'] == point_frame_rate assert c3d_to_compare['header']['points']['first_frame'] == 0 assert c3d_to_compare['header']['points'][ 'last_frame'] == point_frame_rate * n_second - 1 assert c3d_to_compare['header']['analogs']['size'] == len(analog_names) assert c3d_to_compare['header']['analogs'][ 'frame_rate'] == analog_frame_rate assert c3d_to_compare['header']['analogs']['first_frame'] == 0 assert c3d_to_compare['header']['analogs'][ 'last_frame'] == analog_frame_rate * n_second - 1 assert c3d_to_compare['header']['events']['size'] == 18 assert c3d_to_compare['header']['events']['events_time'] == \ (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) assert c3d_to_compare['header']['events']['events_label'] == \ ('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '') # Test the parameters assert c3d_to_compare['parameters']['POINT']['USED']['value'][0] == len( point_names) assert c3d_to_compare['parameters']['POINT']['SCALE']['value'][0] == -1.0 assert c3d_to_compare['parameters']['POINT']['RATE']['value'][ 0] == point_frame_rate assert c3d_to_compare['parameters']['POINT']['FRAMES']['value'][ 0] == point_frame_rate * n_second assert c3d_to_compare['parameters']['POINT']['LABELS']['value'] == list( point_names) assert c3d_to_compare['parameters']['POINT']['DESCRIPTIONS']['value'] == [ "" for _ in point_names ] assert len(c3d_to_compare['parameters']['POINT']['UNITS']['value']) == 0 assert np.all(c3d_to_compare['parameters'][point_new_param[0]][ point_new_param[1]]['value'] == point_new_param[2]) assert c3d_to_compare['parameters']['ANALOG']['USED']['value'][0] == len( analog_names) assert c3d_to_compare['parameters']['ANALOG']['LABELS']['value'] == list( analog_names) assert c3d_to_compare['parameters']['ANALOG']['DESCRIPTIONS']['value'] == [ "" for _ in analog_names ] assert c3d_to_compare['parameters']['ANALOG']['GEN_SCALE']['value'][0] == 1 assert np.all(c3d_to_compare['parameters']['ANALOG']['SCALE']['value'] == tuple([1.0 for _ in analog_names])) assert np.all(c3d_to_compare['parameters']['ANALOG']['OFFSET']['value'] == tuple([0 for _ in analog_names])) assert c3d_to_compare['parameters']['ANALOG']['UNITS']['value'] == [ "" for _ in analog_names ] assert c3d_to_compare['parameters']['ANALOG']['RATE']['value'][ 0] == analog_frame_rate assert len(c3d_to_compare['parameters']['ANALOG']['FORMAT']['value']) == 0 assert len(c3d_to_compare['parameters']['ANALOG']['BITS']['value']) == 0 assert c3d_to_compare['parameters']['FORCE_PLATFORM']['USED']['value'][ 0] == 0 assert len( c3d_to_compare['parameters']['FORCE_PLATFORM']['TYPE']['value']) == 0 assert np.all( c3d_to_compare['parameters']['FORCE_PLATFORM']['ZERO']['value'] == (1, 0)) assert len(c3d_to_compare['parameters']['FORCE_PLATFORM']['CORNERS'] ['value']) == 0 assert len( c3d_to_compare['parameters']['FORCE_PLATFORM']['ORIGIN']['value']) == 0 assert len(c3d_to_compare['parameters']['FORCE_PLATFORM']['CHANNEL'] ['value']) == 0 assert len(c3d_to_compare['parameters']['FORCE_PLATFORM']['CAL_MATRIX'] ['value']) == 0 assert c3d_to_compare['parameters'][new_group_param[0]][new_group_param[1]]['value'] \ == new_group_param[2] # Test the data assert c3d_to_compare['data']['points'].shape == (4, len(point_names), point_frame_rate * n_second) assert c3d_to_compare['data']['analogs'].shape == (1, len(analog_names), analog_frame_rate * n_second) # Compare the read c3d np.testing.assert_almost_equal(c3d_to_compare['data']['points'][0:3, :, :], points) np.testing.assert_almost_equal(c3d_to_compare['data']['analogs'], analogs)
# import c3d # with open('E:/VCL/Users/tofis/Data/DATASETS/RGBDIRD_MOCAP_DATASET/Data/ARTANIM/Vicon/Ball_Calibrations/CalibrationBallSequence.c3d', 'rb') as handle: # reader = c3d.Reader(handle) # for i, (points, analog) in enumerate(reader.read_frames()): # print('Frame {}: {}'.format(i, points.round(2))) import os from ezc3d import c3d path = 'E:/VCL/Users/tofis/Data/DATASETS/RGBDIRD_MOCAP_DATASET/Data/ARTANIM/Vicon/Ball_Calibrations' file = 'Bart_CalibrationBallSequence_04.c3d' c = c3d(os.path.join(path, file)) print(c['parameters']['POINT']['USED']['value'][0]) # Print the number of points used point_data = c['data']['points'] f = open(os.path.join(path, file.replace('c3d', 'txt')), 'w') for i in range(0, point_data.shape[2]): f.write( str(point_data[0][0][i]) + " " + str(point_data[1][0][i]) + " " + str(point_data[2][0][i]) + "\n") f.close()
def RetrieveC3dData(self, fullPath): # Create some dictionaries to store data self.Gen = { "PathName": [], "FileName": [], "SubjName": [], "SubjMass": [], "SubjHeight": [], "ModelUsed": [], "NumbItems": [], "Vid_FirstFrame": [], "Vid_LastFrame": [], "Vid_SampRate": [], "Analog_FirstFrame": [], "Analog_LastFrame": [], "Analog_SampRate": [], "Analog_NumbChan": [], "AnalogUnits": [], "PointsUnit": [], "AnglesUnit": [], "ForcesUnit": [], "MomentsUnit": [], "PowersUnit": [], "ScalarsUnit": [], "SubjLLegLength": [], "SubjRLegLength": [], "ForcePlateOrigin": [], } self.Labels = { "PointsName": [], "Markers": [], "Angles": [], "Scalars": [], "Powers": [], "Forces": [], "Moments": [], "AnalogsName": [], "EventLabels": [], "AnalysisNames": [], } self.Data = { "AllPoints": [], "Markers": [], "Angles": [], "Scalars": [], "Powers": [], "Forces": [], "Moments": [], "Analogs": [], } # returns a handle to RetrieveC3dData self.c3d = c3d(os.path.join(fullPath)) self.GetHeader(fullPath) self.GetSubjects() self.GetPoint() self.GetAnalog() self.GetForcePlatForm() self.GetEventContext() self.GetAnalysis() self.GetProcessing()
def test_create_c3d(): c3d = ezc3d.c3d() # Test the header assert c3d["header"]["points"]["size"] == 0 assert c3d["header"]["points"]["frame_rate"] == 0.0 assert c3d["header"]["points"]["first_frame"] == 0 assert c3d["header"]["points"]["last_frame"] == 0 assert c3d["header"]["analogs"]["size"] == 0 assert c3d["header"]["analogs"]["frame_rate"] == 0.0 assert c3d["header"]["analogs"]["first_frame"] == 0 assert c3d["header"]["analogs"]["last_frame"] == -1 assert c3d["header"]["events"]["size"] == 18 assert c3d["header"]["events"]["events_time"] == ( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ) assert c3d["header"]["events"]["events_label"] == ( "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ) # Test the parameters assert c3d["parameters"]["POINT"]["USED"]["value"][0] == 0 assert c3d["parameters"]["POINT"]["SCALE"]["value"][0] == -1 assert c3d["parameters"]["POINT"]["RATE"]["value"][0] == 0.0 assert c3d["parameters"]["POINT"]["FRAMES"]["value"][0] == 0 assert len(c3d["parameters"]["POINT"]["LABELS"]["value"]) == 0 assert len(c3d["parameters"]["POINT"]["DESCRIPTIONS"]["value"]) == 0 assert len(c3d["parameters"]["POINT"]["UNITS"]["value"]) == 0 assert c3d["parameters"]["ANALOG"]["USED"]["value"][0] == 0 assert len(c3d["parameters"]["ANALOG"]["LABELS"]["value"]) == 0 assert len(c3d["parameters"]["ANALOG"]["DESCRIPTIONS"]["value"]) == 0 assert c3d["parameters"]["ANALOG"]["GEN_SCALE"]["value"][0] == 1 assert len(c3d["parameters"]["ANALOG"]["SCALE"]["value"]) == 0 assert len(c3d["parameters"]["ANALOG"]["OFFSET"]["value"]) == 0 assert len(c3d["parameters"]["ANALOG"]["UNITS"]["value"]) == 0 assert c3d["parameters"]["ANALOG"]["RATE"]["value"][0] == 0.0 assert len(c3d["parameters"]["ANALOG"]["FORMAT"]["value"]) == 0 assert len(c3d["parameters"]["ANALOG"]["BITS"]["value"]) == 0 assert c3d["parameters"]["FORCE_PLATFORM"]["USED"]["value"][0] == 0 assert len(c3d["parameters"]["FORCE_PLATFORM"]["TYPE"]["value"]) == 0 assert np.all(c3d["parameters"]["FORCE_PLATFORM"]["ZERO"]["value"] == (1, 0)) assert len(c3d["parameters"]["FORCE_PLATFORM"]["CORNERS"]["value"]) == 0 assert len(c3d["parameters"]["FORCE_PLATFORM"]["ORIGIN"]["value"]) == 0 assert len(c3d["parameters"]["FORCE_PLATFORM"]["CHANNEL"]["value"]) == 0 assert len(c3d["parameters"]["FORCE_PLATFORM"]["CAL_MATRIX"]["value"]) == 0 # Test the data assert c3d["data"]["points"].shape == (4, 0, 0) assert c3d["data"]["analogs"].shape == (1, 0, 0)
def test_create_and_read_c3d(): # Load an empty c3d structure c3d = ezc3d.c3d() # Fill it with random data point_names = ("point1", "point2", "point3", "point4", "point5") point_frame_rate = 100 n_second = 2 points = np.random.rand(3, len(point_names), point_frame_rate * n_second) analog_names = ("analog1", "analog2", "analog3", "analog4", "analog5", "analog6") analog_frame_rate = 1000 analogs = np.random.rand(1, len(analog_names), analog_frame_rate * n_second) c3d["parameters"]["POINT"]["RATE"]["value"] = [100] c3d["parameters"]["POINT"]["LABELS"]["value"] = point_names c3d["data"]["points"] = points c3d["parameters"]["ANALOG"]["RATE"]["value"] = [1000] c3d["parameters"]["ANALOG"]["LABELS"]["value"] = analog_names c3d["data"]["analogs"] = analogs # Add a custom parameter to the POINT group point_new_param = ("POINT", "newPointParam", (1.0, 2.0, 3.0)) c3d.add_parameter(point_new_param[0], point_new_param[1], point_new_param[2]) # Add a custom parameter a new group new_group_param = ("NewGroup", "newGroupParam", ["MyParam1", "MyParam2"]) c3d.add_parameter(new_group_param[0], new_group_param[1], new_group_param[2]) # Write and read back the data c3d.write("temporary.c3d") c3d_to_compare = ezc3d.c3d("temporary.c3d") # Test the header assert c3d_to_compare["header"]["points"]["size"] == len(point_names) assert c3d_to_compare["header"]["points"]["frame_rate"] == point_frame_rate assert c3d_to_compare["header"]["points"]["first_frame"] == 0 assert c3d_to_compare["header"]["points"][ "last_frame"] == point_frame_rate * n_second - 1 assert c3d_to_compare["header"]["analogs"]["size"] == len(analog_names) assert c3d_to_compare["header"]["analogs"][ "frame_rate"] == analog_frame_rate assert c3d_to_compare["header"]["analogs"]["first_frame"] == 0 assert c3d_to_compare["header"]["analogs"][ "last_frame"] == analog_frame_rate * n_second - 1 assert c3d_to_compare["header"]["events"]["size"] == 18 assert c3d_to_compare["header"]["events"]["events_time"] == ( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ) assert c3d_to_compare["header"]["events"]["events_label"] == ( "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ) # Test the parameters assert c3d_to_compare["parameters"]["POINT"]["USED"]["value"][0] == len( point_names) assert c3d_to_compare["parameters"]["POINT"]["SCALE"]["value"][0] == -1.0 assert c3d_to_compare["parameters"]["POINT"]["RATE"]["value"][ 0] == point_frame_rate assert c3d_to_compare["parameters"]["POINT"]["FRAMES"]["value"][ 0] == point_frame_rate * n_second assert c3d_to_compare["parameters"]["POINT"]["LABELS"]["value"] == list( point_names) assert c3d_to_compare["parameters"]["POINT"]["DESCRIPTIONS"]["value"] == [ "" for _ in point_names ] assert len(c3d_to_compare["parameters"]["POINT"]["UNITS"]["value"]) == 0 assert np.all(c3d_to_compare["parameters"][point_new_param[0]][ point_new_param[1]]["value"] == point_new_param[2]) assert c3d_to_compare["parameters"]["ANALOG"]["USED"]["value"][0] == len( analog_names) assert c3d_to_compare["parameters"]["ANALOG"]["LABELS"]["value"] == list( analog_names) assert c3d_to_compare["parameters"]["ANALOG"]["DESCRIPTIONS"]["value"] == [ "" for _ in analog_names ] assert c3d_to_compare["parameters"]["ANALOG"]["GEN_SCALE"]["value"][0] == 1 assert np.all(c3d_to_compare["parameters"]["ANALOG"]["SCALE"]["value"] == tuple([1.0 for _ in analog_names])) assert np.all(c3d_to_compare["parameters"]["ANALOG"]["OFFSET"]["value"] == tuple([0 for _ in analog_names])) assert c3d_to_compare["parameters"]["ANALOG"]["UNITS"]["value"] == [ "" for _ in analog_names ] assert c3d_to_compare["parameters"]["ANALOG"]["RATE"]["value"][ 0] == analog_frame_rate assert len(c3d_to_compare["parameters"]["ANALOG"]["FORMAT"]["value"]) == 0 assert len(c3d_to_compare["parameters"]["ANALOG"]["BITS"]["value"]) == 0 assert c3d_to_compare["parameters"]["FORCE_PLATFORM"]["USED"]["value"][ 0] == 0 assert len( c3d_to_compare["parameters"]["FORCE_PLATFORM"]["TYPE"]["value"]) == 0 assert np.all( c3d_to_compare["parameters"]["FORCE_PLATFORM"]["ZERO"]["value"] == (1, 0)) assert len(c3d_to_compare["parameters"]["FORCE_PLATFORM"]["CORNERS"] ["value"]) == 0 assert len( c3d_to_compare["parameters"]["FORCE_PLATFORM"]["ORIGIN"]["value"]) == 0 assert len(c3d_to_compare["parameters"]["FORCE_PLATFORM"]["CHANNEL"] ["value"]) == 0 assert len(c3d_to_compare["parameters"]["FORCE_PLATFORM"]["CAL_MATRIX"] ["value"]) == 0 assert c3d_to_compare["parameters"][new_group_param[0]][ new_group_param[1]]["value"] == new_group_param[2] # Test the data assert c3d_to_compare["data"]["points"].shape == (4, len(point_names), point_frame_rate * n_second) assert c3d_to_compare["data"]["analogs"].shape == (1, len(analog_names), analog_frame_rate * n_second) # Compare the read c3d np.testing.assert_almost_equal(c3d_to_compare["data"]["points"][0:3, :, :], points) np.testing.assert_almost_equal(c3d_to_compare["data"]["analogs"], analogs)