Orientation Tracking Setup
- Nicholas Vandenberg
- Posts: 71
- Joined: Wed Jan 20, 2021 12:47 pm
Re: Orientation Tracking Setup
Yeah, editing by hand never goes well. I tried using the API in my conversion code to fix the header, but I can't load it into a TimeSeriesTable when I specify a DataType in the header. I was able to load it into a table with the old header and wrote it to an .sto before.
I may just have to return to that 'older' version of my IMU conversion code, or maybe integrate the TimeSeriesTable export/edit into it?
I may just have to return to that 'older' version of my IMU conversion code, or maybe integrate the TimeSeriesTable export/edit into it?
- Nicholas Bianco
- Posts: 1041
- Joined: Thu Oct 04, 2012 8:09 pm
Re: Orientation Tracking Setup
Hi Nick,
At this point, to save you more pain, we should just construct your table manually through the Matlab API. I wrote some sample code to help get you started, let me know if you have any questions:
At this point, to save you more pain, we should just construct your table manually through the Matlab API. I wrote some sample code to help get you started, let me know if you have any questions:
Code: Select all
import org.opensim.modeling.*;
% Create time vector
time = linspace(0, 2, 101);
timeVec = StdVectorDouble();
for i = 1:length(time)
timeVec.add(time(i));
end
% Create an empty table
table = TimeSeriesTableQuaternion(timeVec);
% Set one column (wrap in loop for more columns)
col = VectorQuaternion(length(time), Quaternion(0.0, 0.0, 0.0, 0.0));
for i = 1:length(time)
% Fill in your actual data here
quat = Quaternion(1.0, 2.0, 3.0, 4.0);
col.set(i-1, quat);
end
table.appendColumn('quat1', col);
% From here, 2 options:
% 1. Write the table as-is
stoq = STOFileAdapterQuaternion();
stoq.write(table, 'table.sto');
% OR
% 2. Flatten the table and then write
tableFlat = TimeSeriesTable(table.flatten()); % flatten() returns a DataTable, but we need a TimeSeriesTable
sto = STOFileAdapter();
sto.write(tableFlat, 'tableFlat.sto');
- Nicholas Vandenberg
- Posts: 71
- Joined: Wed Jan 20, 2021 12:47 pm
Re: Orientation Tracking Setup
Hi Nick, apologies for the slow response.
I wanted to thank you again for your help with this so far, but also wanted to pivot a bit because I think I may have found a simpler solution (that will require a similar process) and I was hoping to get your perspective. I was looking back through our data from Xsens and saw that it's possible to export in a different format, I'm trying an XLSX vs the MVNX which I can now load directly into matlab without needing any additional conversion codes. I then have this big beautiful structure: I was initially thinking I could directly pull the quaternion data from here, but seeing these different headers, I'm wondering if I can instead define the angular pelvis DOFs from this 'SegmentOrientation0x2DEuler'. If I'm able to pull angular data to fill a table (even if it requires a conversion) as opposed to quaternion, I'm wondering can I create a blank states trajectory that I fill individual columns with from sections of this data structure? Is that possible? I'm not as savvy with using the API as I'd like to be but I feel like this doable, even if it needs to instead be a TimeSeriesTable -> STOFileAdapter. I appreciate whatever insight you've got.
Thanks again,
Nick
I wanted to thank you again for your help with this so far, but also wanted to pivot a bit because I think I may have found a simpler solution (that will require a similar process) and I was hoping to get your perspective. I was looking back through our data from Xsens and saw that it's possible to export in a different format, I'm trying an XLSX vs the MVNX which I can now load directly into matlab without needing any additional conversion codes. I then have this big beautiful structure: I was initially thinking I could directly pull the quaternion data from here, but seeing these different headers, I'm wondering if I can instead define the angular pelvis DOFs from this 'SegmentOrientation0x2DEuler'. If I'm able to pull angular data to fill a table (even if it requires a conversion) as opposed to quaternion, I'm wondering can I create a blank states trajectory that I fill individual columns with from sections of this data structure? Is that possible? I'm not as savvy with using the API as I'd like to be but I feel like this doable, even if it needs to instead be a TimeSeriesTable -> STOFileAdapter. I appreciate whatever insight you've got.
Thanks again,
Nick
Re: Orientation Tracking Setup
Hi Nicholas,
Thought I'd quickly chime in here just to flag that building a table like this is definitely possible. The approach is somewhat counterintuitive to me, as I think the best way is to build it row-by-row rather than column-by-column. I think the best example you could find is under the Matlab > Utilities folder that comes with OpenSIm install resources (in the code folder), there is a function osimTableFromStruct. I've used this as an example on a few occasions to build a table from Matlab/Python data.
Aaron
Thought I'd quickly chime in here just to flag that building a table like this is definitely possible. The approach is somewhat counterintuitive to me, as I think the best way is to build it row-by-row rather than column-by-column. I think the best example you could find is under the Matlab > Utilities folder that comes with OpenSIm install resources (in the code folder), there is a function osimTableFromStruct. I've used this as an example on a few occasions to build a table from Matlab/Python data.
Aaron
- Nicholas Vandenberg
- Posts: 71
- Joined: Wed Jan 20, 2021 12:47 pm
Re: Orientation Tracking Setup
Hi Aaron,
That's good to know, and thanks for the suggestion I'll definitely start there. I'm wondering if you could clarify why row-by-row vs col-by-col? My understanding is that I have way more data than I actually need in the structure as it is, so I'd be building a single table that is pulling data from the various sections to fill the different DOFs. Is this incorrect?
Best,
Nick
That's good to know, and thanks for the suggestion I'll definitely start there. I'm wondering if you could clarify why row-by-row vs col-by-col? My understanding is that I have way more data than I actually need in the structure as it is, so I'd be building a single table that is pulling data from the various sections to fill the different DOFs. Is this incorrect?
Best,
Nick
- Nicholas Vandenberg
- Posts: 71
- Joined: Wed Jan 20, 2021 12:47 pm
Re: Orientation Tracking Setup
Quick update here. I was able to figure out how to pull the DOFs I wanted and construct an .sto to use as my input file. I put the OrientationTracking on the backburner for the moment in lieu of pulling SegmentOrientations for the pelvis angular kinematics. I appreciate the help with this though!
Thanks,
Nick
Thanks,
Nick
- Nicholas Bianco
- Posts: 1041
- Joined: Thu Oct 04, 2012 8:09 pm
Re: Orientation Tracking Setup
Hi Nick,
I know you have a decent alternative working, but I'd like to help you figure out the orientation tracking problem if it can be valuable to you.
Best,
Nick
I know you have a decent alternative working, but I'd like to help you figure out the orientation tracking problem if it can be valuable to you.
If you look at the code snippet I posted above, that is a column-by-column since I used "table.appendColumn(col);" to build the table, where "col" is a SimTK::Vector. You can also build a table row-by-row using "table.appendRow(time, row)" where "time" is the time value (not index) and row is a SimTK::RowVector. Note that if you're not working with scalar data (e.g., Vec3's) then you'll need other vector types (e.g., SimTK::VectorVec3 and SimTK::RowVectorVec3).I'm wondering if you could clarify why row-by-row vs col-by-col?
Could you describe what you were hoping to accomplish with the orientation tracking problem again? You might have everything you need, but I'm starting to get fuzzy on the details.My understanding is that I have way more data than I actually need in the structure as it is, so I'd be building a single table that is pulling data from the various sections to fill the different DOFs.
Best,
Nick
- Nicholas Vandenberg
- Posts: 71
- Joined: Wed Jan 20, 2021 12:47 pm
Re: Orientation Tracking Setup
Hey Nick,
Thanks for clarifying the difference and for sharing that bit of code, I used that snippet that you shared to build mine column-by-column. With the organization of the structure that I had, appending the columns that I needed seemed to be the most straightforward way.
My original plan with the pelvis orientation tracking goal was to pull the quaternion data for the segment orientation defining the pelvis in the Xsens output, then use that as a rotation input for the MocoOrientationTrackingGoal. I've had a success with pulling the Euler segment orientations for a tracking problem but I don't think it would hurt to have this working alongside that tracking (it's not a super accurate representation of the angular DOFs at the pelvis, especially considering patients with TFA). I haven't tried it yet but I believe that I'd be able to make an orientations quat.sto using that snippet you shared again, and drive the goal with that?
Thanks,
Nick
Thanks for clarifying the difference and for sharing that bit of code, I used that snippet that you shared to build mine column-by-column. With the organization of the structure that I had, appending the columns that I needed seemed to be the most straightforward way.
My original plan with the pelvis orientation tracking goal was to pull the quaternion data for the segment orientation defining the pelvis in the Xsens output, then use that as a rotation input for the MocoOrientationTrackingGoal. I've had a success with pulling the Euler segment orientations for a tracking problem but I don't think it would hurt to have this working alongside that tracking (it's not a super accurate representation of the angular DOFs at the pelvis, especially considering patients with TFA). I haven't tried it yet but I believe that I'd be able to make an orientations quat.sto using that snippet you shared again, and drive the goal with that?
Thanks,
Nick
- Nicholas Bianco
- Posts: 1041
- Joined: Thu Oct 04, 2012 8:09 pm
Re: Orientation Tracking Setup
Yes, you absolutely can. In theory, there's no harm in having both tracking goals in the same problem, but you might have to experiment with weights to find the best convergence.but I don't think it would hurt to have this working alongside that tracking (it's not a super accurate representation of the angular DOFs at the pelvis, especially considering patients with TFA). I haven't tried it yet but I believe that I'd be able to make an orientations quat.sto using that snippet you shared again, and drive the goal with that?
- Nicholas Vandenberg
- Posts: 71
- Joined: Wed Jan 20, 2021 12:47 pm
Re: Orientation Tracking Setup
I got busy with other stuff and only came back to this orientation tracking goal recently, I was hoping to get another set of eyes on. I've used the previous code snippet to create a quaternion table for the pelvis segment
I'm then trying to bring it in for the orientation tracking code in my problem like this:
as well as directly using pelvisGoal.setRotationReferenceFile('TFAB_02_SSWlk08_Pelvis_Quat.sto');
but I'm getting the following error: Not sure what I'm missing?
Best,
Nick
Code: Select all
Pel_Quat0 = Xsens.data.SegmentOrientation0x2DQuat(sel_win(1):sel_win(2),2);
Pel_Quat1 = Xsens.data.SegmentOrientation0x2DQuat(sel_win(1):sel_win(2),3);
Pel_Quat2 = Xsens.data.SegmentOrientation0x2DQuat(sel_win(1):sel_win(2),4);
Pel_Quat3 = Xsens.data.SegmentOrientation0x2DQuat(sel_win(1):sel_win(2),5);
% grabs a selection of the walking trial
% Create empty quaternion table
timeVec2 = StdVectorDouble();
for i = 1:length(time)
timeVec2.add(time(i));
end
Quat_Table = TimeSeriesTableQuaternion(timeVec2);
% Create pelvis quaternion columns and append to table
col = VectorQuaternion(length(time), Quaternion(0.0, 0.0, 0.0, 0.0));
for i = 1:length(time)
quat = Quaternion(Pel_Quat0(i), Pel_Quat1(i), Pel_Quat2(i), Pel_Quat3(i));
col.set(i-1, quat);
end
Quat_Table.appendColumn('Pelvis',col);
stoq = STOFileAdapterQuaternion();
stoq.write(Quat_Table, 'TFAB_02_SSWlk08_Pelvis_Quat.sto');
Code: Select all
% Track pelvis orientations from Xsens using quaternion rotations
pelvisGoal = MocoOrientationTrackingGoal('pelvisGoal',20);
pelvisTable = TimeSeriesTable('TFAB_02_SSWlk08_Pelvis_Quat.sto');
pelvisTableQuat = pelvisTable.packQuaternion();
pelvisGoal.setRotationReference(pelvisTableQuat);
pel_paths = StdVectorString();
pel_paths.add('/bodyset/pelvis');
pelvisGoal.setFramePaths(pel_paths);
problem.addGoal(pelvisGoal);
but I'm getting the following error: Not sure what I'm missing?
Best,
Nick