Page 1 of 1

C3d Adapter - manipulating TimeSeriesTableVec3 in API

Posted: Mon Oct 25, 2021 4:05 am
by marliesn
Hi,

I am loading a osimC3D object with marker and force data from a c3d-file within Matlab:

Code: Select all

osimc3d = osimC3D(fileName, 1);
markers = osimc3d.getTable_markers();
forces = osimc3d.getTable_forces();
The variables markers and forces are TimeSeriesTableVec3 and TimeSeriesTable, respectively.

I would now like to remove an offset from the marker positions (e.g. horizontal position of SACR marker at first time point).

But I cannot find an efficient way to manipulate the TimeSeriesTableVec3 and TimeSeriesTable properly using the API. Has somebody an advice for me? In detail, I am wondering how I can get data from a specific marker and how I can set data for a specific marker.

I would prefer to work with the TimeSeriesTableVec3 and TimeSeriesTable objects instead of converting them to structs since I want to write them later into .trc and .mot files. I am also aware of the function osimTableFromStruct(). But I still think that it would be nicer to directly manipulate the TimeSeriesTableVec3 and TimeSeriesTable objects.

Thanks a lot in advance and best regards,
Marlies

Re: C3d Adapter - manipulating TimeSeriesTableVec3 in API

Posted: Wed Oct 27, 2021 6:27 am
by marliesn
Hi,

I made some progress in the meantime which might also be interesting for some of you.

Unfortunately, missing marker data cannot always be avoided. I implemented a function in the class osimC3D to replace [0, 0, 0] by [nan, nan, nan] for missing markers since at least the OpenSim scaling can deal with Nans but gets confused when having wrong zeros.

Code: Select all

function placeNaNs(self)
% Since OpenSim can not deal well with zeros beeing in the data
% instead of NaNs, this function can be used to replace them.

import org.opensim.modeling.*

hasNaNs = zeros(self.getNumTrajectories(), 1);
for iRow = 0 : self.markers.getNumRows()-1
    dataRow = self.markers.getRowAtIndex(iRow);
    rowChanged = 0;
    for iMarker = 0 : self.getNumTrajectories()-1
        data = dataRow.get(iMarker);
        if data.isNumericallyEqual(0) % Put NaNs if at [0, 0, 0]
            hasNaNs(iMarker+1) = 1;
            rowChanged = 1;
            data.setToNaN();
            dataRow.set(iMarker, data);
        end
    end
    if rowChanged
        self.markers.setRowAtIndex(iRow, dataRow);
    end
end

% Tell user what we did
for iMarker = find(hasNaNs)-1
    fprintf('Zeros were replaced by NaNs for marker %s. OpenSim might not like NaNs but can deal with it better than with zeros. \n', self.markers.getColumnLabel(iMarker));
end
end
The code is not perfect, since it would be nicer to direct manipulate entire trajectories of single markers. If you find a good solution for to directly extract a marker trajectory, I would be happy to get some insights.

Best regards,
Marlies

Re: C3d Adapter - manipulating TimeSeriesTableVec3 in API

Posted: Wed Oct 27, 2021 3:28 pm
by kernalnet
Hi,

I'm not a MATLAB user, but get/updDependentColumn() can be a solution. Here are some useful links:
https://simtk.org/api_docs/opensim/api_ ... 5527374584
https://simtk.org/api_docs/opensim/api_ ... 51f0ba38b4
https://github.com/MaartenAfschrift/Ope ... ding.m#L68

I'm currently using OpenSim v.4.3 API and markers gaps are nan not zero. This might be due to your OpenSim version (EZC3D has been used to pares C3D files since v.4.2).

Hope this helps.

Best,
Mohammadreza

Re: C3d Adapter - manipulating TimeSeriesTableVec3 in API

Posted: Thu Oct 28, 2021 12:35 am
by marliesn
Hi Mohammadreza,

thanks a lot for your help. That looks very useful. It was not obvious to me that the trajectories are called dependent columns.

I am already using OpenSim 4.3 API (GetVersion(): 4.3-2021-08-27-4bc7ad9). I read in another post, that there should be Nans already, but I do not know why I get zeros. Might be related to my c3d files. But I am fine with replacing them "by hand".

Best regards,
Marlies