├── .gitattributes ├── .gitignore ├── README.md ├── classManagers ├── MOTWorker.m ├── ScalingHelper.m ├── TRCWorker.m ├── ikHelper.m ├── osimIK.m ├── osimTRC.m ├── solverIK.m ├── solverIK_backup.m └── virtualMarkerManager.m ├── examples ├── OpenSimCreateTugOfWarModel.m ├── TugOfWar_CompleteRunVisualize.m ├── build_and_simulate_simple_arm.m ├── c3dExport.m ├── pendulum_marker_positions.m ├── setupAndRunAnalyzeBatchExample.m ├── setupAndRunIKBatchExample.m ├── simpleOptimizerExample.m ├── simpleOptimizerObjectiveFunction.m ├── simulate_double_pendulum_and_write_tables.m ├── strengthScaler.m └── wiringInputsAndOutputsWithTableReporter.m ├── misc ├── FindOsim.m ├── GenerateSubtrials_UsingConvenianceClasses.m ├── OrientationTacking_UsingConvenianceClasses.m ├── TRCFileFixer.m ├── createActuatorsFile.m ├── externalLoadsBuilder.m ├── generateTrackingTasksMarkers.m ├── imuDataSlicer.m ├── orientationTrackingHelper.m ├── osimRotateTableData.m ├── plotMuscleFLCurves.m ├── prescribeMotionInModel.m ├── set_coordinate_from_states.m ├── set_coordinates_add_noise.m ├── set_coordinates_random_values.m └── writeMOT.m ├── mocapDataConversion ├── convertC3D_to_osim.m └── read_trcFile.m ├── modelEditing └── simplyfy_model_and_data.m ├── solvers └── solverIK.m ├── support └── TRCFileFixer.m └── tests ├── testC3Dconverter.m ├── test_data ├── arm26.osim ├── double_pendulum_markers.osim ├── gait10dof18musc_ik_CRLF_line_ending.mot ├── gait10dof18musc_subject01.osim ├── gait10dof18musc_walk_CRLF_line_ending.trc ├── gait2392_simbody.osim ├── single_leg.osim ├── std_subject01_walk1_states.sto ├── subject01_static.mot ├── subject01_static.trc ├── subject01_walk1.trc ├── walking2.c3d ├── walking2.mot ├── walking2.trc ├── walking2_headerNormal.mot ├── walking5.c3d ├── walking5.mot └── walking5.trc ├── test_ikHelper.m └── testosimTableStruct.m /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | .DS_Store 3 | 4 | # Matlab Files 5 | *.asv 6 | *.m~ 7 | 8 | # OpenSim files 9 | *.txt 10 | *.log 11 | *.keyholder 12 | *.err 13 | 14 | # Sublime file 15 | *.sublime* 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Opensim-matlab 2 | Scripts and tools for using OpenSim in Matlab. 3 | -------------------------------------------------------------------------------- /classManagers/MOTWorker.m: -------------------------------------------------------------------------------- 1 | classdef MOTWorker < matlab.mixin.SetGet 2 | properties 3 | table 4 | name 5 | path 6 | end 7 | methods 8 | function writeMOT(obj) 9 | import org.opensim.modeling.* 10 | if isempty(obj.name) 11 | error('name not set. use setName() to set a file name') 12 | elseif isempty(obj.path) 13 | error('path not set. use setPath() to set a file path') 14 | end 15 | % Update the label names 16 | obj.updateLabelNames() 17 | % Update the header info to inclde 'nCol' and 'nRows' 18 | table_clone = obj.updateheaderinfo(); 19 | % define the absolute path to the file 20 | fullfilepath = fullfile(obj.path, [obj.name '.mot']); 21 | % use OpenSim file adapter to print the table to file 22 | STOFileAdapter().write(table_clone, fullfilepath ); 23 | display(['MOT file written: ' fullfilepath ]); 24 | end 25 | function setTable(obj, osimTable) 26 | % Flatten Table if Vec3 27 | osimTable = obj.flattenTable(osimTable); 28 | % Set the table 29 | obj.table = osimTable; 30 | end 31 | function setName(obj,name) 32 | obj.name = name; 33 | end 34 | function setPath(obj, path) 35 | obj.path = path; 36 | end 37 | function point2mm(obj) 38 | table_clone = obj.table.clone(); 39 | % Get a vector of column labels 40 | labels = table_clone.getColumnLabels(); 41 | for i = 0 : labels.size() - 1 42 | % Get the Current Label 43 | label = char(labels.get(i)); 44 | if ~isempty(strfind(label,'p')) 45 | % if the label is a point (designated with 'p') 46 | for u = 0 : table_clone.getNumRows()-1 47 | % Get the point data 48 | point = table_clone.getDependentColumnAtIndex(i).get(u); 49 | % Divide the point by 1000 and set. 50 | table_clone.getDependentColumnAtIndex(i).set(u,point/1000); 51 | end 52 | end 53 | end 54 | % override the internal table 55 | obj.setTable(table_clone) 56 | disp('Internal table point converted to mm') 57 | end 58 | end 59 | methods (Static) 60 | function osimTable = flattenTable(osimTable) 61 | % Flattens a Vec3 table into a table of doubles 62 | import org.opensim.modeling.* 63 | % Check that the input table is a TimesSeriesTable 64 | if isempty(strfind(osimTable.getClass, 'TimeSeriesTable')) 65 | disp('Input is not an OpenSim Times Series Table') 66 | end 67 | % Check that the input table is of Vec3 type 68 | if ~isempty(strfind(osimTable.getClass, 'Vec3')) 69 | postfix = StdVectorString(); 70 | postfix.add('_x'); 71 | postfix.add('_y'); 72 | postfix.add('_z'); 73 | osimTable = osimTable.flatten(postfix); 74 | disp('TimesSeriesVec3 converted to TimesSeriesTable') 75 | end 76 | end 77 | end 78 | 79 | methods (Access = private, Hidden = true) 80 | function table_clone = updateheaderinfo(obj) 81 | table_clone = obj.table.clone(); 82 | if table_clone.getTableMetaDataKeys().size() > 0 83 | for i = 0 : table_clone.getTableMetaDataKeys().size() - 1 84 | % get the metakey string at index zero. Since the array gets smaller on 85 | % each loop, we just need to keep taking the first one in the array. 86 | metakey = char(table_clone.getTableMetaDataKeys().get(0)); 87 | % remove the key from the meta data 88 | table_clone.removeTableMetaDataKey(metakey) 89 | end 90 | end 91 | % Add the column and row data to the meta key 92 | table_clone.addTableMetaDataString('nColumns',num2str(table_clone.getNumColumns()+1)) 93 | table_clone.addTableMetaDataString('nRows',num2str(table_clone.getNumRows())); 94 | end 95 | function updateLabelNames(obj) 96 | table_clone = obj.table.clone(); 97 | labels = table_clone.getColumnLabels(); 98 | for i = 0 : labels.size() - 1 99 | label = char(labels.get(i)); 100 | 101 | if i < 9 102 | n = '1'; 103 | elseif 8 < i < 18; 104 | n = '2'; 105 | elseif 17 < i < 27; 106 | n = '3'; 107 | end 108 | 109 | if ~isempty(strfind(label,'f')) 110 | s = ['ground_force_' n '_v']; 111 | elseif ~isempty(strfind(label,'p')) 112 | s = ['ground_force_' n '_p']; 113 | elseif ~isempty(strfind(label,'m')) 114 | s = ['ground_torque_' n '_m']; 115 | else 116 | error(['Column name ' label ' isnt recognized as a force, point, or moment']) 117 | end 118 | % Get the index for the underscore 119 | % in = strfind(label,'_'); 120 | % add the specifier (f,p,or m) to the label name. 121 | %label_new = [label(1:in) s label(in+1:end)]; 122 | label_new = [s label(end)]; 123 | 124 | % update the label name 125 | labels.set(i,label_new); 126 | end 127 | % set the column labels 128 | table_clone().setColumnLabels(labels) 129 | obj.setTable(table_clone) 130 | end 131 | end 132 | end 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /classManagers/ScalingHelper.m: -------------------------------------------------------------------------------- 1 | classdef ScalingHelper 2 | properties (Access = private) 3 | filepath 4 | filename 5 | scaletool 6 | modelscaler 7 | markerplacer 8 | measurementset 9 | genericmodelmaker 10 | end 11 | methods 12 | function obj = ScalingHelper(filePath) 13 | % Get the path and file name of the input file 14 | [obj.filepath, ohj.filename, ext] = fileparts(filePath); 15 | 16 | import org.opensim.modeling.* 17 | % Instantiate a ScaleTool and store in the object properties 18 | obj.scaletool = ScaleTool(filePath); 19 | % Instantiate a ModelScaler() object from the scaletool 20 | obj.modelscaler = obj.scaletool.getModelScaler(); 21 | % markerplacer 22 | obj.markerplacer = obj.scaletool.getMarkerPlacer(); 23 | % measurement set 24 | obj.measurementset = obj.modelscaler.getMeasurementSet(); 25 | % Generic Model Maker 26 | obj.genericmodelmaker = obj.scaletool.getGenericModelMaker() 27 | 28 | % Check that a model path is assigned 29 | gmm = obj.genericmodelmaker; 30 | % Get the model name 31 | model_file = char(gmm.getModelFileName); 32 | % Check that the model name exists 33 | if ~exist(model_file, 'file') 34 | % If it doesn't exist, give a warning to set the model name. 35 | disp('WARNING: Model is unassigned, update model name with full path') 36 | else 37 | obj.markerplacer.setOutputModelFileName( strrep(model_file,'.osim','_registered.osim')); 38 | obj.modelscaler.setOutputModelFileName(strrep(model_file,'.osim','_scaled.osim')); 39 | end 40 | end 41 | function updModel(obj,modelpath) 42 | if ~exist(modelpath, 'file') 43 | % If it doesn't exist, give a warning to set the model name. 44 | warning('Model cant be found, check input path') 45 | else 46 | [filepath, name, ext] = fileparts(modelpath); 47 | obj.genericmodelmaker.setModelFileName([name ext]) 48 | obj.markerplacer.setOutputModelFileName( strrep([name ext],'_Generic.osim','_registered.osim')); 49 | obj.modelscaler.setOutputModelFileName(strrep([name ext],'_Generic.osim','_scaled.osim')); 50 | end 51 | end 52 | function updMarkerFile(obj,markerpath) 53 | if ~exist(markerpath, 'file') 54 | % If it doesn't exist, give a warning to set the model name. 55 | warning('Model cant be found, check input path') 56 | else 57 | [filepath, name, ext] = fileparts(markerpath); 58 | obj.markerplacer.setMarkerFileName( [name ext] ); 59 | obj.modelscaler.setMarkerFileName( [name ext] ); 60 | end 61 | 62 | end 63 | function dispModelPaths(obj) 64 | disp(['Input Model is: ' char(obj.genericmodelmaker.getModelFileName()) ]); 65 | disp(['Scaled Model : ' char(obj.modelscaler.getOutputModelFileName()) ]); 66 | disp(['moved Model : ' char(obj.markerplacer.getOutputModelFileName())]); 67 | end 68 | function labels = getMeasurementSetNames(obj) 69 | % Get a cell array of label names 70 | nM = obj.measurementset.getSize; 71 | % Go through the list and get the names 72 | labels = strings(19,1); 73 | for i = 0 : nM - 1 74 | labels(i+1) = char(obj.measurementset().get(i).getName); 75 | end 76 | end 77 | function m = getMeasurement(obj, mName) 78 | % Get a reference to a MeasurementSet 79 | mIndex = find(contains(obj.getMeasurementSetNames() , mName))-1; 80 | m = obj.measurementset.get(mIndex); 81 | end 82 | function markerlabels = getMeasurementMarkerNames(obj,mName) 83 | % Get an array of makerNames for the measurement 84 | m = obj.getMeasurement(mName); 85 | % For each marker pair, get the markers and print into a cell 86 | % array 87 | nmpairs = m.getNumMarkerPairs; 88 | markerlabels = strings(nmpairs,2); 89 | for i = 0 : nmpairs - 1 90 | markerlabels(i+1,1) = char(m.getMarkerPair(i).getMarkerName(0)); 91 | markerlabels(i+1,2) = char(m.getMarkerPair(i).getMarkerName(1)); 92 | end 93 | end 94 | function displayMeasurementSetInformation(obj) 95 | labels = getMeasurementSetNames(obj); 96 | 97 | for i = 0 : length(labels) - 1 98 | markerLabels = obj.getMeasurementMarkerNames(labels{i+1}); 99 | disp([num2str(size(markerLabels,1)) ' Marker pairs for Measurement ' labels{i+1} ':']); 100 | disp(markerLabels) 101 | end 102 | end 103 | function replaceMeasurement(obj,measurementName, mkname1, mkname2) 104 | % Get the measurement object 105 | m = obj.getMeasurement(measurementName); 106 | % Get the MarkerPairSet for the Measurement 107 | mps = m.getMarkerPairSet(); 108 | % Update the first pair of markers in the set 109 | mps.get(0).setMarkerName(0,mkname1); 110 | mps.get(0).setMarkerName(1,mkname2); 111 | % Remove any additional marker pairs from the measurement 112 | nmps = mps.getSize(); 113 | if nmps > 1 114 | for i = 1 : nmps - 1 115 | mps.remove(1); 116 | end 117 | end 118 | % Display the new measurement's marker pair 119 | markerlabels = obj.getMeasurementMarkerNames(measurementName); 120 | disp([num2str(size(markerlabels,1)) ' Marker pairs for Measurement ' measurementName ':']); 121 | disp(markerlabels); 122 | end 123 | function filepath = getModelScalerTRCFilePath(obj) 124 | filepath = obj.modelscaler.getMarkerFileName(); 125 | end 126 | function setTRCFilePath(obj,filepath) 127 | obj.modelscaler.setMarkerFileName(filepath); 128 | obj.markerplacer.setMarkerFileName(filepath); 129 | end 130 | function printScaleTool(obj, filepath) 131 | obj.scaletool.print(filepath); 132 | end 133 | function displayIKTasks(obj) 134 | % Display the IK Coordinates Tasks in the command window 135 | ikts = obj.markerplacer().getIKTaskSet(); 136 | % Get the Number of Tasks 137 | nikts = ikts.getSize(); 138 | % Build a strings array of task names, weights, and if the tasks 139 | % are applied. 140 | tasks = strings(nikts, 4); 141 | for i = 0 : nikts - 1 142 | tasks(i+1,1) = num2str(i); 143 | tasks(i+1,2) = char(ikts.get(i).getName()); 144 | tasks(i+1,3) = char(num2str(ikts.get(i).getWeight())); 145 | if ikts.get(i).getApply 146 | tasks(i+1,4) = "True"; 147 | else 148 | tasks(i+1,4) = "False"; 149 | end 150 | end 151 | % Display the results in the Matlab command window as a make 152 | % shift table. 153 | disp( ["Index", "Task","Weight","Applied";"---","---", "---", "---"; tasks] ) 154 | end 155 | function updTaskWeight(obj,taskName, weight) 156 | if ischar(taskName) || isstring(taskName) 157 | obj.markerplacer().getIKTaskSet().get(taskName).setWeight(weight); 158 | elseif isnumeric(taskName) 159 | [r,c] = size(taskName); 160 | for i = taskName 161 | obj.markerplacer().getIKTaskSet().get(i).setWeight(weight); 162 | end 163 | end 164 | end 165 | function updTaskApply(obj,taskName, apply) 166 | obj.markerplacer().getIKTaskSet().get(taskName).setApply(apply); 167 | end 168 | function saveTaskSet(obj,filepath) 169 | % Display the IK Coordinates Tasks in the command window 170 | ikts = obj.markerplacer().getIKTaskSet().print(filepath); 171 | end 172 | 173 | % function filepath = getModelScalerOutputModelFile(obj) 174 | % ms = obj.modelscaler; 175 | % end 176 | % function setModelScalerOutputModelFile(obj) 177 | % filepath = obj.modelscaler; 178 | % end 179 | 180 | end 181 | end 182 | -------------------------------------------------------------------------------- /classManagers/TRCWorker.m: -------------------------------------------------------------------------------- 1 | classdef TRCWorker < matlab.mixin.SetGet 2 | properties 3 | table 4 | name 5 | path 6 | end 7 | methods 8 | function readTRC(obj) 9 | import org.opensim.modeling.* 10 | if isempty(obj.name) 11 | error('name not set. use setName() to set a file name') 12 | elseif isempty(obj.path) 13 | error('path not set. use setPath() to set a file path') 14 | end 15 | % define the absolute path to the file 16 | fullfilepath = fullfile(obj.path, [obj.name '.trc']); 17 | % Use the OpenSim adapter to read the file 18 | table = TRCFileAdapter().read(fullfilepath) 19 | % set the objects table 20 | obj.setTable(table) 21 | end 22 | function writeTRC(obj) 23 | import org.opensim.modeling.* 24 | if isempty(obj.name) 25 | error('name not set. use setName() to set a file name') 26 | elseif isempty(obj.path) 27 | error('path not set. use setPath() to set a file path') 28 | end 29 | % edit the marker names for errors (spaces, *, ...) 30 | obj.updateMarkerNames() 31 | % define the absolute path to the file 32 | fullfilepath = fullfile(obj.path, [obj.name '.trc']); 33 | 34 | % use OpenSim file adapter to print the table to file 35 | TRCFileAdapter().write(obj.table, fullfilepath ); 36 | 37 | display(['TRC file written: ' fullfilepath ]); 38 | end 39 | function setTable(obj,osimtable) 40 | % Sets the internal table to a new table 41 | 42 | % check that the input class is correct 43 | obj.tablecheck(osimtable) 44 | % update the internal table 45 | obj.table = osimtable; 46 | end 47 | function setName(obj,name) 48 | % Set the filename 49 | obj.name = name; 50 | end 51 | function setPath(obj, path) 52 | % set the directory path 53 | obj.path = path; 54 | end 55 | end 56 | methods (Access = private, Hidden = true) 57 | function updateMarkerNames(obj) 58 | table_clone = obj.table.clone(); 59 | labels = table_clone.getColumnLabels(); 60 | for i = 0 : labels.size() - 1 61 | label = char(labels.get(i)); 62 | 63 | if ~isempty(strfind(label,' ')) 64 | label = strrep(label,' ','_'); 65 | elseif ~isempty(strfind(label,'*')) 66 | label = strrep(label,'*','_'); 67 | end 68 | labels.set(i,label); 69 | end 70 | % set the column labels 71 | table_clone().setColumnLabels(labels) 72 | obj.setTable(table_clone) 73 | end 74 | function tablecheck(obj,osimtable) 75 | 76 | if isempty(strfind(osimtable.getClass, 'TimeSeriesTable')) 77 | error('Input is not an OpenSim Times Series Table') 78 | end 79 | 80 | if isempty(strfind(osimtable.getClass, 'Vec3')) 81 | error('Input is not an OpenSim Vec3 Times Series Table') 82 | end 83 | end 84 | end 85 | end -------------------------------------------------------------------------------- /classManagers/ikHelper.m: -------------------------------------------------------------------------------- 1 | classdef ikHelper < matlab.mixin.SetGet 2 | properties (Access = private) 3 | modelFileName 4 | markerFileName 5 | model 6 | markerdata 7 | markerLabels 8 | markerWeightSet 9 | stime 10 | etime 11 | dt 12 | errors 13 | locations 14 | angles 15 | end 16 | methods 17 | function obj = ikHelper(modelFileName, markerFileName) 18 | import org.opensim.modeling.* 19 | 20 | modelFileName = modelFileName; 21 | markerFileName = markerFileName; 22 | 23 | model = Model(modelFileName); 24 | markerdata = TRCFileAdapter().readFile(markerFileName); 25 | 26 | % Get a list of all the trackable markers in the model and the 27 | % data. 28 | markerLabelsInModel = {}; 29 | for i = 0 :model.getMarkerSet().getSize() - 1 30 | markerLabelsInModel = [markerLabelsInModel ; {char(model.getMarkerSet().get(i).getName)}]; 31 | end 32 | 33 | markerLabelsInData = {}; 34 | for i = 0 :markerdata.getNumColumns() - 1 35 | markerLabelsInData = [markerLabelsInData ; {char(markerdata.getColumnLabels().get(i))}]; 36 | end 37 | 38 | % Get the list markers that have data to track. 39 | MarkersInBoth = intersect(markerLabelsInData,markerLabelsInModel); 40 | 41 | % Edit Model to remove all markers not in both 42 | markerLabels = {}; 43 | for i = 1 : length(markerLabelsInModel) 44 | if ~sum(ismember(MarkersInBoth, markerLabelsInModel{i})) 45 | m =model.getMarkerSet().get(markerLabelsInModel{i}); 46 | model.getMarkerSet().remove(m); 47 | else 48 | markerLabels = [markerLabels;markerLabelsInModel(i)]; 49 | end 50 | end 51 | 52 | % Make an OpenSim makerWeightsSet with default MarkerWeights. 53 | markerWeightSet = SetMarkerWeights(); 54 | for i = 1 : length(markerLabels) 55 | markerWeightSet.cloneAndAppend( MarkerWeight(markerLabels{i}, 1 ) ); 56 | end 57 | markerWeightSet = markerWeightSet; 58 | 59 | 60 | % Make default start and end times from the markerdata 61 | stime =markerdata.getIndependentColumn().get(0); 62 | etime =markerdata.getIndependentColumn().get(... 63 | markerdata.getIndependentColumn().size()-1); 64 | % Get the dataRate 65 | dataRate = str2num(markerdata.getTableMetaDataAsString('DataRate')); 66 | 67 | obj.modelFileName = modelFileName; 68 | obj.markerFileName = markerFileName; 69 | obj.model = model; 70 | obj.markerdata = markerdata; 71 | obj.markerLabels = markerLabels; 72 | obj.markerWeightSet = markerWeightSet; 73 | obj.stime = stime; 74 | obj.etime = etime; 75 | obj.dt = 1/dataRate; 76 | obj.errors = []; 77 | obj.locations = []; 78 | obj.angles = []; 79 | end 80 | function o = getStartTime(obj) 81 | o = obj.stime; 82 | end 83 | function o = getEndTime(obj) 84 | o = obj.etime; 85 | end 86 | function o = getMarkerLabels(obj) 87 | o = obj.markerLabels; 88 | end 89 | function o = getMarkerWeightSet(obj) 90 | import org.opensim.modeling.* 91 | o = obj.markerWeightSet.clone(); 92 | end 93 | function setMarkerWeight(obj,markerName,weight) 94 | for i = 0 : obj.markerWeightSet.getSize - 1 95 | if contains(char(obj.markerWeightSet.get(i).getName()),markerName) 96 | obj.markerWeightSet.get(i).setWeight(weight); 97 | break 98 | elseif i == obj.markerWeightSet.getSize - 1 99 | error(['Marker Name, ' markerName ', not found in Marker Set']) 100 | end 101 | end 102 | end 103 | function o = getErrors(obj) 104 | o = obj.errors; 105 | end 106 | function o = getAngles(obj) 107 | o = obj.angles; 108 | end 109 | function printErrors(obj, filename) 110 | 111 | end 112 | function printMot(obj,filename) 113 | import org.opensim.modeling.* 114 | 115 | 116 | dataTable = DataTable(); 117 | [nRows, nCols] = size(obj.angles); 118 | 119 | cLables = StdVectorString(); 120 | for i = 0 : obj.model.getCoordinateSet().getSize() - 1 121 | cLables.add(char(obj.model.getCoordinateSet().get(i).getName())) 122 | end 123 | dataTable.setColumnLabels(cLables); 124 | 125 | row = RowVector(obj.model.getCoordinateSet().getSize()); 126 | for u = 1 : nRows 127 | for i = 0 : obj.model.getCoordinateSet().getSize() - 1 128 | 129 | if contains(char(obj.model.getCoordinateSet().get(i).getMotionType),'Rotational') 130 | % Convert from Rad to Deg if rotational 131 | row.set(i, rad2deg(obj.angles(u,i+1))); 132 | else 133 | row.set(i, obj.angles(u,i+1)); 134 | end 135 | end 136 | t = obj.stime + (u-1)*obj.dt; 137 | dataTable.appendRow( t , row); 138 | end 139 | 140 | % Add Meta Data Key 141 | dataTable.addTableMetaDataString('Coordinates',''); 142 | dataTable.addTableMetaDataString('DataRate',num2str(fix(1/obj.dt))); 143 | dataTable.addTableMetaDataString('inDegrees','yes'); 144 | 145 | % Convert to a time series table 146 | tst = TimeSeriesTable(dataTable); 147 | % Write table to file 148 | STOFileAdapter().write(tst,filename) 149 | end 150 | function run(obj) 151 | 152 | import org.opensim.modeling.* 153 | 154 | markerref = MarkersReference( obj.markerdata,... 155 | obj.markerWeightSet,... 156 | Units('m')); 157 | 158 | % Instantiate the ikSolver and set some values. 159 | ikSolver = InverseKinematicsSolver(obj.model,... 160 | markerref,... 161 | SimTKArrayCoordinateReference(),... 162 | Inf); 163 | % Set ikSolver accuracy 164 | accuracy = 1e-5; 165 | ikSolver.setAccuracy(accuracy); 166 | 167 | s = obj.model.initSystem(); 168 | s.setTime(obj.stime); 169 | 170 | ikSolver.assemble(s); 171 | 172 | errors = []; 173 | angles = []; 174 | locations = []; 175 | currentTime = obj.stime; 176 | while currentTime < obj.etime 177 | s.setTime(currentTime); 178 | % Perform tracking 179 | ikSolver.track(s); 180 | % get the marker errors 181 | nRow = size(errors,1); 182 | for u = 0 : ikSolver.getNumMarkersInUse() - 1 183 | errors(nRow+1, u+1) = ikSolver.computeCurrentMarkerError(u); 184 | end 185 | % Get the Model Marker Locations 186 | for u = 0 : ikSolver.getNumMarkersInUse() - 1 187 | location = ikSolver.computeCurrentMarkerLocation(u); 188 | locations(nRow+1,(u+1)*3-2:(u+1)*3) = [location.get(0) location.get(1) location.get(2)]; 189 | end 190 | % Get the Coordinates Values 191 | obj.model.realizeVelocity(s); 192 | % Get the coordinate Set 193 | cs = obj.model.getCoordinateSet(); 194 | nvalues = cs.getSize(); 195 | for u = 0 : nvalues - 1 196 | angles(nRow+1,u+1) = cs().get(u).getValue(s); 197 | end 198 | % Move ahead in time and repeat. 199 | currentTime = currentTime + obj.dt; 200 | end 201 | 202 | % Update the objects properties with these new values 203 | obj.errors = errors; 204 | obj.locations = locations; 205 | obj.angles = angles; 206 | end 207 | end 208 | end -------------------------------------------------------------------------------- /classManagers/osimIK.m: -------------------------------------------------------------------------------- 1 | classdef osimIK < matlab.mixin.SetGet 2 | %% ikManager Manages OpenSim IK analysis for muliple trc files. 3 | % Class that instantiates an IKSolver and manages which files, 4 | % and for which times, the solver performs IK. The IK Solver also 5 | % calculates and tracks summed marker error. The ikManager takes a 6 | % trcManager on construction. A trcManager holds all of the trc data 7 | % and has functions specifically for editing and sampling trc files. 8 | % 9 | % 10 | properties 11 | model 12 | trcm 13 | data 14 | trackableMarkerList 15 | ik 16 | weights 17 | markerrefs 18 | startTime 19 | endTime 20 | timeArray 21 | errors 22 | coordinateTable 23 | end 24 | methods 25 | function self = osimIK(model, trcm) 26 | import org.opensim.modeling.* 27 | % Determine the trackable markers 28 | trackableMarkers = osimTRC.getTrackableMarkerList(model, trcm.getDataTableClone()); 29 | % Make an OpenSim makerWeightsSet with default MarkerWeights. 30 | markerWeightSet = SetMarkerWeights(); 31 | for i = 1 : length(trackableMarkers) 32 | markerWeightSet.cloneAndAppend( MarkerWeight(trackableMarkers{i}, 1)); 33 | end 34 | markerWeightSet.setName('default_markerWeightSet'); 35 | % Generate a Marker Reference Object 36 | markerref = MarkersReference(trcm.getDataTableClone(),... 37 | markerWeightSet, Units('m')); 38 | % Set Values for internal properties. 39 | self.model = model; 40 | self.trcm = trcm; 41 | self.data = trcm.getDataTableClone(); 42 | self.trackableMarkerList = trackableMarkers; 43 | self.weights = markerWeightSet; 44 | self.markerrefs = markerref; 45 | self.startTime = trcm.getTimeStart(); 46 | self.endTime = trcm.getTimeEnd(); 47 | self.timeArray = trcm.getTimeArray; 48 | end 49 | function mweights = getMarkerWeights(self) 50 | mweights = self.weights.clone(); 51 | end 52 | function setMarkerWeights(self, mweights) 53 | import org.opensim.modeling.* 54 | % Set the internal marker weights object 55 | self.weights = mweights(); 56 | % update the marker ref object with the new weights. 57 | markerref = MarkersReference(self.data,... 58 | mweights, Units('m')); 59 | self.markerrefs = markerref; 60 | end 61 | function setStartTime(self, stime) 62 | if stime < self.startTime || stime > self.endTime 63 | error('Start time is out of bounds.') 64 | else 65 | self.startTime = stime; 66 | end 67 | end 68 | function setEndTime(self, etime) 69 | if etime > self.endTime || etime < self.startTime 70 | error('End time is out of bounds.') 71 | else 72 | self.endTime = etime; 73 | end 74 | end 75 | function stime = getStartTime(self) 76 | stime = self.startTime; 77 | end 78 | function etime = getEndTime(self) 79 | etime = self.endTime; 80 | end 81 | function run(self) 82 | import org.opensim.modeling.* 83 | % Clone model components 84 | model = self.model.clone(); 85 | % Add a reporter to the model 86 | ikReporter = TableReporter(); 87 | ikReporter.setName("ik_reporter"); 88 | coordinates = model.getCoordinateSet(); 89 | for i = 0 : model.getNumCoordinates() - 1 90 | coord = coordinates.get(i); 91 | ikReporter.updInput('inputs').connect(coord.getOutput('value'), coord.getName()); 92 | end 93 | model.addComponent(ikReporter); 94 | s = model.initSystem(); 95 | % Instantiate the ikSolver 96 | ik = InverseKinematicsSolver(model,... 97 | self.markerrefs,... 98 | SimTKArrayCoordinateReference(),... 99 | Inf); 100 | 101 | % Set ikSolver accuracy 102 | accuracy = 1e-5; 103 | ik.setAccuracy(accuracy); 104 | % Assemble the model 105 | s.setTime(self.startTime()); 106 | ik.assemble(s); 107 | 108 | % Get the coordinate Set 109 | errors = []; 110 | currentTime = self.timeArray(1); 111 | for i = 1 : length( self.timeArray() ) 112 | disp(['Running IK for time ' num2str(self.timeArray(i))]) 113 | s.setTime( self.timeArray(i) ); 114 | % Perform tracking 115 | ik.track(s); 116 | % get the marker errors 117 | for u = 0 : ik.getNumMarkersInUse() - 1 118 | errors(i, u+1) = ik.computeCurrentMarkerError(u); 119 | end 120 | model.realizeReport(s) 121 | end 122 | self.coordinateTable = ikReporter.getTable().clone(); 123 | self.errors = errors; 124 | end 125 | function writeMot(self, outputFileName) 126 | import org.opensim.modeling.* 127 | % Build a TimeSeriesTable for angles 128 | data = self.coordinateTable; 129 | % Update rotational coordinates into degrees 130 | tst = self.updateDegrees(data); 131 | % Add meta data 132 | tst.addTableMetaDataString('inDegrees', 'yes'); 133 | % Write to file 134 | STOFileAdapter.write(tst, outputFileName); 135 | disp([outputFileName ' written to file. ']); 136 | end 137 | function writeMarkerErrors(self, outputFileName) 138 | 139 | end 140 | function total_error = getTotalError(self) 141 | % Compute the sum of all the marker errors 142 | total_error = sum(sum(self.errors)); 143 | end 144 | end 145 | methods (Access = private, Hidden = true) 146 | function tst = buildTimeSeriesTable(self, data, labels, timeArray) 147 | import org.opensim.modeling.* 148 | 149 | times = self.data.getIndependentColumn(); 150 | 151 | [nt, nc] = size(data); 152 | matrix = Matrix(nt,nc); 153 | 154 | for i = 0 : times.size() - 1 155 | for j = 0 : nc - 1 156 | matrix.set(i, j, data(i+1,j+1) ); 157 | end 158 | end 159 | % Generate a Table of rotations using the new Matrix 160 | tst = TimeSeriesTable(times, matrix, labels); 161 | end 162 | function tst = updateDegrees(self, tst) 163 | import org.opensim.modeling.* 164 | disp('Converting Radians to Degrees') 165 | cs = self.model.getCoordinateSet(); 166 | for i = 0 : cs.getSize() - 1 167 | if strcmp('Rotational', char(cs.get(i).getMotionType())) 168 | for u = 0 : tst.getNumRows() - 1 169 | r = tst.getRowAtIndex(u); 170 | r.set(i, rad2deg(r.getElt(0,i))); 171 | end 172 | end 173 | end 174 | end 175 | end 176 | end 177 | -------------------------------------------------------------------------------- /classManagers/osimTRC.m: -------------------------------------------------------------------------------- 1 | classdef osimTRC < matlab.mixin.SetGet 2 | % osimTRC(filePath) 3 | % Class for reading and operating on TRC Files. 4 | properties (Access = private) 5 | filepath 6 | filename 7 | workingTable 8 | recoveryTable 9 | end 10 | methods 11 | function self = osimTRC(path2TRC) 12 | % Constructor for the osimTRC manager. Takes a path to a trc 13 | 14 | % load java libs 15 | import org.opensim.modeling.* 16 | % Use a c3dAdapter to read the c3d file 17 | self.workingTable = TimeSeriesTableVec3(path2TRC); 18 | % Store a backup Table that can be recovered 19 | self.recoveryTable = self.workingTable; 20 | % Store some path names for the 21 | [self.filepath, self.filename, ext] = fileparts(path2TRC); 22 | end 23 | function p = getTRCPath(self) 24 | p = self.filepath(); 25 | end 26 | function n = getTRCName(self) 27 | n = self.filename(); 28 | end 29 | function n = getNumRows(self) 30 | % Get the number of Rows of Data 31 | n = self.workingTable.getNumRows(); 32 | end 33 | function n = getNumMarkers(self) 34 | % Get the number of markers in the c3d file 35 | n = self.workingTable.getNumColumns(); 36 | end 37 | function timecol = getTimeArray(self) 38 | % Get the time column 39 | timecol = zeros(self.getNumRows() , 1); 40 | for i = 1 : self.getNumRows() 41 | timecol(i) = self.workingTable.getIndependentColumn().get(i-1); 42 | end 43 | end 44 | function t = getTimeStart(self) 45 | % Get the start time of the c3d file 46 | timeArray = self.getTimeArray(); 47 | format long g 48 | t = timeArray(1); 49 | end 50 | function t = getTimeEnd(self) 51 | % Get the end time of the c3d file 52 | timeArray = self.getTimeArray(); 53 | format long g 54 | t = timeArray(end); 55 | end 56 | function labels = getMarkerLabels(self) 57 | % Get the list of marker labels 58 | labels = strings(self.getNumMarkers(),1); 59 | for i = 1 : self.getNumMarkers() 60 | labels(i) = char(self.workingTable.getColumnLabel(i-1)); 61 | end 62 | end 63 | function table = getDataTableClone(self) 64 | table = self.workingTable.clone(); 65 | end 66 | function trcStruct = getDataAsStructs(self) 67 | % Convert the OpenSim tables into Matlab Structures 68 | trcStruct = osimTableToStruct(self.workingTable); 69 | end 70 | function data = getMarkerData(self, markerName) 71 | % Get a Matlab array of data points for a specific trajectory 72 | % Get Index from the markername 73 | mIndex = find(contains(self.getMarkerLabels() , markerName))-1; 74 | if isempty(mIndex) 75 | error(['Marker label ' markerName ' not found.']); 76 | end 77 | % Get the column vector at index 78 | cv = self.workingTable.getDependentColumnAtIndex(mIndex); 79 | % Convert the colomn vector into a Matlab array 80 | data = zeros(self.getNumRows(), 3); 81 | for i = 0 : self.getNumRows() - 1 82 | data(i+1,:) = osimVec3ToArray( cv.get(i) ); 83 | end 84 | end 85 | function addMarker(self, markerName, data) 86 | import org.opensim.modeling.* 87 | % Validate input data? must have correct number of rows 88 | [nr,nc] = size(data); 89 | if nr ~= self.getNumRows 90 | error('Input data length ~= target data length') 91 | elseif nc ~= 3 92 | error('Input data does not have 3 columns') 93 | end 94 | % Instantiate an empty Column vector of vec3's 95 | markerVector = RowVectorVec3(self.getNumRows); 96 | % % Resize the Vector for the current table size 97 | % markerVector.resize(self.getNumRows,1); 98 | % Fill the vector with the input data 99 | for i = 0 : self.getNumRows - 1 100 | markerVector.set(i, osimVec3FromArray( data(i+1,:) ) ); 101 | end 102 | % Append the vector to the current table 103 | self.workingTable.appendColumn(markerName,markerVector); 104 | % Update table meta data key for number of markers 105 | self.updMetaData('NumMarkers', self.workingTable.getNumColumns); 106 | % Display some information to the user 107 | disp(['Marker ' markerName ' successfully added to the table']); 108 | end 109 | function addMeanOfTwoMarkers(self, NewMarkerlabel ,mk1, mk2) 110 | % Compute the new marker vector 111 | data = (self.getMarkerData(mk1) + self.getMarkerData(mk2))/2; 112 | % Add the New Marker to the Table 113 | self.addMarker(NewMarkerlabel,data) 114 | end 115 | function addZeroProjectionMarker(self, mk) 116 | % Computes a marker projected on the floor of the lab (Y = 0). 117 | % Adds the marker to the internal table. 118 | data = self.getMarkerData(mk); 119 | % Zero all Y values. This assumes the data is correctly rotated. 120 | data(:,2) = zeros(size(data,1),1); 121 | % Add new marker to the table 122 | self.addMarker([mk '_proj'],data); 123 | end 124 | function recoverOriginalTable(self) 125 | % Overrides working table with stored backup copy of table 126 | answer = questdlg('Any and all changes to the current table will be lost, Continue?', ... 127 | 'Revert to Original Data Table', ... 128 | 'Yes','No',''); 129 | % Handle response 130 | switch answer 131 | case 'Yes' 132 | self.workingTable = self.recoveryTable.clone(); 133 | disp('Current working Table reverted to original table') 134 | case 'No' 135 | disp('No changes made to current table') 136 | end 137 | end 138 | function writeTRC(self,postfix) 139 | % Write marker data to trc file. 140 | import org.opensim.modeling.* 141 | % validate the postfix so that the original file doesn't get 142 | % overidden. 143 | if isempty(postfix) 144 | error('Function must have a string so original file isnt overwritten') 145 | end 146 | % Compute an output path to use for writing to file 147 | outputPath = fullfile(self.filepath,[self.filename postfix '.trc']); 148 | % Write to file 149 | TRCFileAdapter().write( self.workingTable, outputPath); 150 | disp(['Marker file written to ' outputPath]); 151 | end 152 | function u = getUnits(self) 153 | u = char(self.workingTable.getTableMetaDataAsString('Units')); 154 | end 155 | function updUnits(self,InputChar) 156 | if ~ischar(InputChar) 157 | error('input must by of type string (char)') 158 | end 159 | % Get the current Unit value 160 | u = self.getUnits(); 161 | % Update the Unit value 162 | self.updMetaData('Units', InputChar) 163 | % display change to the User 164 | disp(['Changed Units from ' u ' to ' self.getUnits()]); 165 | end 166 | function t = getTableSlice(self, sTime, eTime) 167 | t = self.workingTable().clone(); 168 | t.trim(sTime,eTime) 169 | end 170 | function writeTableSlice(self, sTime, eTime, filePath) 171 | import org.opensim.modeling.* 172 | table = self.getTableSlice(sTime,eTime); 173 | TRCFileAdapter().write(table, filePath) 174 | end 175 | end 176 | methods (Static) 177 | function trackableMarkers = getTrackableMarkerList(model, mTable) 178 | % Determine the trackable markers in the trial 179 | import org.opensim.modeling.* 180 | % Get all the marker labels in a table 181 | labels = mTable.getColumnLabels(); 182 | markerlabels = {}; 183 | for i = 0 : labels.size() - 1 184 | markerlabels(i+1) = {char(labels.get(i))}; 185 | end 186 | % Get all the marker labels in a model 187 | markerset w= model.getMarkerSet(); 188 | modelmarkerlabels = {}; 189 | for i = 0 : markerset.getSize() - 1 190 | modelmarkerlabels(i+1) = {char(markerset.get(i).getName())}; 191 | end 192 | % Generate a list from the intersect of both lists 193 | trackableMarkers = intersect(markerlabels,modelmarkerlabels); 194 | end 195 | end 196 | methods (Access = private, Hidden = true) 197 | function updMetaData(self, KeyName, Value) 198 | % Update a table meta data key value 199 | if isnumeric(Value) 200 | Value = num2str(Value); 201 | elseif ~ischar(Value) 202 | error('MetaDataKey value must be a number of a char') 203 | end 204 | % Does the meta data key exist? 205 | self.workingTable.hasTableMetaDataKey(KeyName); 206 | % Remove the Key 207 | self.workingTable.removeTableMetaDataKey(KeyName); 208 | % Add the Key back with the updated value 209 | self.workingTable.addTableMetaDataString(KeyName, Value); 210 | end 211 | end 212 | end 213 | -------------------------------------------------------------------------------- /classManagers/solverIK.m: -------------------------------------------------------------------------------- 1 | function [locations, errors, angles,anglesPacked] = solverIK(model, trcpath, markerList, weights) 2 | %% solverIK is a Matlab interface to the OpenSim IKSolver(). 3 | % Inputs are an OpenSim Model, path to a trc file, list of markers to be 4 | % tracked, and an array of weights corresponding with each marker. 5 | % 6 | % Outputs are the locations of the model markers, the errors between the 7 | % model and experimental markers, a coordinate value array (without labels), 8 | % and a struct of coordinate values (allocated labels). 9 | % 10 | 11 | % use the IK solver and report back the individual marker errors. 12 | import org.opensim.modeling.* 13 | % Initialize OpenSim model 14 | s = model.initSystem(); 15 | nM = length(markerList); 16 | %% get lists of the marker and coordinate names 17 | % markerNames = []; 18 | % for i = 0 : model.getMarkerSet().getSize()-1; 19 | % markerNames = [markerNames {char(model.getMarkerSet().get(i).getName() )}]; 20 | % end 21 | % 22 | % trcNames = []; 23 | % for i = 0 : t.getNumColumns() - 1 24 | % trcNames = [trcNames {char(t.getColumnLabels().get(i))}]; 25 | % end 26 | % Generate a final list of Markers to track 27 | % markerList = intersect(markerNames,trcNames); 28 | 29 | coordName = []; 30 | for i = 0 : model.getCoordinateSet().getSize()-1; 31 | coordName = [coordName {char(model.getCoordinateSet().get(i).getName() )}]; 32 | end 33 | 34 | %% Populate markers reference object with desired marker weights 35 | markerWeights = SetMarkerWeights(); 36 | for i = 1 : length(markerList) 37 | markerWeights.cloneAndAppend( MarkerWeight(markerList{i}, weights(i) ) ); 38 | end 39 | 40 | % Set marker weights 41 | markerref = MarkersReference(); 42 | markerref.setMarkerWeightSet(markerWeights) 43 | % Create an arry of blank coordinate reference objects 44 | coordref = SimTKArrayCoordinateReference(); 45 | 46 | % Populate coordinate references object with desired coordinate values 47 | % and weights 48 | for i = 1 : length(coordName) 49 | coordRef = CoordinateReference(coordName{i} , Constant() ); 50 | coordRef.setWeight(0); 51 | coordRef.markAdopted(); 52 | coordref.push_back(coordRef); 53 | end 54 | 55 | %% Define kinematics reporter for output 56 | % Load marker data 57 | % markerref.loadMarkersFile(trcpath) % , Units('Millimeters')); 58 | markerref.loadMarkersFile(trcpath) 59 | 60 | % Get start and end times 61 | timeRange = markerref.getValidTimeRange(); 62 | startTime = timeRange.get(0); 63 | endTime = timeRange.get(1); 64 | 65 | % Define constraint weight 66 | constweight = Inf; 67 | 68 | %% Instantiate the ikSolver and set some values. 69 | ikSolver = InverseKinematicsSolver(model,markerref, coordref,constweight); 70 | % Set ikSolver accuracy 71 | accuracy = 1e-5; 72 | ikSolver.setAccuracy(accuracy); 73 | % Assemble the model 74 | s.setTime(startTime); 75 | ikSolver.assemble(s); 76 | 77 | %% Loop through markers and define weights 78 | % for i = 0 : model.getMarkerSet().getSize() - 1 79 | % ikSolver.updateMarkerWeight(i,1); 80 | % end 81 | 82 | % Loop through IK coordinate tasks and define values and weights 83 | for i = 1 : model.getCoordinateSet().getSize() 84 | ikSolver.updateCoordinateReference(coordName{i},0); 85 | end 86 | 87 | %% Compute dt and nFrames 88 | dt = 1.0/markerref.getSamplingFrequency(); 89 | nFrames = round(( (endTime-startTime)/dt )+1); 90 | 91 | %% Perform IK analysis 92 | disp('Starting IK analysis') 93 | errors = []; 94 | angles = []; 95 | locations = []; 96 | for i = 0 : nFrames - 1 97 | % set the time 98 | s.setTime(startTime+i*dt); 99 | % run the iksolver for the time 100 | ikSolver.track(s); 101 | % Get the marker errors 102 | for u = 0 : nM - 1 103 | errors(i+1,u+1) = ikSolver.computeCurrentMarkerError(u); 104 | end 105 | % Get the Model Marker Locations 106 | for u = 0 : nM - 1 107 | location = ikSolver.computeCurrentMarkerLocation(u); 108 | locations(i+1,(u+1)*3-2:(u+1)*3) = [location.get(0) location.get(1) location.get(2)]; 109 | end 110 | % Get the Coordinates Values 111 | model.realizeVelocity(s); 112 | % Get the coordinate Set 113 | cs = model.getCoordinateSet(); 114 | nvalues = cs.getSize(); 115 | for u = 0 : nvalues - 1 116 | angles(i+1,u+1) = cs().get(u).getValue(s); 117 | end 118 | end 119 | 120 | %% Pack the angles 121 | anglesPacked = struct(); 122 | for u = 0 : nvalues - 1 123 | name = char(cs.get(u).getName()); 124 | if ~isempty(strfind(name,'tx')) || ~isempty(strfind(name,'ty')) || ~isempty(strfind(name,'tz')) 125 | eval(['anglesPacked.' char(cs.get(u).getName()) '= angles(:,u+1);']) 126 | else 127 | % Angles are in rad. COnvert to deg 128 | eval(['anglesPacked.' char(cs.get(u).getName()) '= rad2deg(angles(:,u+1));']) 129 | end 130 | end 131 | 132 | anglesPacked.time = [startTime:dt:endTime]'; 133 | 134 | 135 | end -------------------------------------------------------------------------------- /classManagers/solverIK_backup.m: -------------------------------------------------------------------------------- 1 | function [locations, errors, angles,anglesPacked] = solverIK(model, trcpath, markerList, weights) 2 | %% solverIK is a Matlab interface to the OpenSim IKSolver(). 3 | % Inputs are an OpenSim Model, path to a trc file, list of markers to be 4 | % tracked, and an array of weights corresponding with each marker. 5 | % 6 | % Outputs are the locations of the model markers, the errors between the 7 | % model and experimental markers, a coordinate value array (without labels), 8 | % and a struct of coordinate values (allocated labels). 9 | % 10 | 11 | % Use the IK solver and report back the individual marker errors. 12 | import org.opensim.modeling.* 13 | % Initialize OpenSim model 14 | s = model.initSystem(); 15 | nM = length(markerList); 16 | trcTable = TRCFileAdapter().read(trcpath); 17 | trcTable.removeTableMetaDataKey('Units') 18 | trcTable.addTableMetaDataString('Units','Meters') 19 | 20 | 21 | 22 | 23 | %% get lists of the marker and coordinate names 24 | % markerNames = []; 25 | % for i = 0 : model.getMarkerSet().getSize()-1; 26 | % markerNames = [markerNames {char(model.getMarkerSet().get(i).getName() )}]; 27 | % end 28 | % 29 | % trcNames = []; 30 | % for i = 0 : t.getNumColumns() - 1 31 | % trcNames = [trcNames {char(t.getColumnLabels().get(i))}]; 32 | % end 33 | % Generate a final list of Markers to track 34 | % markerList = intersect(markerNames,trcNames); 35 | 36 | coordName = []; 37 | for i = 0 : model.getCoordinateSet().getSize()-1; 38 | coordName = [coordName {char(model.getCoordinateSet().get(i).getName() )}]; 39 | end 40 | 41 | %% Populate markers reference object with desired marker weights 42 | markerWeights = SetMarkerWeights(); 43 | for i = 1 : length(markerList) 44 | markerWeights.cloneAndAppend( MarkerWeight(markerList{i}, weights(i) ) ); 45 | end 46 | 47 | %% Make a Marker Reference Object 48 | markerref = MarkersReference(trcTable,markerWeights,Units('Meters')); 49 | 50 | % Get Time values from MarkerRef 51 | timeRange = markerref.getValidTimeRange(); 52 | startTime = timeRange.get(0); 53 | endTime = timeRange.get(1); 54 | 55 | %% Create an arry of blank coordinate reference objects 56 | coordref = SimTKArrayCoordinateReference(); 57 | 58 | % % Populate coordinate references object with desired coordinate values 59 | % % and weights 60 | % for i = 1 : length(coordName) 61 | % coordRef = CoordinateReference(coordName{i} , Constant() ); 62 | % coordRef.setWeight(0); 63 | % coordRef.markAdopted(); 64 | % coordref.push_back(coordRef); 65 | % end 66 | 67 | %% Define kinematics reporter for output 68 | 69 | %% Define constraint weight 70 | constweight = Inf; 71 | 72 | %% Instantiate the ikSolver and set some values. 73 | ikSolver = InverseKinematicsSolver(model,markerref,coordref,constweight); 74 | % Set ikSolver accuracy 75 | accuracy = 1e-5; 76 | ikSolver.setAccuracy(accuracy); 77 | 78 | % %% Loop through IK coordinate tasks and define values and weights 79 | % for i = 0 : model.getMarkerSet().getSize() - 1 80 | % ikSolver.updateMarkerWeight(i,1); 81 | % end 82 | % for i = 1 : model.getCoordinateSet().getSize() 83 | % ikSolver.updateCoordinateReference(coordName{i},0); 84 | % end 85 | 86 | %% Compute dt and nFrames 87 | dt = 1.0/markerref.getSamplingFrequency(); 88 | nFrames = round(( (endTime-startTime)/dt )+1); 89 | 90 | %% Assemble the model 91 | s.setTime(startTime); 92 | time = startTime; 93 | validTime = []; 94 | 95 | disp('Assessing ability to assemble...' ); 96 | while time <= endTime 97 | s.setTime(time); 98 | try 99 | ikSolver.assemble(s); 100 | validTime(length(validTime)+1,1) = time; 101 | catch 102 | % Don't need it to do anything 103 | end 104 | % Increment time; 105 | time = round(time + dt, 3); 106 | end 107 | disp(['IK is only possible from time= ' num2str(validTime(1)) ' to ' num2str(validTime(end)) ]); 108 | 109 | %% Perform IK analysis 110 | disp('Starting IK analysis') 111 | errors = []; 112 | angles = []; 113 | locations = []; 114 | % Get a fresh State 115 | s = model.initSystem(); 116 | 117 | for i = 1 : length(validTime) 118 | % Set the time 119 | s.setTime(validTime(i)); 120 | % 121 | if i == 1 122 | ikSolver.assemble(s); 123 | end 124 | % run the iksolver for the time 125 | ikSolver.track(s); 126 | end 127 | % Get the marker errors 128 | for u = 0 : nM - 1 129 | errors(i,u+1) = ikSolver.computeCurrentMarkerError(u); 130 | end 131 | % Get the Model Marker Locations 132 | for u = 0 : nM - 1 133 | location = ikSolver.computeCurrentMarkerLocation(u); 134 | locations(i,(u+1)*3-2:(u+1)*3) = [location.get(0) location.get(1) location.get(2)]; 135 | end 136 | % Get the Coordinates Values 137 | model.realizeVelocity(s); 138 | % Get the coordinate Set 139 | cs = model.getCoordinateSet(); 140 | nvalues = cs.getSize(); 141 | for u = 0 : nvalues - 1 142 | angles(i,u+1) = cs().get(u).getValue(s); 143 | end 144 | end 145 | 146 | %% Pack the angles 147 | anglesPacked = struct(); 148 | for u = 0 : nvalues - 1 149 | name = char(cs.get(u).getName()); 150 | if ~isempty(strfind(name,'tx')) || ~isempty(strfind(name,'ty')) || ~isempty(strfind(name,'tz')) 151 | eval(['anglesPacked.' char(cs.get(u).getName()) '= angles(:,u+1);']) 152 | else 153 | % Angles are in rad. Convert to deg 154 | eval(['anglesPacked.' char(cs.get(u).getName()) '= rad2deg(angles(:,u+1));']) 155 | end 156 | end 157 | 158 | anglesPacked.time = [validTime(1):dt:validTime(end)]'; 159 | 160 | 161 | end -------------------------------------------------------------------------------- /classManagers/virtualMarkerManager.m: -------------------------------------------------------------------------------- 1 | classdef virtualMarkerManager < matlab.mixin.SetGet 2 | %% virtualMarkerManager(model, trcManager) 3 | % Class that manages the computation and addition of virtual markers to a 4 | % trc data structure. This includes Hip joint, Helical Axis, and joint 5 | % mid-point calculations. 6 | properties (Access = private) 7 | 8 | 9 | 10 | end 11 | methods 12 | function self = virutalMarkerManager() 13 | 14 | end 15 | end 16 | methods (Static) 17 | function [Cr] = CoR_Estimation(TrP) 18 | %------------------------------------------------------------------------- 19 | %[CR] = COR_ESTIMATION(TrP) 20 | % COR_ESTIMATION: Calculation of the relative center of rotation (CoR) 21 | % between body A (proximal)and body B (distal) in the coordinate system 22 | % (CS) of the body A. 23 | % 24 | % INPUT: TrP - matrix containing the trajectories of the markers attached 25 | % to the body B and expressed in the CS of body A. dim(TrP)= N x 3p 26 | % where N is number of samples and p is the number of distal markers 27 | % 28 | % OUTPUT: Cr - rotation center coordinates in the CS of A (Cx,Cy,Cz) 29 | % 30 | % COMMENTS: COR_ESTIMATION provides the Centre of the bias-compensated quartic 31 | % best fitted sphere (S4). The CR is determined through a closed form 32 | % minimization of the quartic objective function (Gamage and Lasenby, 2002). 33 | % The bias is compensated for by solving it iteratively using, at each iteration, 34 | % the previous solution as initial estimate and introducing a correction term, 35 | % which incorporates the latter estimate and a model of the photogrammetric 36 | % error, detailed in Halvorsen (2003). The S4 algorithm has been proved to 37 | % the best among the best performing algorithms both in simulation 38 | % (Camomilla et al., 2006) and in in vitro 39 | % (Cereatti et al., 2009). For optimal results the number of samples should 40 | % higher than 500 (Camomilla et al., 2006). 41 | % 42 | % References: 43 | % 1) Gamage, S.S.H.U., Lasenby, J., 2002. New least squares solutions for 44 | % estimating the average centre of rotation and the axis of rotation. 45 | % Journal of Biomechanics 35, 87?93. 46 | % 2) Halvorsen, K., 2003. Bias compensated least square estimate of the 47 | % center of rotation. Journal of Biomechanics 36, 999?1008. 48 | % 3) Camomilla, V., Cereatti, A., Vannozzi, G., Cappozzo, A., 2006. An 49 | % optimized protocol for hip joint centre determination using the 50 | % functional method. Journal of Biomechanics 39, 1096?1106. 51 | % 4) Cereatti, A., Donati, M., Camomilla, V., Margheritini, F., Cappozzo, 52 | % A., 2009. Hip joint centre location: an ex vivo study. Journal of 53 | % Biomechanics 42, 818?823. 54 | % ------------------------------------------------------------------------- 55 | % $ Version: 1.0 $ 56 | % CODE by Andrea Cereatti, 2014. 57 | % ------------------------------------------------------------------------- 58 | [r c] = size(TrP); 59 | if r<500 60 | warning('The number of samples for the identification of the CoR could be too small, for a more accurate estimate please collect a larger number of samples'); 61 | end 62 | D = zeros(3); 63 | V1 = []; 64 | V2 = []; 65 | V3 = []; 66 | b1 = [0 0 0]; 67 | Cr = []; 68 | Cm_in = []; 69 | % Computation of the terms of eq.5 of Gamage and Lasenby (2002) 70 | for j = 1:3:c 71 | d1 = zeros(3); 72 | V2a = 0; 73 | V3a = [0 0 0]; 74 | for i = 1:r 75 | d1 = [d1+TrP(i,j:j+2)'*(TrP(i,j:j+2))]; %dim(3x3) 76 | a = (TrP(i,j).^2+TrP(i,j+1).^2+TrP(i,j+2).^2); %dim(1) 77 | V2a = V2a+a; % dim(1) 78 | V3a = V3a+a*TrP(i,j:j+2); %dim(1x3) 79 | end 80 | D = D+(d1/r); %dim(3x3) 81 | V2 = [V2,V2a/r]; %dim(1xp) 82 | b1 = [b1+V3a/r]; %dim(1x3) 83 | end 84 | 85 | V1 = mean(TrP); %dim(1x3p) 86 | p = size(V1,2); 87 | e1 = 0; 88 | E = zeros(3); 89 | f1 = [0 0 0]; 90 | F = [0 0 0]; 91 | for k = 1:3:p 92 | e1 = V1(k:k+2)'*V1(k:k+2); %dim(3x3) 93 | E = E+e1; %dim(3x3) 94 | f1 = V2((k-1)/3+1)*V1(k:k+2); %dim(1x3) 95 | F = F+f1; %dim(1x3) 96 | end 97 | % Coefficients of the linear system reported in eq.5 of Gamage and Lasenby (2002) 98 | A = 2*(D-E); %dim(3x3) 99 | B =(b1-F)'; %dim(3x1) 100 | [U,S,V] = svd(A); %the linear system is solved using the singular value decomposition 101 | Cr_in = V*inv(S)*U'*B; %dim(1x3)CoR estimate without Halvorsen's bias correction 102 | Cr_p = Cr_in+[1,1,1]'; %To enter in the while cycle 103 | kk = 0; 104 | % Bias compensated least square estimate proposed by Halvorsen (2003) 105 | while spatialMath.distanceBetweenPoints(Cr_p',Cr_in') > 0.0000001 106 | Cr_p = Cr_in; %initial estimate 107 | sigma2 = []; %noise variance 108 | 109 | %Computation of the noise variance sigma2 110 | for j=1:3:c 111 | marker = TrP(:,j:j+2); 112 | Ukp = marker-(Cr_in*ones(1,r))'; 113 | %Computation of u^2 114 | u2 = 0; 115 | app = []; 116 | for i = 1:r 117 | u2 = u2+Ukp(i,:)*Ukp(i,:)'; 118 | app = [app,Ukp(i,:)*Ukp(i,:)']; 119 | end 120 | u2 = u2/r; 121 | % computation of sigma 122 | sigmaP = 0; 123 | for i = 1:r 124 | sigmaP = sigmaP+(app(i)-u2)^2; 125 | end 126 | sigmaP = sigmaP/(4*u2*r); 127 | sigma2 =[sigma2;sigmaP]; 128 | end 129 | sigma2 = mean(sigma2); 130 | 131 | %Computation of the correction term Bcorr 132 | deltaB = 0; 133 | for j = 1:3:c 134 | deltaB = deltaB+V1(j:j+2)'-Cr_in; 135 | end 136 | deltaB = 2*sigma2*deltaB; 137 | Bcorr = B-deltaB; % corrected term B 138 | 139 | %Iterative estimation of the CoR according to Halvorsen(2003) 140 | [U,S,V] = svd(A); 141 | Cr_in = V*inv(S)*U'*Bcorr; 142 | end 143 | Cr = Cr_in; 144 | end 145 | end 146 | end 147 | 148 | 149 | -------------------------------------------------------------------------------- /examples/OpenSimCreateTugOfWarModel.m: -------------------------------------------------------------------------------- 1 | % ----------------------------------------------------------------------- % 2 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 3 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 4 | % for more information. OpenSim is developed at Stanford University % 5 | % and supported by the US National Institutes of Health (U54 GM072970, % 6 | % R24 HD065690) and by DARPA through the Warrior Web program. % 7 | % % 8 | % Copyright (c) 2005-2017 Stanford University and the Authors % 9 | % % 10 | % Licensed under the Apache License, Version 2.0 (the "License"); % 11 | % you may not use this file except in compliance with the License. % 12 | % You may obtain a copy of the License at % 13 | % http://www.apache.org/licenses/LICENSE-2.0. % 14 | % % 15 | % Unless required by applicable law or agreed to in writing, software % 16 | % distributed under the License is distributed on an "AS IS" BASIS, % 17 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 18 | % implied. See the License for the specific language governing % 19 | % permissions and limitations under the License. % 20 | % ----------------------------------------------------------------------- % 21 | 22 | % OpenSimCreateTugOfWarModel.m - script to perform the same model building and 23 | % simulation tasks as the MainExample from the SDK examples 24 | 25 | % This example script creates a model similar to the TugofWar API example. 26 | % Two muscles are created and attached to a block. Linear controllers are 27 | % defined for the muscles. 28 | 29 | % Pull in the modeling classes straight from the OpenSim distribution 30 | import org.opensim.modeling.* 31 | 32 | %/////////////////////////////////////////// 33 | %// DEFINE BODIES AND JOINTS OF THE MODEL // 34 | %/////////////////////////////////////////// 35 | 36 | % Create a blank model 37 | model = Model(); 38 | model.setName('TugOfWar') 39 | 40 | % Convenience - create a zero value Vec3 41 | zeroVec3 = ArrayDouble.createVec3(0); 42 | 43 | % Set gravity as 0 since there is no ground contact model in this version 44 | % of the example 45 | model.setGravity(zeroVec3); 46 | 47 | % GROUND BODY 48 | 49 | % Get a reference to the model's ground body 50 | ground = model.getGround(); 51 | 52 | % Add display geometry to the ground to visualize in the GUI 53 | ground.attachGeometry(Mesh('ground.vtp')); 54 | ground.attachGeometry(Mesh('anchor1.vtp')); 55 | ground.attachGeometry(Mesh('anchor2.vtp')); 56 | 57 | % "BLOCK" BODY 58 | 59 | % Create a block Body with associate dimensions, mass properties, and DisplayGeometry 60 | block = Body(); 61 | block.setName('Block'); 62 | block.setMass(20); 63 | block.setMassCenter(zeroVec3); 64 | % Need to set inertia 65 | block.attachGeometry(Mesh('block.vtp')); 66 | 67 | % FREE JOINT 68 | 69 | % Create a new free joint with 6 degrees-of-freedom (coordinates) between the block and ground bodies 70 | blockSideLength = 0.1; 71 | locationInParentVec3 = ArrayDouble.createVec3([0, blockSideLength/2, 0]); 72 | blockToGround = FreeJoint('blockToGround', ... 73 | ground, locationInParentVec3, zeroVec3, ... 74 | block, zeroVec3, zeroVec3); 75 | 76 | % Set bounds on coordinates 77 | angleRange = [-pi/2, pi/2]; 78 | positionRange = [-1, 1]; 79 | blockToGround.upd_coordinates(0).setRange(angleRange); 80 | blockToGround.upd_coordinates(1).setRange(angleRange); 81 | blockToGround.upd_coordinates(2).setRange(angleRange); 82 | blockToGround.upd_coordinates(3).setRange(positionRange); 83 | blockToGround.upd_coordinates(4).setRange(positionRange); 84 | blockToGround.upd_coordinates(5).setRange(positionRange); 85 | 86 | % Add the block body to the model 87 | model.addBody(block) 88 | 89 | %/////////////////////////////////////// 90 | %// DEFINE FORCES ACTING ON THE MODEL // 91 | %/////////////////////////////////////// 92 | 93 | % Set muscle parameters 94 | maxIsometricForce = 1000.0; 95 | optimalFiberLength = 0.25; 96 | tendonSlackLength = 0.1; 97 | pennationAngle = 0.0; 98 | 99 | % Create new muscles 100 | muscle1 = Thelen2003Muscle(); 101 | muscle1.setName('muscle1') 102 | muscle1.setMaxIsometricForce(maxIsometricForce) 103 | muscle1.setOptimalFiberLength(optimalFiberLength) 104 | muscle1.setTendonSlackLength(tendonSlackLength); 105 | muscle1.setPennationAngleAtOptimalFiberLength(pennationAngle) 106 | 107 | % Path for muscle 1 108 | muscle1.addNewPathPoint('muscle1-point1', ground, ArrayDouble.createVec3([0.0,0.05,-0.35])) 109 | muscle1.addNewPathPoint('muscle1-point2', block, ArrayDouble.createVec3([0.0,0.0,-0.05])) 110 | 111 | % Repeat for Muscle 2 112 | muscle2 = Thelen2003Muscle(); 113 | muscle2.setName('muscle2'); 114 | muscle2.setMaxIsometricForce(maxIsometricForce) 115 | muscle2.setOptimalFiberLength(optimalFiberLength) 116 | muscle2.setTendonSlackLength(tendonSlackLength) 117 | muscle2.setPennationAngleAtOptimalFiberLength(pennationAngle) 118 | 119 | % Path for muscle 2 120 | muscle2.addNewPathPoint('muscle2-point1', ground, ArrayDouble.createVec3([0.0,0.05,0.35])) 121 | muscle2.addNewPathPoint('muscle2-point2', block, ArrayDouble.createVec3([0.0,0.0,0.05])) 122 | 123 | % Add the two muscles (as forces) to the model 124 | model.addForce(muscle1) 125 | model.addForce(muscle2); 126 | 127 | %Set up Controller 128 | initialTime = 0.0; 129 | finalTime = 3.0; 130 | 131 | muscleController = PrescribedController(); 132 | muscleController.setName('LinearRamp Controller') 133 | muscleController.setActuators(model.updActuators()) 134 | 135 | % Define linear functions for the control values for the two muscles 136 | slopeAndIntercept1=ArrayDouble(0.0, 2); 137 | slopeAndIntercept2=ArrayDouble(0.0, 2); 138 | 139 | % Muscle1 control has slope of -1 starting 1 at t = 0 140 | slopeAndIntercept1.setitem(0, -1.0/(finalTime-initialTime)); 141 | slopeAndIntercept1.setitem(1, 1.0); 142 | 143 | % Muscle2 control has slope of 0.95 starting 0.05 at t = 0 144 | slopeAndIntercept2.setitem(0, 0.95/(finalTime-initialTime)); 145 | slopeAndIntercept2.setitem(1, 0.05); 146 | 147 | % Set the indiviudal muscle control functions for the prescribed muscle controller 148 | muscleController.prescribeControlForActuator('muscle1', LinearFunction(slopeAndIntercept1)); 149 | muscleController.prescribeControlForActuator('muscle2', LinearFunction(slopeAndIntercept2)); 150 | 151 | % Add the control set controller to the model 152 | model.addController(muscleController); 153 | 154 | model.print('tug_of_war_muscles_controller.osim'); 155 | -------------------------------------------------------------------------------- /examples/TugOfWar_CompleteRunVisualize.m: -------------------------------------------------------------------------------- 1 | % ----------------------------------------------------------------------- % 2 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 3 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 4 | % for more information. OpenSim is developed at Stanford University % 5 | % and supported by the US National Institutes of Health (U54 GM072970, % 6 | % R24 HD065690) and by DARPA through the Warrior Web program. % 7 | % % 8 | % Copyright (c) 2005-2017 Stanford University and the Authors % 9 | % % 10 | % Licensed under the Apache License, Version 2.0 (the "License"); % 11 | % you may not use this file except in compliance with the License. % 12 | % You may obtain a copy of the License at % 13 | % http://www.apache.org/licenses/LICENSE-2.0. % 14 | % % 15 | % Unless required by applicable law or agreed to in writing, software % 16 | % distributed under the License is distributed on an "AS IS" BASIS, % 17 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 18 | % implied. See the License for the specific language governing % 19 | % permissions and limitations under the License. % 20 | % ----------------------------------------------------------------------- % 21 | 22 | % This script runs a forward simulation with the tug of war model created 23 | % in the script OpenSimCreateTugOfWarModel. 24 | 25 | % Rotate the view window to see the simulation run. 26 | 27 | % First, import the classes from the jar file so that these can be called 28 | % directly 29 | import org.opensim.modeling.* 30 | 31 | % Generate a new model object by loading the tug of war model from file 32 | osimModel = Model('tug_of_war_muscles_controller.osim'); 33 | 34 | % Set up the visualizer to show the model and simulation 35 | osimModel.setUseVisualizer(true); 36 | 37 | % Initializing the model 38 | osimModel.initSystem(); 39 | 40 | %% DEFINE SOME PARAMETERS FOR THE SIMULATION 41 | 42 | % Define the new tool object which will be run 43 | tool = ForwardTool(); %--> to see all properties which can be set type 'methodsview(tool)' 44 | 45 | % Define the model which the forward tool will operate on 46 | tool.setModel(osimModel); 47 | 48 | % Define the start and finish times for simulation 49 | tool.setStartTime(0); 50 | tool.setFinalTime(3); 51 | tool.setSolveForEquilibrium(true); 52 | 53 | % Define the name of the forward analysis 54 | tool.setName('tugOfWar'); 55 | 56 | % Run the simulation 57 | tool.run(); %--> rotate the view to see the tug of war simulation 58 | 59 | -------------------------------------------------------------------------------- /examples/build_and_simulate_simple_arm.m: -------------------------------------------------------------------------------- 1 | %% build_and_simulate_simple_arm.m 2 | % This API example demonstrates building and simulating a simple arm model 3 | % consisting of two bodies, two joints, a muscle, and a controller. The API 4 | % visualizer and a reporter are used to display the simulation results. 5 | 6 | % Author(s): James Dunne, Chris Dembia, Tom Uchida % 7 | % -------------------------------------------------------------------------- % 8 | % build_and_simulate_simple_arm.m % 9 | % -------------------------------------------------------------------------- % 10 | % The OpenSim API is a toolkit for musculoskeletal modeling and simulation. % 11 | % See http://opensim.stanford.edu and the NOTICE file for more information. % 12 | % OpenSim is developed at Stanford University and supported by the US % 13 | % National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA % 14 | % through the Warrior Web program. % 15 | % % 16 | % Copyright (c) 2005-2017 Stanford University and the Authors % 17 | % Author(s): James Dunne, Chris Dembia, Tom Uchida % 18 | % % 19 | % Licensed under the Apache License, Version 2.0 (the "License"); you may % 20 | % not use this file except in compliance with the License. You may obtain a % 21 | % copy of the License at http://www.apache.org/licenses/LICENSE-2.0. % 22 | % % 23 | % Unless required by applicable law or agreed to in writing, software % 24 | % distributed under the License is distributed on an "AS IS" BASIS, % 25 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 26 | % See the License for the specific language governing permissions and % 27 | % limitations under the License. % 28 | % -------------------------------------------------------------------------- % 29 | 30 | 31 | 32 | import org.opensim.modeling.* 33 | 34 | model = Model(); 35 | model.setUseVisualizer(true); 36 | 37 | % Create two links, each with a mass of 1 kg, center of mass at the body's 38 | % origin, and moments and products of inertia of zero. 39 | humerus = Body('humerus', 1, Vec3(0), Inertia(0)); 40 | radius = Body('radius', 1, Vec3(0), Inertia(0)); 41 | 42 | % Connect the bodies with pin joints. Assume each body is 1 m long. 43 | shoulder = PinJoint('shoulder', ... 44 | model.getGround(), ... % Parent body 45 | Vec3(0), ... % Location in parent 46 | Vec3(0), ... % Orientation in parent 47 | humerus, ... % Child body 48 | Vec3(0, 1, 0), ... % Location in child 49 | Vec3(0)); % Orientation in child 50 | elbow = PinJoint('elbow', ... 51 | humerus, Vec3(0), Vec3(0), radius, Vec3(0, 1, 0), Vec3(0)); 52 | 53 | % Add a muscle that flexes the elbow. 54 | biceps = Millard2012EquilibriumMuscle('biceps', 200, 0.6, 0.55, 0); 55 | biceps.addNewPathPoint('origin', humerus, Vec3(0, 0.8, 0)); 56 | biceps.addNewPathPoint('insertion', radius, Vec3(0, 0.7, 0)); 57 | 58 | % Add a controller that specifies the excitation of the muscle. 59 | brain = PrescribedController(); 60 | brain.addActuator(biceps); 61 | % Muscle excitation is 0.3 for the first 0.5 seconds, then increases to 1. 62 | brain.prescribeControlForActuator('biceps', StepFunction(0.5, 3, 0.3, 1)); 63 | 64 | % Add components to the model. 65 | model.addBody(humerus); model.addBody(radius); 66 | model.addJoint(shoulder); model.addJoint(elbow); 67 | model.addForce(biceps); 68 | model.addController(brain); 69 | 70 | % Add a console reporter to print the muscle fiber force and elbow angle. The 71 | % output will be written to the log file (out.log) in the current directory. 72 | reporter = ConsoleReporter(); 73 | reporter.set_report_time_interval(1.0); 74 | reporter.addToReport(biceps.getOutput('fiber_force')); 75 | reporter.addToReport(elbow.getCoordinate().getOutput('value'), 'elbow_angle'); 76 | model.addComponent(reporter); 77 | 78 | % Add display geometry. 79 | bodyGeometry = Ellipsoid(0.1, 0.5, 0.1); 80 | bodyGeometry.setColor(Vec3(0.5)); % Gray 81 | 82 | % Attach an ellipsoid to a frame located at the center of each body. 83 | humerusCenter = PhysicalOffsetFrame(); 84 | humerusCenter.setName('humerusCenter'); 85 | humerusCenter.setParentFrame(humerus); 86 | humerusCenter.setOffsetTransform(Transform(Vec3(0, 0.5, 0))); 87 | humerus.addComponent(humerusCenter); 88 | humerusCenter.attachGeometry(bodyGeometry.clone()); 89 | 90 | radiusCenter = PhysicalOffsetFrame(); 91 | radiusCenter.setName('radiusCenter'); 92 | radiusCenter.setParentFrame(radius); 93 | radiusCenter.setOffsetTransform(Transform(Vec3(0, 0.5, 0))); 94 | radius.addComponent(radiusCenter); 95 | radiusCenter.attachGeometry(bodyGeometry.clone()); 96 | 97 | % Configure the model. 98 | state = model.initSystem(); 99 | % Fix the shoulder at its default angle and begin with the elbow flexed. 100 | shoulder.getCoordinate().setLocked(state, true); 101 | elbow.getCoordinate().setValue(state, 0.5 * pi); 102 | model.equilibrateMuscles(state); 103 | 104 | % Simulate. 105 | manager = Manager(model); 106 | manager.setInitialTime(0); 107 | manager.setFinalTime(10.0); 108 | manager.integrate(state); 109 | 110 | % Display results recorded by ConsoleReporter. 111 | if (exist('out.log', 'file') ~= 2), error('log file (out.log) not found'); end 112 | type('out.log'); 113 | fprintf('Success!\n'); 114 | -------------------------------------------------------------------------------- /examples/c3dExport.m: -------------------------------------------------------------------------------- 1 | c3dfile = '/Users/jimmy/repository/opensim-matlab/tests/shared/walking2.c3d'; 2 | %% 3 | import org.opensim.modeling.* 4 | %% Construct an opensimC3D object with input c3d path 5 | c3d = opensimC3D(c3dfile); 6 | %% Rotate the data 7 | c3d.rotateData('x',-90) 8 | %% Write the tables to file 9 | c3d.write2file() 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/pendulum_marker_positions.m: -------------------------------------------------------------------------------- 1 | %% pendulum_marker_positions.m 2 | % OpenSim API example to build, simulate, and generate outputs for a 3 | % double-pendulum model. Writes the results to .sto and .trc files. 4 | 5 | % Author(s): James Dunne, Tom Uchida, Chris Dembia % 6 | % -------------------------------------------------------------------------- % 7 | % The OpenSim API is a toolkit for musculoskeletal modeling and simulation. % 8 | % See http://opensim.stanford.edu and the NOTICE file for more information. % 9 | % OpenSim is developed at Stanford University and supported by the US % 10 | % National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA % 11 | % through the Warrior Web program. % 12 | % % 13 | % Copyright (c) 2005-2017 Stanford University and the Authors % 14 | % Author(s): James Dunne, Tom Uchida, Chris Dembia % 15 | % % 16 | % Licensed under the Apache License, Version 2.0 (the "License"); you may % 17 | % not use this file except in compliance with the License. You may obtain a % 18 | % copy of the License at http://www.apache.org/licenses/LICENSE-2.0. % 19 | % % 20 | % Unless required by applicable law or agreed to in writing, software % 21 | % distributed under the License is distributed on an "AS IS" BASIS, % 22 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 23 | % See the License for the specific language governing permissions and % 24 | % limitations under the License. % 25 | % -------------------------------------------------------------------------- % 26 | 27 | %% import java libraries 28 | import org.opensim.modeling.* 29 | 30 | %% Instantiate a (empty) model 31 | model = Model(); 32 | model.setUseVisualizer(true); 33 | 34 | %% Build model 35 | % bodies 36 | r1 = Body('rod1', 1, Vec3(0), Inertia(0)); 37 | r2 = Body('rod2', 1, Vec3(0), Inertia(0)); 38 | model.addBody(r1); model.addBody(r2); 39 | 40 | % joints 41 | p1 = PinJoint('pin1', model.getGround(), Vec3(0), Vec3(0), r1, Vec3(0, 1, 0), Vec3(0)); 42 | p2 = PinJoint('pin2', r1, Vec3(0), Vec3(0), r2, Vec3(0, 1, 0), Vec3(0)); 43 | model.addJoint(p1);model.addJoint(p2); 44 | 45 | % attach geometry to the bodies 46 | g = Cylinder(0.05,0.5); g.setColor(Vec3(1)); 47 | r1b = PhysicalOffsetFrame(); r1b.setName('r1b'); 48 | r1b.setParentFrame(r1); r1b.setOffsetTransform(Transform(Vec3(0, 0.5, 0))); 49 | r1.addComponent(r1b); r1b.attachGeometry(g.clone()); 50 | r2b = PhysicalOffsetFrame(); r2b.setName('r2b'); 51 | r2b.setParentFrame(r2); r2b.setOffsetTransform(Transform(Vec3(0, 0.5, 0))); 52 | r2.addComponent(r2b); r2b.attachGeometry(g.clone()); 53 | 54 | % markers 55 | m = Marker(); m.setParentFrame(r1);m.set_location(Vec3(0.1,0.5,0));m.setName('marker_1'); 56 | m2 = Marker(); m2.setParentFrame(r1); m2.set_location(Vec3(0.25,0.2,0.2)); m2.setName('marker_2'); 57 | m3 = Marker(); m3.set_location(Vec3(-0.25,0.2,-0.2)); m3.setParentFrame(r1); m3.setName('marker_3'); 58 | m4 = Marker(); m4.set_location(Vec3(0.1,0.5,0)); m4.setParentFrame(r2); m4.setName('marker_4') 59 | m5 = Marker(); m5.set_location(Vec3(0.25,0.2,0.2)); m5.setParentFrame(r2); m5.setName('marker_5') 60 | m6 = Marker(); m6.set_location(Vec3(-0.25,0.2,-0.2)); m6.setParentFrame(r2); m6.setName('marker_6') 61 | 62 | model.addMarker(m); model.addMarker(m2); model.addMarker(m3); 63 | model.addMarker(m4); model.addMarker(m5); model.addMarker(m6); 64 | 65 | %% Set the default values of the coordinates 66 | model.getCoordinateSet().get(0).setDefaultValue(-1.04719755) 67 | model.getCoordinateSet().get(1).setDefaultValue(-0.78539816) 68 | 69 | % set time interval for the reporter 70 | reportTimeInterval = 0.1; 71 | 72 | % add console reporter 73 | reporter = ConsoleReporter(); 74 | reporter.set_report_time_interval(reportTimeInterval); 75 | reporter.addToReport(model.getCoordinateSet().get(0).getOutput('value'), 'pin1_coord_0'); 76 | reporter.addToReport(model.getCoordinateSet().get(1).getOutput('value'), 'pin2_coord_0'); 77 | model.addComponent(reporter); 78 | 79 | % add reporter for coordinates 80 | cReporter = TableReporter(); 81 | cReporter.set_report_time_interval(reportTimeInterval); 82 | cReporter.addToReport(model.getCoordinateSet().get(0).getOutput('value'), 'pin1_coord_0'); 83 | cReporter.addToReport(model.getCoordinateSet().get(1).getOutput('value'), 'pin2_coord_0'); 84 | model.addComponent(cReporter); 85 | 86 | % add reporter for markers 87 | mReporter = TableReporterVec3(); 88 | mReporter.set_report_time_interval(reportTimeInterval); 89 | mReporter.addToReport(model.getMarkerSet().get(0).getOutput('location'), 'marker_1'); 90 | mReporter.addToReport(model.getMarkerSet().get(1).getOutput('location'), 'marker_2'); 91 | mReporter.addToReport(model.getMarkerSet().get(2).getOutput('location'), 'marker_3'); 92 | mReporter.addToReport(model.getMarkerSet().get(3).getOutput('location'), 'marker_4'); 93 | mReporter.addToReport(model.getMarkerSet().get(4).getOutput('location'), 'marker_5'); 94 | mReporter.addToReport(model.getMarkerSet().get(5).getOutput('location'), 'marker_6'); 95 | model.addComponent(mReporter); 96 | 97 | %% Run a forward simulation using the Manager. 98 | % cReporter.clearTable(); mReporter.clearTable(); 99 | state = model.initSystem(); 100 | manager = Manager(model); 101 | manager.setInitialTime(0); 102 | manager.setFinalTime(4); 103 | manager.integrate(state); 104 | 105 | %% Write joint angles to .sto file. 106 | filename = 'pendulum_coordinates.sto'; 107 | STOFileAdapter.write(cReporter.getTable(), filename); 108 | fprintf('Joint angles written to %s\n', filename); 109 | 110 | %% Write marker locations to .sto file. 111 | filename = 'marker_locations.sto'; 112 | markerTable = mReporter.getTable(); 113 | STOFileAdapterVec3.write(markerTable, filename); 114 | fprintf('Marker locations written to %s\n', filename); 115 | 116 | %% Write marker locations to .trc file. 117 | filename = 'marker_locations.trc'; 118 | markerTable.addTableMetaDataString('DataRate', num2str(reportTimeInterval)); 119 | markerTable.addTableMetaDataString('Units', 'm'); 120 | TRCFileAdapter.write(markerTable, filename); 121 | 122 | fprintf('Marker locations written to %s\n', filename); 123 | fprintf('Success!\n'); 124 | -------------------------------------------------------------------------------- /examples/setupAndRunAnalyzeBatchExample.m: -------------------------------------------------------------------------------- 1 | % ----------------------------------------------------------------------- % 2 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 3 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 4 | % for more information. OpenSim is developed at Stanford University % 5 | % and supported by the US National Institutes of Health (U54 GM072970, % 6 | % R24 HD065690) and by DARPA through the Warrior Web program. % 7 | % % 8 | % Copyright (c) 2005-2017 Stanford University and the Authors % 9 | % % 10 | % Licensed under the Apache License, Version 2.0 (the "License"); % 11 | % you may not use this file except in compliance with the License. % 12 | % You may obtain a copy of the License at % 13 | % http://www.apache.org/licenses/LICENSE-2.0. % 14 | % % 15 | % Unless required by applicable law or agreed to in writing, software % 16 | % distributed under the License is distributed on an "AS IS" BASIS, % 17 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 18 | % implied. See the License for the specific language governing % 19 | % permissions and limitations under the License. % 20 | % ----------------------------------------------------------------------- % 21 | 22 | % Pull in the modeling classes straight from the OpenSim distribution 23 | import org.opensim.modeling.* 24 | 25 | % move to directory where this subject's files are kept 26 | subjectDir = uigetdir('testData', 'Select the folder that contains the current subject data'); 27 | 28 | % Go to the folder in the subject's folder where IK Results are 29 | ik_results_folder = [subjectDir '\IKResults\']; 30 | 31 | % specify where setup files will be printed. 32 | setupfiles_folder = [subjectDir '\AnalyzeSetup\']; 33 | 34 | % specify where results will be printed. 35 | results_folder = [subjectDir '\AnalyzeResults\']; 36 | 37 | % %% To send an email at the end of this function define these variables appropriately: 38 | % % more details available here: 39 | % % http://www.mathworks.com/support/solutions/en/data/1-3PRRDV/ 40 | % % 41 | % mail = 'youremailaddress@gmail.com'; %Your GMail email address 42 | % password = 'yourPassword'; %Your GMail password 43 | % 44 | % % Then this code will set up the preferences properly: 45 | % setpref('Internet','E_mail',mail); 46 | % setpref('Internet','SMTP_Server','smtp.gmail.com'); 47 | % setpref('Internet','SMTP_Username',mail); 48 | % setpref('Internet','SMTP_Password',password); 49 | % props = java.lang.System.getProperties; 50 | % props.setProperty('mail.smtp.auth','true'); 51 | % props.setProperty('mail.smtp.socketFactory.class', 'javax.net.ssl.SSLSocketFactory'); 52 | % props.setProperty('mail.smtp.socketFactory.port','465'); 53 | 54 | %% Get and operate on the files 55 | 56 | subjectNumber = 'subject01'; 57 | genericSetupForAn = [setupfiles_folder subjectNumber '_Setup_Analyze_generic.xml']; 58 | analyzeTool = AnalyzeTool(genericSetupForAn); 59 | 60 | % get the file names that match the ik_reults convention 61 | % this is where consistent naming conventions pay off 62 | trialsForAn = dir([ik_results_folder '*_ik.mot']); 63 | nTrials =length(trialsForAn); 64 | 65 | for trial= 1:nTrials; 66 | % get the name of the file for this trial 67 | motIKCoordsFile = trialsForAn(trial).name; 68 | 69 | % create name of trial from .trc file name 70 | name = regexprep(motIKCoordsFile,'_ik.mot',''); 71 | 72 | % get .mot data to determine time range 73 | motCoordsData = Storage([ik_results_folder motIKCoordsFile]); 74 | 75 | % for this example, column is time 76 | initial_time = motCoordsData.getFirstTime(); 77 | final_time = motCoordsData.getLastTime(); 78 | 79 | analyzeTool.setName(name); 80 | analyzeTool.setResultsDir(results_folder); 81 | analyzeTool.setCoordinatesFileName([ik_results_folder motIKCoordsFile]); 82 | analyzeTool.setInitialTime(initial_time); 83 | analyzeTool.setFinalTime(final_time); 84 | 85 | outfile = ['Setup_Analyze_' name '.xml']; 86 | analyzeTool.print([setupfiles_folder outfile]); 87 | 88 | analyzeTool.run(); 89 | fprintf(['Performing IK on cycle # ' num2str(trial) '\n']); 90 | 91 | % rename the out.log so that it doesn't get overwritten 92 | copyfile('out.log',[results_folder name '_out.log']) 93 | 94 | end 95 | %sendmail(mail,subjectNumber, ['Hello! Analysis for ' subjectNumber ' is complete']); 96 | 97 | -------------------------------------------------------------------------------- /examples/setupAndRunIKBatchExample.m: -------------------------------------------------------------------------------- 1 | % ----------------------------------------------------------------------- % 2 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 3 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 4 | % for more information. OpenSim is developed at Stanford University % 5 | % and supported by the US National Institutes of Health (U54 GM072970, % 6 | % R24 HD065690) and by DARPA through the Warrior Web program. % 7 | % % 8 | % Copyright (c) 2005-2017 Stanford University and the Authors % 9 | % Author(s): Edith Arnold % 10 | % % 11 | % Licensed under the Apache License, Version 2.0 (the "License"); % 12 | % you may not use this file except in compliance with the License. % 13 | % You may obtain a copy of the License at % 14 | % http://www.apache.org/licenses/LICENSE-2.0. % 15 | % % 16 | % Unless required by applicable law or agreed to in writing, software % 17 | % distributed under the License is distributed on an "AS IS" BASIS, % 18 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 19 | % implied. See the License for the specific language governing % 20 | % permissions and limitations under the License. % 21 | % ----------------------------------------------------------------------- % 22 | 23 | % setupAndRunIKBatchExample.m 24 | % Author: Edith Arnold 25 | 26 | % This example script runs multiple inverse kinematics trials for the model Subject01. 27 | % All input files are in the folder ../Matlab/testData/Subject01 28 | % To see the results load the model and ik output in the GUI. 29 | 30 | % Pull in the modeling classes straight from the OpenSim distribution 31 | import org.opensim.modeling.* 32 | 33 | % move to directory where this subject's files are kept 34 | subjectDir = uigetdir('testData', 'Select the folder that contains the current subject data'); 35 | 36 | % Go to the folder in the subject's folder where .trc files are 37 | trc_data_folder = uigetdir(subjectDir, 'Select the folder that contains the marker data files in .trc format.'); 38 | 39 | % specify where results will be printed. 40 | results_folder = uigetdir(subjectDir, 'Select the folder where the IK Results will be printed.'); 41 | 42 | % Get and operate on the files 43 | % Choose a generic setup file to work from 44 | [genericSetupForIK,genericSetupPath,FilterIndex] = ... 45 | uigetfile('*.xml','Pick the a generic setup file to for this subject/model as a basis for changes.'); 46 | ikTool = InverseKinematicsTool([genericSetupPath genericSetupForIK]); 47 | 48 | % Get the model 49 | [modelFile,modelFilePath,FilterIndex] = ... 50 | uigetfile('*.osim','Pick the the model file to be used.'); 51 | 52 | % Load the model and initialize 53 | model = Model([modelFilePath modelFile]); 54 | model.initSystem(); 55 | 56 | % Tell Tool to use the loaded model 57 | ikTool.setModel(model); 58 | 59 | trialsForIK = dir(fullfile(trc_data_folder, '*.trc')); 60 | 61 | nTrials = size(trialsForIK); 62 | 63 | % Loop through the trials 64 | for trial= 1:nTrials; 65 | 66 | % Get the name of the file for this trial 67 | markerFile = trialsForIK(trial).name; 68 | 69 | % Create name of trial from .trc file name 70 | name = regexprep(markerFile,'.trc',''); 71 | fullpath = ([trc_data_folder '\' markerFile]) 72 | 73 | % Get trc data to determine time range 74 | markerData = MarkerData(fullpath); 75 | 76 | % Get initial and intial time 77 | initial_time = markerData.getStartFrameTime(); 78 | final_time = markerData.getLastFrameTime(); 79 | 80 | % Setup the ikTool for this trial 81 | ikTool.setName(name); 82 | ikTool.setMarkerDataFileName(fullpath); 83 | ikTool.setStartTime(initial_time); 84 | ikTool.setEndTime(final_time); 85 | ikTool.setOutputMotionFileName([results_folder '\' name '_ik.mot']); 86 | 87 | % Save the settings in a setup file 88 | outfile = ['Setup_IK_' name '.xml']; 89 | ikTool.print([genericSetupPath '\' outfile]); 90 | 91 | fprintf(['Performing IK on cycle # ' num2str(trial) '\n']); 92 | % Run IK 93 | ikTool.run(); 94 | 95 | end 96 | -------------------------------------------------------------------------------- /examples/simpleOptimizerExample.m: -------------------------------------------------------------------------------- 1 | % ----------------------------------------------------------------------- % 2 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 3 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 4 | % for more information. OpenSim is developed at Stanford University % 5 | % and supported by the US National Institutes of Health (U54 GM072970, % 6 | % R24 HD065690) and by DARPA through the Warrior Web program. % 7 | % % 8 | % Copyright (c) 2005-2017 Stanford University and the Authors % 9 | % Author(s): Ayman Habib, Lorenzo Flores % 10 | % % 11 | % Licensed under the Apache License, Version 2.0 (the "License"); % 12 | % you may not use this file except in compliance with the License. % 13 | % You may obtain a copy of the License at % 14 | % http://www.apache.org/licenses/LICENSE-2.0. % 15 | % % 16 | % Unless required by applicable law or agreed to in writing, software % 17 | % distributed under the License is distributed on an "AS IS" BASIS, % 18 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 19 | % implied. See the License for the specific language governing % 20 | % permissions and limitations under the License. % 21 | % ----------------------------------------------------------------------- % 22 | 23 | % simpleOptimizationExample.m 24 | % Author: Ayman Habib, Lorenzo Flores 25 | 26 | %% Load Java libraris 27 | import org.opensim.modeling.* 28 | 29 | % Read in osim model 30 | modelPath = strcat('testData',filesep,'Arm26_Optimize.osim'); 31 | %Create the Original OpenSim model from a .osim file 32 | model = Model(modelPath); 33 | state = model.initSystem; 34 | 35 | coords = model.getCoordinateSet(); 36 | coords.get('r_shoulder_elev').setValue(state, 0.0); 37 | 38 | % Get the set of muscles 39 | muscles = model.getMuscles(); 40 | nMuscles = muscles.getSize(); 41 | 42 | for i = 0:nMuscles-1 43 | % for each muscle, set the fiber length 44 | muscles.get(i).setActivation(state, 1.0); 45 | afl = ActivationFiberLengthMuscle.safeDownCast(muscles.get(i)); 46 | afl.setFiberLength(state, .1); 47 | end 48 | 49 | %% Set the value of the elbow coordinate 50 | elbowFlexCoord = model.updCoordinateSet().get('r_elbow_flex'); 51 | elbowFlexCoord.setValue(state, 1.0); 52 | 53 | %% Equilibrate the muslces 54 | model.equilibrateMuscles(state); 55 | 56 | %% Set up optimization 57 | coordMin = elbowFlexCoord.getRangeMin(); 58 | coordMax = elbowFlexCoord.getRangeMax(); 59 | 60 | %% Control bounds must be specified as a column vector, every row 61 | %% corresponds to a control 62 | lowerBound = coordMin * ones(1,1); 63 | upperBound = coordMax * ones(1,1); 64 | 65 | %% Parameters to be passed in to the optimizer 66 | params.model = model; 67 | params.state = state; 68 | 69 | % knobs or coefficients that need to be computed by the optimizer 70 | initialCoefficients = 1.0*ones(1,1); 71 | 72 | %options = optimset('MaxIter',5000,'TolFun',0.00001); 73 | 74 | % Call the native optimizer fminsearch 75 | [f,fval,exitflag,output] = fminsearch(@(coeffs0) simpleOptimizerObjectiveFunction(coeffs0,params),... 76 | initialCoefficients); 77 | 78 | disp(strcat('Optimization #iterations=',num2str(output.iterations),' joint angle = ',num2str(f*180/pi),', moment arm = ',num2str(-fval))); 79 | 80 | -------------------------------------------------------------------------------- /examples/simpleOptimizerObjectiveFunction.m: -------------------------------------------------------------------------------- 1 | function f = simpleOptimizerObjectiveFunction(coeffs,params) 2 | % Runs model simulation for gvien coefficients, returns integration 3 | % coeffs = initial set of control values 4 | % params = optimization parameters; simulation parameters and 5 | % pointers to instantiated OpenSim objects. 6 | 7 | % Import OpenSim modeling classes 8 | import org.opensim.modeling.* 9 | 10 | % Get access to step counter and current best velocity value. 11 | %global stepCount bestSoFar; 12 | 13 | %% Get a reference to the model, as the model doesn't change in this example. 14 | osimModel = params.model; 15 | s = params.state; 16 | 17 | elbowFlexCoord = osimModel.updCoordinateSet().get('r_elbow_flex'); 18 | elbowFlexCoord.setValue(s, coeffs); 19 | % Now equilibriate muscles at this configuration 20 | muscles = osimModel.getMuscles(); 21 | nMuscles = muscles.getSize(); 22 | 23 | for i = 0:nMuscles-1 24 | muscles.get(i).setActivation(s, 1.0); 25 | afl = ActivationFiberLengthMuscle.safeDownCast(muscles.get(i)); 26 | afl.setFiberLength(s, .1); 27 | end 28 | 29 | %% Make sure the muscles states are in equilibrium 30 | osimModel.equilibrateMuscles(s); 31 | 32 | bicShort = osimModel.getMuscles().get('BICshort'); 33 | 34 | %% Compute moment arm of BICshort, flip sign since the optimizer tries to minimize rather than maximize 35 | f = bicShort.computeMomentArm(s, elbowFlexCoord); 36 | 37 | % Update stepCount 38 | % stepCount = stepCount + 1; 39 | 40 | % Check step counter, save results when appropriate 41 | % if f < bestSoFar 42 | % 43 | % bestSoFar = f; 44 | % disp(strcat('Optimization (',num2str(stepCount),') f = ',num2str(f),', bestSoFar = ',num2str(bestSoFar))); 45 | % disp(coeffs); 46 | % end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /examples/simulate_double_pendulum_and_write_tables.m: -------------------------------------------------------------------------------- 1 | %% simulate_double_pendulum_and_write_tables.m 2 | % OpenSim API example that builds, simulates, and reports the motion of a 3 | % double-pendulum model (with markers). Writes the results to .sto and .trc 4 | % 5 | % Author(s): James Dunne, Tom Uchida, Chris Dembia % 6 | % -------------------------------------------------------------------------- % 7 | % simulate_double_pendulum_and_write_tables.m % 8 | % -------------------------------------------------------------------------- % 9 | % The OpenSim API is a toolkit for musculoskeletal modeling and simulation. % 10 | % See http://opensim.stanford.edu and the NOTICE file for more information. % 11 | % OpenSim is developed at Stanford University and supported by the US % 12 | % National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA % 13 | % through the Warrior Web program. % 14 | % % 15 | % Copyright (c) 2005-2017 Stanford University and the Authors % 16 | % Author(s): James Dunne, Tom Uchida, Chris Dembia % 17 | % % 18 | % Licensed under the Apache License, Version 2.0 (the "License"); you may % 19 | % not use this file except in compliance with the License. You may obtain a % 20 | % copy of the License at http://www.apache.org/licenses/LICENSE-2.0. % 21 | % % 22 | % Unless required by applicable law or agreed to in writing, software % 23 | % distributed under the License is distributed on an "AS IS" BASIS, % 24 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 25 | % See the License for the specific language governing permissions and % 26 | % limitations under the License. % 27 | % -------------------------------------------------------------------------- % 28 | 29 | %% import java libraries 30 | import org.opensim.modeling.* 31 | 32 | % Read double-pendulum model. 33 | model = Model('double_pendulum_markers.osim'); 34 | model.setUseVisualizer(false); 35 | 36 | % Set the time interval (in seconds) between consecutive data points stored by 37 | % the reporters. 38 | reportTimeInterval = 0.1; 39 | 40 | % Add a console reporter to print the joint angles. The output will be written 41 | % to the log file (out.log) in the current directory. 42 | consoleReporter = ConsoleReporter(); 43 | consoleReporter.set_report_time_interval(reportTimeInterval); 44 | % When connecting the outputs, set the alias names to 'pin1_angle' and 45 | % 'pin2_angle'. The aliases will appear as the column labels. 46 | consoleReporter.addToReport( ... 47 | model.getCoordinateSet().get(0).getOutput('value'), 'pin1_angle'); 48 | consoleReporter.addToReport( ... 49 | model.getCoordinateSet().get(1).getOutput('value'), 'pin2_angle'); 50 | model.addComponent(consoleReporter); 51 | 52 | % Add a table reporter to record the joint angles. 53 | tableReporterForAngles = TableReporter(); 54 | tableReporterForAngles.set_report_time_interval(reportTimeInterval); 55 | tableReporterForAngles.addToReport( ... 56 | model.getCoordinateSet().get(0).getOutput('value'), 'pin1_angle'); 57 | tableReporterForAngles.addToReport( ... 58 | model.getCoordinateSet().get(1).getOutput('value'), 'pin2_angle'); 59 | model.addComponent(tableReporterForAngles); 60 | 61 | % Add a table reporter to record the marker locations, which are of type Vec3. 62 | tableReporterForMarkers = TableReporterVec3(); 63 | tableReporterForMarkers.set_report_time_interval(reportTimeInterval); 64 | tableReporterForMarkers.addToReport( ... 65 | model.getMarkerSet().get(0).getOutput('location'), 'marker_1'); 66 | tableReporterForMarkers.addToReport( ... 67 | model.getMarkerSet().get(1).getOutput('location'), 'marker_2'); 68 | model.addComponent(tableReporterForMarkers); 69 | 70 | % Run a forward simulation using the Manager. 71 | state = model.initSystem(); 72 | manager = Manager(model); 73 | manager.setInitialTime(0); 74 | manager.setFinalTime(2); 75 | manager.integrate(state); 76 | 77 | % Display results recorded by the console reporter. 78 | if (exist('out.log', 'file') ~= 2), error('log file (out.log) not found'); end 79 | type('out.log'); 80 | 81 | % Write joint angles to .sto file. 82 | filename = 'pendulum_coordinates.sto'; 83 | STOFileAdapter.write(tableReporterForAngles.getTable(), filename); 84 | fprintf('Joint angles written to %s\n', filename); 85 | 86 | % Write marker locations to .sto file. 87 | filename = 'marker_locations.sto'; 88 | markerTable = tableReporterForMarkers.getTable(); 89 | STOFileAdapterVec3.write(markerTable, filename); 90 | fprintf('Marker locations written to %s\n', filename); 91 | 92 | % Write marker locations to .trc file. The TRCFileAdapter requires DataRate and 93 | % Units be included in the table metadata. 94 | filename = 'marker_locations.trc'; 95 | markerTable.addTableMetaDataString('DataRate', num2str(reportTimeInterval)); 96 | markerTable.addTableMetaDataString('Units', 'm'); 97 | TRCFileAdapter.write(markerTable, filename); 98 | fprintf('Marker locations written to %s\n', filename); 99 | 100 | fprintf('Success!\n'); 101 | -------------------------------------------------------------------------------- /examples/strengthScaler.m: -------------------------------------------------------------------------------- 1 | % ----------------------------------------------------------------------- % 2 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 3 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 4 | % for more information. OpenSim is developed at Stanford University % 5 | % and supported by the US National Institutes of Health (U54 GM072970, % 6 | % R24 HD065690) and by DARPA through the Warrior Web program. % 7 | % % 8 | % Copyright (c) 2005-2017 Stanford University and the Authors % 9 | % Author(s): Dan Lichtwark % 10 | % % 11 | % Licensed under the Apache License, Version 2.0 (the "License"); % 12 | % you may not use this file except in compliance with the License. % 13 | % You may obtain a copy of the License at % 14 | % http://www.apache.org/licenses/LICENSE-2.0. % 15 | % % 16 | % Unless required by applicable law or agreed to in writing, software % 17 | % distributed under the License is distributed on an "AS IS" BASIS, % 18 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 19 | % implied. See the License for the specific language governing % 20 | % permissions and limitations under the License. % 21 | % ----------------------------------------------------------------------- % 22 | 23 | % strengthScaler.m 24 | % Author: Dan Lichtwark 25 | 26 | function strengthScaler(scaleFactor, Model_In, Model_Out) 27 | % OSIMstrength_scaler(scaleFactor, Model_In, Model_Out) 28 | % Test program to load muscles and change strength of muscles and re-save 29 | % model 30 | % 31 | % Inputs - scaleFactor (double) - amount to scale all muscle forces 32 | % Model_In (string) - existing model path and file name 33 | % Model_Out (string) - new model path and file name 34 | % 35 | % eg. strengthScaler(2) 36 | % eg. strengthScaler(2, 'mySimpleBlockModel.osim') 37 | % eg. strengthScaler(2, 'mySimpleBlockModel.osim', 'myStrongerBlockModel.osim') 38 | % 39 | % Author: Glen Lichtwark (The University of Queensland) 40 | % with invaluable assistance from Ayman Habib (Stanford University) 41 | % Initial code replicating the muscleStrengthScaler.cpp file developed by 42 | % Edith Arnold and Ajay Seth 43 | 44 | import org.opensim.modeling.* 45 | 46 | error(nargchk(1, 3, nargin)); 47 | 48 | if nargin < 2 49 | [Model_In, path] = uigetfile('.osim'); 50 | fileoutpath = [Model_In(1:end-5),'_MuscleScaled.osim']; 51 | filepath = [path Model_In]; 52 | elseif nargin < 3 53 | fileoutpath = [Model_In(1:end-5),'_MuscleScaled.osim']; 54 | filepath = Model_In; 55 | else 56 | filepath = Model_In; 57 | fileoutpath = Model_Out; 58 | end 59 | 60 | %Create the Original OpenSim model from a .osim file 61 | Model1 = Model(filepath); 62 | Model1.initSystem; 63 | 64 | % Create a copy of the original OpenSim model for the Modified Model 65 | Model2 = Model(Model1); 66 | Model2.initSystem; 67 | 68 | % Rename the modified Model so that it comes up with a different name in 69 | % the GUI navigator 70 | Model2.setName('modelModified'); 71 | 72 | % Get the set of muscles that are in the original model 73 | Muscles1 = Model1.getMuscles(); 74 | 75 | %Count the muscles 76 | nMuscles = Muscles1.getSize(); 77 | 78 | disp(['Number of muscles in orginal model: ' num2str(nMuscles)]); 79 | 80 | % Get the set of forces that are in the scaled model 81 | % (Should be the same as the original at this point.) 82 | Muscles2 = Model2.getMuscles(); 83 | 84 | % loop through forces and scale muscle Fmax accordingly (index starts at 0) 85 | for i = 0:nMuscles-1 86 | 87 | %get the muscle that the original muscle set points to 88 | %to read the muscle type and the max isometric force 89 | currentMuscle = Muscles1.get(i); 90 | 91 | %define the muscle in the modified model for changing 92 | newMuscle = Muscles2.get(i); 93 | 94 | %define the new muscle force by multiplying current muscle max 95 | %force by the scale factor 96 | newMuscle.setMaxIsometricForce(currentMuscle.getMaxIsometricForce()*scaleFactor); 97 | 98 | end 99 | 100 | % save the updated model to an OSIM xml file 101 | Model2.print(fileoutpath) 102 | disp(['The new model has been saved at ' fileoutpath]); 103 | 104 | end 105 | -------------------------------------------------------------------------------- /examples/wiringInputsAndOutputsWithTableReporter.m: -------------------------------------------------------------------------------- 1 | % ----------------------------------------------------------------------- % 2 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 3 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 4 | % for more information. OpenSim is developed at Stanford University % 5 | % and supported by the US National Institutes of Health (U54 GM072970, % 6 | % R24 HD065690) and by DARPA through the Warrior Web program. % 7 | % % 8 | % Copyright (c) 2005-2017 Stanford University and the Authors % 9 | % Author(s): Christopher Dembia % 10 | % % 11 | % Licensed under the Apache License, Version 2.0 (the "License"); % 12 | % you may not use this file except in compliance with the License. % 13 | % You may obtain a copy of the License at % 14 | % http://www.apache.org/licenses/LICENSE-2.0. % 15 | % % 16 | % Unless required by applicable law or agreed to in writing, software % 17 | % distributed under the License is distributed on an "AS IS" BASIS, % 18 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 19 | % implied. See the License for the specific language governing % 20 | % permissions and limitations under the License. % 21 | % ----------------------------------------------------------------------- % 22 | 23 | % This example shows how to wire inputs and outputs by reporting the position 24 | % of the system's center of mass. We also illustrate that input-output 25 | % connections are stored in model (.osim) files. 26 | % The model contains just one body, a free joint, and the table reporter. 27 | 28 | import org.opensim.modeling.*; 29 | 30 | 31 | modelFilename = 'wiring_inputs_and_outputs_with_TableReporter.osim'; 32 | 33 | %% Create and print the model to a .osim file. 34 | % -------------------------------------------- 35 | model = Model(); 36 | model.setName('model'); 37 | 38 | % Create a body with name 'body', mass of 1 kg, center of mass at the 39 | % origin of the body, and unit inertia (Ixx = Iyy = Izz = 1 kg-m^2). 40 | body = Body('body', 1.0, Vec3(0), Inertia(1)); 41 | 42 | % Create a free joint (all 6 degrees of freedom) with Ground as the parent 43 | % body and 'body' as the child body. 44 | joint = FreeJoint('joint', model.getGround(), body); 45 | 46 | % Add the body and joint to the model. 47 | model.addComponent(body); 48 | model.addComponent(joint); 49 | 50 | % Create a TableReporter to save quantities to a file after simulating. 51 | reporter = TableReporterVec3(); 52 | reporter.setName('reporter'); 53 | reporter.set_report_time_interval(0.1); 54 | % Report the position of the origin of the body. 55 | reporter.addToReport(body.getOutput('position')); 56 | % For comparison, we will also get the center of mass position from the 57 | % Model, and we can check that the two outputs are the same for our 58 | % one-body system. The (optional) second argument is an alias for the name 59 | % of the output; it is used as the column label in the table. 60 | reporter.addToReport(model.getOutput('com_position'), 'com_pos'); 61 | % Display what input-output connections look like in XML (in .osim files). 62 | disp('Reporter input-output connections in XML:'); 63 | disp(reporter.dump()); 64 | 65 | model.addComponent(reporter); 66 | 67 | model.print(modelFilename); 68 | 69 | 70 | %% Load the model file and simulate. 71 | % ---------------------------------- 72 | deserializedModel = Model(modelFilename); 73 | state = deserializedModel.initSystem(); 74 | 75 | % We can fetch the TableReporter from within the deserialized model. 76 | reporter = TableReporterVec3.safeDownCast(... 77 | deserializedModel.getComponent('reporter')); 78 | % We can access the names of the outputs that the reporter is connected to. 79 | disp('Outputs connected to the reporter:'); 80 | for i = 0:(reporter.getInput('inputs').getNumConnectees() - 1) 81 | disp(reporter.getInput('inputs').getConnecteeName(i)); 82 | end 83 | 84 | % Simulate the model. 85 | manager = Manager(deserializedModel); 86 | manager.setInitialTime(0); 87 | manager.setFinalTime(1.0); 88 | manager.integrate(state); 89 | 90 | % Now that the simulation is done, get the table from the TableReporter and 91 | % write it to a file. 92 | % This returns the TimeSeriesTableVec3 that holds the history of positions. 93 | table = reporter.getTable(); 94 | % Create a FileAdapter, which handles writing to (and reading from) .sto files. 95 | sto = STOFileAdapterVec3(); 96 | sto.write(table, 'wiring_inputs_and_outputs_with_TableReporter.sto'); 97 | % You can open the .sto file in a text editor and see that both outputs 98 | % (position of body's origin, and position of system mass center) are the same. 99 | 100 | -------------------------------------------------------------------------------- /misc/FindOsim.m: -------------------------------------------------------------------------------- 1 | function [S C] = FindOsim(varargin) 2 | % Returns a Struct of osim files anywhere in (or below) an input path. If 3 | % no input, will search the current directory. 4 | 5 | if nargin == 0 6 | path = cd; 7 | elseif nargin == 1 8 | path = varargin{1}; 9 | end 10 | 11 | currentDir = cd; 12 | 13 | % Change Dir to input Dir 14 | cd(path) 15 | % Return a struct of osim files 16 | S = dir('**/*.osim'); 17 | cd(currentDir); 18 | 19 | % Output as a cell array with full paths 20 | C = {}; 21 | for i = 1 : length(S) 22 | C(i) = {fullfile(S(i).folder, S(i).name)}; 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /misc/GenerateSubtrials_UsingConvenianceClasses.m: -------------------------------------------------------------------------------- 1 | %% GenerateSubtrials_UsingConvenianceClasses.m 2 | % Example code generating sub-trials from a single, large, IMU data file. 3 | % This is usefull when many minutes of IMU data have been collected but 4 | % orienation tracking with OpenSense is only necessary during specific 5 | % times of the trial. This script uses the OpenSense Matlab Class 6 | % imuDataSlicer(). 7 | 8 | % ----------------------------------------------------------------------- % 9 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 10 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 11 | % for more information. OpenSim is developed at Stanford University % 12 | % and supported by the US National Institutes of Health (U54 GM072970, % 13 | % R24 HD065690) and by DARPA through the Warrior Web program. % 14 | % % 15 | % Copyright (c) 2005-2019 Stanford University and the Authors % 16 | % Author(s): James Dunne % 17 | % % 18 | % Licensed under the Apache License, Version 2.0 (the "License"); % 19 | % you may not use this file except in compliance with the License. % 20 | % You may obtain a copy of the License at % 21 | % http://www.apache.org/licenses/LICENSE-2.0. % 22 | % % 23 | % Unless required by applicable law or agreed to in writing, software % 24 | % distributed under the License is distributed on an "AS IS" BASIS, % 25 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 26 | % implied. See the License for the specific language governing % 27 | % permissions and limitations under the License. % 28 | % ----------------------------------------------------------------------- % 29 | 30 | %% Clear any variables in the workspace 31 | clear all; close all; clc; 32 | 33 | %% Instantiate a imuDataSlicer() 34 | trialpath = 'MT_012005D6_009-001_orientations.sto'; 35 | accPath = 'MT_012005D6_009-001_accelerations.sto'; 36 | % Instantiate the data slicer to carve out smaller trial files 37 | ds = imuDataSlicer(trialpath); 38 | 39 | %% Slice the calibration trial and write it to file 40 | stime = 0.00; 41 | etime = 0.05; 42 | ds.setDataTimeIntervalInMinutes(stime, etime) 43 | ds.generateSubTrial(); 44 | ds.writeSubTrial('calibration_trial') 45 | 46 | %% Slice out a section of walking data and write it to file. 47 | stime = 0.05; 48 | etime = 0.15; 49 | ds.setDataTimeIntervalInMinutes(stime, etime); 50 | ds.generateSubTrial(); 51 | ds.writeSubTrial('Walking_05_10'); 52 | 53 | -------------------------------------------------------------------------------- /misc/OrientationTacking_UsingConvenianceClasses.m: -------------------------------------------------------------------------------- 1 | %% OrientationTacking_UsingConvenianceClasses.m 2 | % Example code to calibrate and track orienation data with OpenSense. This 3 | % script uses the Matlab Class orientationTrackingHelper(). 4 | 5 | % ----------------------------------------------------------------------- % 6 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 7 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 8 | % for more information. OpenSim is developed at Stanford University % 9 | % and supported by the US National Institutes of Health (U54 GM072970, % 10 | % R24 HD065690) and by DARPA through the Warrior Web program. % 11 | % % 12 | % Copyright (c) 2005-2019 Stanford University and the Authors % 13 | % Author(s): James Dunne % 14 | % % 15 | % Licensed under the Apache License, Version 2.0 (the "License"); % 16 | % you may not use this file except in compliance with the License. % 17 | % You may obtain a copy of the License at % 18 | % http://www.apache.org/licenses/LICENSE-2.0. % 19 | % % 20 | % Unless required by applicable law or agreed to in writing, software % 21 | % distributed under the License is distributed on an "AS IS" BASIS, % 22 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 23 | % implied. See the License for the specific language governing % 24 | % permissions and limitations under the License. % 25 | % ----------------------------------------------------------------------- % 26 | 27 | %% Orientation Tracking 28 | clear all; close all; clc; 29 | % Instantiate an orienation tracking helper object. This is a Matlab Class 30 | % that wraps both Calibration and Tracking in the same object for greater 31 | % conveniance. 32 | ot = orientationTrackingHelper(); 33 | 34 | %% Calibrate the Model 35 | % Setup the Model Calibration. 36 | ot.setModelCalibrationPoseFile('imuTrackingModel.osim'); 37 | % ot.setCalibrationTrialName('MT_012005D6_009-quaternions_calibration_trial_Facing_X.sto'); 38 | ot.setCalibrationTrialName('MT_012005D6_009-001_orientations.sto'); 39 | ot.setBaseHeadingAxis(0) 40 | ot.setVisualizeCalibratedModel(0) 41 | ot.setCalibratedModelOutputName('calibrated_imuTrackingModel.osim') 42 | % Run the orientation calibration. 43 | ot.generateCalibratedModel() 44 | % Write the calibrated model to file. 45 | ot.writeCalibratedModel2File() 46 | 47 | %% Run IK Orientation Tracking 48 | % Set the name of the orientation File to be tracked 49 | ot.setTrackingOrientationsFileName('MT_012005D6_009-001_orientations.sto'); 50 | % Set the Output directory for the results file 51 | ot.setIKResultsDir('IKResults') 52 | % Set the time interval (in minutes) to be tracked. 53 | ot.setIKTimeIntervalInMinutes(0.05,0.10); 54 | % Set the Visualization Boolean. 55 | ot.setVisualizeTracking(1); 56 | % Run orientation tracking 57 | ot.runOrientationTracking(); 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /misc/TRCFileFixer.m: -------------------------------------------------------------------------------- 1 | function TRCFileFixer(trcPath) 2 | %% Fix issues with a TRC File 3 | 4 | %% Get file parts for the input TRC 5 | [FILEPATH,NAME,EXT] = fileparts(trcPath); 6 | if isempty(FILEPATH) 7 | FILEPATH = cd; 8 | end 9 | 10 | %% Read data in and format into a struct 11 | q = read_trcFile(trcPath); 12 | 13 | markers = struct(); 14 | for i = 1 : q.nummarkers 15 | markers.(q.labels{i}) = q.data(:, i*3-2:i*3); 16 | end 17 | markers.time = q.time; 18 | 19 | %% Convert the stucture to an OpenSim Table 20 | % import opensim libraries 21 | import org.opensim.modeling.* 22 | 23 | % Display a message saying that this may take awhile 24 | display('If your trc file is large, this may take awhile :('); 25 | 26 | % Convert using function found in opensim code/Matlab/utilities folder 27 | mTable = osimTableFromStruct(markers); 28 | % Add Necessary MetaData 29 | mTable.addTableMetaDataString('DataRate', num2str(q.datarate)); 30 | mTable.addTableMetaDataString('Units', 'mm'); 31 | 32 | %% Write to file using the TRCFileAdapter 33 | outputPath = fullfile(FILEPATH, strrep(trcPath, '.trc', '_fixed.trc')); 34 | TRCFileAdapter().write( mTable, outputPath) 35 | display(['TRC File Written to ' outputPath ]); 36 | end 37 | 38 | function q = read_trcFile(fname) 39 | 40 | fin = fopen(fname, 'r'); 41 | if fin == -1 42 | error(['unable to open ', fname]) 43 | end 44 | 45 | nextline = fgetl(fin); 46 | trcversion = sscanf(nextline, 'PathFileType %d'); 47 | if trcversion ~= 4 48 | disp('trc PathFileType is not 4, aborting'); 49 | return; 50 | end 51 | 52 | nextline = fgetl(fin); 53 | 54 | nextline = fgetl(fin); 55 | values = sscanf(nextline, '%f %f %f %f'); 56 | numframes = values(3); 57 | q.nummarkers = values(4); 58 | numcolumns=3*q.nummarkers+2; 59 | 60 | nextline = fgetl(fin); 61 | q.labels = cell(1, numcolumns); 62 | [q.labels{1}, nextline] = strtok(nextline); % should be Frame# 63 | [q.labels{2}, nextline] = strtok(nextline); % should be Time 64 | for i = 1 : q.nummarkers 65 | [markername, nextline] = strtok(nextline); 66 | q.labels{2+i} = markername; 67 | end 68 | 69 | nextline = fgetl(fin); 70 | if isspace(nextline(1)) 71 | while true 72 | nextline = fgetl(fin); 73 | if ~isspace(nextline(1)) 74 | break 75 | end 76 | end 77 | end 78 | 79 | columns_in_table = length(sscanf(nextline, '%f')); 80 | markers_in_table = (columns_in_table - 2) /3; 81 | if markers_in_table ~= q.nummarkers 82 | warning(['Number of Marker labels in file (' num2str(q.nummarkers) ') doesnt equal number of columns of marker data (' num2str(markers_in_table) '). ']) 83 | end 84 | % Update the number of markers 85 | q.nummarkers = markers_in_table; 86 | % Put the data in an array 87 | data = zeros(numframes,columns_in_table); 88 | for i = 1 : numframes 89 | data(i,:) = sscanf(nextline, '%f')'; 90 | nextline = fgetl(fin); 91 | end 92 | q.time = data(:,2); 93 | q.data = data(:,3:end); 94 | q.labels = q.labels(3:end); 95 | q.datarate = 1/(q.time(2) - q.time(1)); 96 | end -------------------------------------------------------------------------------- /misc/createActuatorsFile.m: -------------------------------------------------------------------------------- 1 | function createActuatorsFile(modelpath) 2 | %% Function to generate a generic OpenSim Actuator File from a Model by 3 | % identifying the coordinates that are connected to ground and placing 4 | % point or torque actuators on translational or rotational coordinates, 5 | % respectively. All other coordiantes will get coordinate actuators. 6 | % Any constrained coordinates will be ignored. 7 | % File is Printed to the same folder as the selected Model. 8 | % 9 | % Inputs - modelpath ? path to an OSIM file (string) 10 | % 11 | % e.g. createActuatorsFile('myInputModel.osim') 12 | 13 | % Author: James Dunne, Tom Uchida, Chris Dembia, 14 | % Ajay Seth, Ayman Habib, Shrinidhi K. Lakshmikanth, Jen Hicks. 15 | % ----------------------------------------------------------------------- % 16 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 17 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 18 | % for more information. OpenSim is developed at Stanford University % 19 | % and supported by the US National Institutes of Health (U54 GM072970, % 20 | % R24 HD065690) and by DARPA through the Warrior Web program. % 21 | % % 22 | % Copyright (c) 2005-2016 Stanford University and the Authors % 23 | % Author(s): James Dunne % 24 | % % 25 | % Licensed under the Apache License, Version 2.0 (the "License"); % 26 | % you may not use this file except in compliance with the License. % 27 | % You may obtain a copy of the License at % 28 | % http://www.apache.org/licenses/LICENSE-2.0. % 29 | % % 30 | % Unless required by applicable law or agreed to in writing, software % 31 | % distributed under the License is distributed on an "AS IS" BASIS, % 32 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 33 | % implied. See the License for the specific language governing % 34 | % permissions and limitations under the License. % 35 | % ----------------------------------------------------------------------- % 36 | 37 | %% Import OpenSim Libraries 38 | import org.opensim.modeling.* 39 | 40 | 41 | display('Loading the model...'); 42 | if nargin < 1 43 | [pathname,filename] = uigetfile('*.osim', 'PSelect an OpenSim Model File'); 44 | modelpath = fullfile(filename,pathname); 45 | elseif nargin > 1 46 | error('Too many inputs to function. Input is Model path'); 47 | end 48 | 49 | %% Instantiate the model 50 | model = Model(modelpath); 51 | 52 | %% Generate an instance of the model 53 | model = Model(modelFilePath); 54 | 55 | %% Instantiate the underlying computational System and return a handle to the State 56 | state = model.initSystem(); 57 | 58 | %% Get the number of coordinates and a handle to the coordainte set 59 | coordSet = model.getCoordinateSet(); 60 | nCoord = coordSet.getSize(); 61 | 62 | %% Instantiate some empty vec3's for later. 63 | massCenter = Vec3(); 64 | axisValues = Vec3(); 65 | 66 | %% Instantiate an empty Force set 67 | forceSet = ForceSet(); 68 | 69 | %% Set the optimal force 70 | optimalForce = 1; 71 | 72 | %% Start going through the coordinates, creating an actuator for each 73 | for iCoord = 0 : nCoord - 1 74 | 75 | % get a reference to the current coordinate 76 | coordinate = coordSet.get(iCoord); 77 | % If the coodinate is constrained (locked or prescribed), don't 78 | % add an actuator 79 | if coordinate.isConstrained(state) 80 | continue 81 | end 82 | 83 | % get the joint, parent and child names for the coordiante 84 | joint = coordinate.getJoint(); 85 | parentName = joint.getParentFrame().getName(); 86 | childName = joint.getChildFrame().getName(); 87 | 88 | % If the coordinates parent body is connected to ground, we need to 89 | % add residual actuators (torque or point). 90 | if strcmp(parentName, model.getGround.getName() ) 91 | 92 | % Custom and Free Joints have three translational and three 93 | % rotational coordinates. 94 | if strcmp(joint.getConcreteClassName(), 'CustomJoint') || strcmp(joint.getConcreteClassName(), 'FreeJoint') 95 | % get the coordainte motion type 96 | motion = char(coordinate.getMotionType()); 97 | % to get the axis value for the coordinate, we need to drill 98 | % down into the coordinate transform axis 99 | eval(['concreteJoint = ' char(joint.getConcreteClassName()) '.safeDownCast(joint);']) 100 | sptr = concreteJoint.getSpatialTransform(); 101 | for ip = 0 : 5 102 | if strcmp(char(sptr.getCoordinateNames().get(ip)), char(coordinate.getName)) 103 | sptr.getTransformAxis(ip).getAxis(axisValues); 104 | break 105 | end 106 | end 107 | 108 | 109 | % make a torque actuator if a rotational coordinate 110 | if strcmp(motion, 'Rotational') 111 | newActuator = TorqueActuator(joint.getParentFrame(),... 112 | joint.getParentFrame(),... 113 | axisValues); 114 | 115 | % make a point actuator if a translational coordinate. 116 | elseif strcmp(motion, 'translational') 117 | % make a new Point actuator 118 | newActuator = PointActuator(); 119 | % set the body 120 | newActuator.set_body(char(joint.getChildFrame().getName())) 121 | % set point that forces acts at 122 | newActuator.set_point(massCenter) 123 | % the point is expressed in the local 124 | newActuator.set_point_is_global(false) 125 | % set the direction that actuator will act in 126 | newActuator.set_direction(axisValues) 127 | % the force is expressed in the global 128 | newActuator.set_force_is_global(true) 129 | else % something else that we don't support right now 130 | newActuator = CoordinateActuator(); 131 | end 132 | else % if the joint type is not free or custom, just add coordinate actuators 133 | % make a new coordinate actuator for that coordinate 134 | newActuator = CoordinateActuator(); 135 | end 136 | 137 | else % the coordinate is not connected to ground, and can just be a 138 | % coordinate actuator. 139 | newActuator = CoordinateActuator( char(coordinate.getName) ); 140 | end 141 | 142 | % set the optimal force for that coordinate 143 | newActuator.setOptimalForce(optimalForce); 144 | % set the actuator name 145 | newActuator.setName( coordinate.getName() ); 146 | % set min and max controls 147 | newActuator.setMaxControl(Inf) 148 | newActuator.setMinControl(-Inf) 149 | 150 | % append the new actuator onto the empty force set 151 | forceSet.cloneAndAppend(newActuator); 152 | end 153 | 154 | 155 | %% Print Actuators to file. 156 | % Get the file parts 157 | [pathname,filename,ext] = fileparts(modelpath); 158 | % Make the print path 159 | printPath = fullfile(pathname, [filename '_actuators.xml']); 160 | %% Print the actuators xml file 161 | forceSet.print(printPath); 162 | %% Display printed file 163 | display(['Printed actuators to ' printPath]) 164 | 165 | end 166 | -------------------------------------------------------------------------------- /misc/externalLoadsBuilder.m: -------------------------------------------------------------------------------- 1 | classdef externalLoadsBuilder < matlab.mixin.SetGet 2 | % Class for building a external loads .xml 3 | % 4 | % External loads file require the allocation of forces to bodies. In this 5 | % class we find which foot of a standard OpenSim gait model is closest to 6 | % forces from a forceplate, then use that information to write an 7 | % external loads file for use in Inverse Dynamics. 8 | properties (Access = private) 9 | NumCoordinates 10 | coordinateLabels 11 | times 12 | times_forces 13 | motion 14 | forces 15 | forcelocationIndex 16 | ForceRow 17 | forceStruct 18 | forceslabels 19 | model 20 | state 21 | datafile 22 | outputFileName 23 | end 24 | methods 25 | function obj = externalLoadsBuilder(modelPath, path2MotionFile, Path2GRFFile) 26 | import org.opensim.modeling.* 27 | % Get motioin data into a table 28 | motion = STOFileAdapter().read(path2MotionFile); 29 | % Generate an array with times 30 | nRows = motion.getNumRows(); 31 | timeCol = motion.getIndependentColumn(); 32 | dt = timeCol.get(1) - timeCol.get(0); 33 | times = [timeCol.get(0):dt:timeCol.get(nRows-1)]'; 34 | 35 | % Get the coordinate names 36 | coordinatelabels = {}; 37 | tableLabels = motion.getColumnLabels; 38 | for i = 0 : motion.getNumColumns() -1 39 | coordinatelabels{i+1,1} = char(tableLabels.get(i)); 40 | end 41 | 42 | % Get the location of the forces from the input file 43 | forces = STOFileAdapter().read(Path2GRFFile); 44 | nCols = forces.getNumColumns(); 45 | nForces = nCols/9; 46 | forceslabels = {}; 47 | tableLabels = forces.getColumnLabels(); 48 | for i = 0 : nCols - 1 49 | forceslabels{i+1,1} = char(tableLabels.get(i)); 50 | end 51 | 52 | locationIndex = []; 53 | for i = 1 : nCols 54 | if contains(forceslabels{i},'px') 55 | locationIndex = [locationIndex i]; 56 | end 57 | end 58 | % Generate an array with times 59 | nRows = forces.getNumRows(); 60 | timeCol = forces.getIndependentColumn(); 61 | dt = timeCol.get(1) - timeCol.get(0); 62 | times_forces= [timeCol.get(0):dt:timeCol.get(nRows-1)]'; 63 | 64 | % Get the marker and force data as Structs 65 | forceStruct = osimTableToStruct(forces); 66 | 67 | % Create the output name, which can be used later 68 | [path,name,ext] = fileparts(Path2GRFFile); 69 | if isempty(path) 70 | path = cd; 71 | end 72 | outputFileName = fullfile(path,[name '_ExternalLoads.xml']); 73 | 74 | % Instantiat a model 75 | model = Model(modelPath); 76 | state = model.initSystem(); 77 | 78 | % Set the properties of the class 79 | obj.NumCoordinates = length(coordinatelabels); 80 | obj.coordinateLabels = coordinatelabels; 81 | obj.times = times; 82 | obj.times_forces = times_forces; 83 | obj.motion = motion; 84 | obj.forces = forces; 85 | obj.forceStruct = forceStruct; 86 | obj.ForceRow = 0; 87 | obj.forcelocationIndex = locationIndex; 88 | obj.forceslabels = forceslabels; 89 | obj.model = model; 90 | obj.state = state; 91 | obj.datafile = Path2GRFFile; 92 | obj.outputFileName = outputFileName; 93 | end 94 | function run(obj) 95 | import org.opensim.modeling.* 96 | disp('Building External Loads file ...') 97 | % For each force; when do they peak?. Find the 98 | % closest foot at peak? 99 | feetAllocation = {}; 100 | fpUsed = []; 101 | % For each force, find the time of peak force 102 | for i = 1 : length(obj.forcelocationIndex) 103 | eval(['[M I] = max(obj.forceStruct.ground_force_' num2str(i) '_vy());']); 104 | if M < 100 105 | continue 106 | end 107 | fpUsed = [fpUsed i]; 108 | time = obj.times_forces(I); 109 | obj.ForceRow = I; 110 | 111 | % At the peak, find which foot is closest to the force point 112 | % Posiiton the model from the coordinate 113 | obj.motionBuilder(time); 114 | % Determine which foot is closest to the force 115 | feetAllocation = [feetAllocation {obj.forces2bodies(i,I)}]; 116 | end 117 | 118 | % Allocate the force an External load object 119 | el = ExternalLoads(); 120 | 121 | for i = 1 : length(feetAllocation) 122 | % Build an external force 123 | ef = ExternalForce(); 124 | ef.setName([ feetAllocation{i} '_ExternalForce']); 125 | ef.set_applied_to_body( feetAllocation{i} ); 126 | ef.set_force_expressed_in_body('ground'); 127 | ef.set_point_expressed_in_body('ground'); 128 | % Get the force, point, and torque colomn identifiers 129 | forceIDIndex = find( contains(obj.forceslabels,[num2str(fpUsed(i)) '_vx'])); 130 | pointIDIndex = find( contains(obj.forceslabels,[num2str(fpUsed(i)) '_px'])); 131 | torqueIDIndex = find( contains(obj.forceslabels,[num2str(fpUsed(i)) '_mx'])); 132 | % Set the identifiers on the the external force 133 | ef.set_force_identifier( strrep(obj.forceslabels{forceIDIndex},'x','')); 134 | ef.set_point_identifier(strrep(obj.forceslabels{pointIDIndex},'x','') ); 135 | ef.set_torque_identifier(strrep(obj.forceslabels{torqueIDIndex},'x','')); 136 | % Clone and append the external force to the external load 137 | el.cloneAndAppend(ef); 138 | end 139 | % Set the Datafile Path 140 | el.setDataFileName(obj.datafile); 141 | % Write the .XML to file 142 | el.print(obj.outputFileName()); 143 | disp(['External Loads written to ' obj.outputFileName()]); 144 | end 145 | function motionBuilder(obj, time) 146 | import org.opensim.modeling.* 147 | % Set the pose of the model from the motion file 148 | 149 | % Check that motion file and model are consistent 150 | if obj.NumCoordinates ~= obj.motion.getNumColumns() 151 | error('Number of Coordinates in motion file dont match model') 152 | end 153 | % 154 | dataRow = find(time == obj.times); 155 | % Get the index for the row of data whose time value is closest 156 | % from the coordinate data 157 | [c dataRow] = min(abs(obj.times-time)); 158 | 159 | % Get the data as a Row Vector 160 | data = obj.motion.getRowAtIndex(dataRow - 1); 161 | % Set the pose of the model from the Row Data 162 | for i = 0 : obj.NumCoordinates - 1 163 | % Get the label 164 | coordLabel = obj.coordinateLabels{i+1}; 165 | % set the coordinate value. 166 | obj.model.getCoordinateSet().get(coordLabel).setValue(obj.state,data.get(i)); 167 | end 168 | disp(['Model coordinate values set from time = ' num2str(time)]); 169 | end 170 | function closestFoot = forces2bodies(obj,forcePlateIndex,I) 171 | import org.opensim.modeling.* 172 | % Get the Calcaneous positions in Ground 173 | cr_position = osimVec3ToArray(obj.model.getBodySet.get('calcn_r').getPositionInGround(obj.state)); 174 | cl_position = osimVec3ToArray(obj.model.getBodySet.get('calcn_l').getPositionInGround(obj.state)); 175 | 176 | % Get the point column number in the force timesseries table. 177 | u = obj.forcelocationIndex(forcePlateIndex) - 1; 178 | % Get the XYZ value of the point 179 | p = [obj.forces.getDependentColumnAtIndex(u ).get(I-1) ... 180 | obj.forces.getDependentColumnAtIndex(u+1).get(I-1) ... 181 | obj.forces.getDependentColumnAtIndex(u+2).get(I-1)]; 182 | if obj.dbp(cr_position,p) < obj.dbp(cl_position,p) 183 | closestFoot = 'calcn_r'; 184 | else 185 | closestFoot = 'calcn_l'; 186 | end 187 | end 188 | function d = dbp(obj,p1,p2) 189 | % distanceBetweenPoints 190 | % Compute the distance between two 3D points. 191 | % get the vector between the points 192 | if ~isequal(size(p1), size(p2)) 193 | error('input arrays are of different sizes') 194 | end 195 | % Pre-allocate an array for the distance 196 | d = zeros(size(p1,1),1); 197 | % Calc the vector between the two points 198 | v = p1 - p2; 199 | % Calc the length of the vector 200 | for i = 1 : size(v,1) 201 | d(i) = norm(v(i,:)); 202 | end 203 | end 204 | function datafilepath = getOutputFileName(obj) 205 | datafilepath = obj.outputFileName(); 206 | end 207 | function startTime = getMotionStartTime(obj) 208 | startTime = obj.times(1); 209 | end 210 | function endTime = getMotionEndTime(obj) 211 | endTime = obj.times(end); 212 | end 213 | end 214 | end 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /misc/generateTrackingTasksMarkers.m: -------------------------------------------------------------------------------- 1 | function markerList = generateTrackingTasksMarkers(model, trcpath) 2 | %% generateTrackingTasksMarkers 3 | % Generate a list of Marker labels that can be used to make tracking tasks. 4 | % 5 | 6 | %% Import OpenSim Libs 7 | import org.opensim.modeling.* 8 | 9 | %% Get the marker Table 10 | trc = TRCFileAdapter().read(trcpath); 11 | 12 | %% get the TRC Marker Names 13 | t = TRCFileAdapter().read(trcpath); 14 | trcNames = []; 15 | 16 | for i = 0 : t.getNumColumns() - 1 17 | label = char(t.getColumnLabels().get(i)); 18 | if ~isempty(strfind(label, ':')) 19 | label = label(strfind(label, ':')+1:end); 20 | end 21 | trcNames = [trcNames; {label}]; 22 | end 23 | 24 | %% Get Model Marker Names 25 | markerNames = []; 26 | for i = 0 : model.getMarkerSet().getSize()-1; 27 | markerNames = [markerNames; {char(model.getMarkerSet().get(i).getName() )}]; 28 | end 29 | 30 | %% Generate a final list of Markers to track 31 | markerList = intersect(markerNames,trcNames); 32 | 33 | end -------------------------------------------------------------------------------- /misc/orientationTrackingHelper.m: -------------------------------------------------------------------------------- 1 | % orientationTrackingHelper() 2 | % Helper Class to perform OpenSense Tracking of Orienation data. 3 | % Models can be calibrated and IK Tracking. 4 | % There are no Inputs to this class, but updates must be made to settings 5 | % such as the setCalibratedModelName() and trackingOrientationsFileName() 6 | classdef orientationTrackingHelper < matlab.mixin.SetGet 7 | 8 | % ----------------------------------------------------------------------- % 9 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 10 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 11 | % for more information. OpenSim is developed at Stanford University % 12 | % and supported by the US National Institutes of Health (U54 GM072970, % 13 | % R24 HD065690) and by DARPA through the Warrior Web program. % 14 | % % 15 | % Copyright (c) 2005-2019 Stanford University and the Authors % 16 | % Author(s): James Dunne % 17 | % % 18 | % Licensed under the Apache License, Version 2.0 (the "License"); % 19 | % you may not use this file except in compliance with the License. % 20 | % You may obtain a copy of the License at % 21 | % http://www.apache.org/licenses/LICENSE-2.0. % 22 | % % 23 | % Unless required by applicable law or agreed to in writing, software % 24 | % distributed under the License is distributed on an "AS IS" BASIS, % 25 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 26 | % implied. See the License for the specific language governing % 27 | % permissions and limitations under the License. % 28 | % ----------------------------------------------------------------------- % 29 | properties (Access = private) 30 | modelCalibrationPoseFile 31 | calibrationTrialName 32 | baseImuName 33 | baseHeadingAxis 34 | opensenseUtility 35 | visualizeCalibratedModel 36 | calibratedModel 37 | calibratedModelName 38 | ikSetupPath 39 | trackingOrientationsFileName 40 | visualizeTracking 41 | outputResultsFileName 42 | ikStartTime 43 | ikEndTime 44 | ikStudy 45 | ikResultsDir 46 | end 47 | methods 48 | function obj = orientationTrackingHelper 49 | import org.opensim.modeling.* 50 | obj.modelCalibrationPoseFile =''; 51 | obj.calibrationTrialName = ''; 52 | obj.baseImuName = 'pelvis_imu'; 53 | obj.baseHeadingAxis = CoordinateAxis(0); 54 | obj.opensenseUtility = OpenSenseUtilities(); 55 | obj.visualizeCalibratedModel = 0; 56 | outputResultsFileName = []; 57 | obj.ikStartTime = []; 58 | obj.ikEndTime = []; 59 | end 60 | function generateCalibratedModel(obj) 61 | import org.opensim.modeling.* 62 | model = obj.opensenseUtility.calibrateModelFromOrientations(obj.modelCalibrationPoseFile,... 63 | obj.calibrationTrialName,... 64 | obj.baseImuName,... 65 | obj.baseHeadingAxis,... 66 | obj.visualizeCalibratedModel); 67 | model.initSystem(); 68 | obj.calibratedModel = model; 69 | end 70 | function writeCalibratedModel2File(obj) 71 | import org.opensim.modeling.* 72 | obj.calibratedModel.print(obj.calibratedModelName()) 73 | end 74 | function setCalibratedModelOutputName(obj,fileName) 75 | obj.calibratedModelName = fileName; 76 | end 77 | function o = getCalibratedModelOutputName(obj) 78 | o = obj.calibratedModelName; 79 | end 80 | function setModelCalibrationPoseFile(obj, fileName) 81 | obj.modelCalibrationPoseFile = fileName; 82 | end 83 | function o = getModelCalibrationPoseFile(obj) 84 | o = obj.modelCalibrationPoseFile; 85 | end 86 | function setCalibrationTrialName(obj, fileName) 87 | obj.calibrationTrialName = fileName; 88 | end 89 | function o = getCalibrationTrialName(obj) 90 | o = obj.calibrationTrialName; 91 | end 92 | function setBaseHeadingAxis(obj, heading) 93 | import org.opensim.modeling.* 94 | obj.baseHeadingAxis = CoordinateAxis(heading); 95 | end 96 | function o = getBaseHeadingAxis(obj) 97 | o = obj.baseHeadingAxis(); 98 | end 99 | function setVisualizeCalibratedModel(obj, b) 100 | obj.visualizeCalibratedModel = b; 101 | end 102 | function o = getVisualizeCalibratedModel(obj) 103 | o = obj.visualizeCalibratedModel (); 104 | end 105 | function setIkSetupPath(obj, fileName) 106 | obj.ikSetupPath = fileName; 107 | end 108 | function o = getIkSetupPath(obj) 109 | o = obj.ikSetupPath; 110 | end 111 | function setTrackingOrientationsFileName(obj,fileName) 112 | obj.trackingOrientationsFileName = fileName; 113 | end 114 | function getTrackingOrientationsFileName(obj) 115 | o = obj.trackingOrientationsFileName ; 116 | end 117 | function setVisualizeTracking(obj,b) 118 | obj.visualizeTracking = b; 119 | end 120 | function o = getVisualizeTracking(obj) 121 | o = obj.visualizeTracking(); 122 | end 123 | function setOutputResultsFileName(obj, fileName) 124 | obj.outputResultsFileName = fileName; 125 | end 126 | function o = getOutputResultsFileName(obj) 127 | o = obj.outputResultsFileName; 128 | end 129 | function setIKTimeIntervalInMinutes(obj, stime, etime) 130 | t0 = seconds(minutes(fix((stime)))) + ((stime - fix((stime)))*100); 131 | tn = seconds(minutes(fix((etime)))) + ((etime - fix((etime)))*100); 132 | 133 | obj.ikStartTime = t0; 134 | obj.ikEndTime = tn; 135 | end 136 | function o = getIKStartTime(obj) 137 | o = obj.ikStartTime; 138 | end 139 | function o = getIKEndTime(obj) 140 | o = obj.ikEndTime; 141 | end 142 | function o = writeIKStudySetup2File(obj,ikStudyFileName) 143 | import org.modeling.opensim.* 144 | 145 | if isempty(obj.ikStudy) 146 | error('No IK solution has been generated, run runOrientationTracking()') 147 | end 148 | % Write the IK Study Setup to file. 149 | obj.ikStudy.print(ikStudyFileName); 150 | end 151 | function setIKResultsDir(obj, dirName) 152 | obj.ikResultsDir = dirName; 153 | end 154 | function runOrientationTracking(obj) 155 | import org.opensim.modeling.* 156 | % Instantiate an IK Study 157 | ik = InverseKinematicsStudy(); 158 | ik.set_orientations_file_name(obj.trackingOrientationsFileName) 159 | % Set time range 160 | imuData = STOFileAdapterQuaternion().readFile(obj.trackingOrientationsFileName); 161 | % Set the start and end times 162 | ik.setStartTime( obj.ikStartTime) 163 | ik.setEndTime(obj.ikEndTime) 164 | 165 | % Set the axis heading 166 | if obj.baseHeadingAxis().isXAxis 167 | trackingHeadingAxis = 'x'; 168 | elseif obj.baseHeadingAxis().isYAxis 169 | trackingHeadingAxis = 'y'; 170 | elseif obj.baseHeadingAxis().isZAxis 171 | trackingHeadingAxis = 'z'; 172 | end 173 | % Set the base IMU 174 | ik.set_base_imu_label(obj.baseImuName) 175 | % set the heading axis 176 | ik.set_base_heading_axis(trackingHeadingAxis); 177 | % Change the model file 178 | ik.setModel(obj.calibratedModel); 179 | % Set the output directory Name 180 | ik.set_results_directory(obj.ikResultsDir) 181 | % Run IK 182 | ik.run(obj.visualizeTracking) 183 | % Save IKStudy Object for writing to file 184 | obj.ikStudy = ik; 185 | end 186 | end 187 | end 188 | -------------------------------------------------------------------------------- /misc/osimRotateTableData.m: -------------------------------------------------------------------------------- 1 | function table_rotated = osimRotateTableData(table, axisString, value) 2 | % Utility function for for rotating Vec3 TableData elements 3 | % about an axisString by value (in degrees). 4 | % table Vec3 dataTable 5 | % axisString string 'x', 'y', or 'z' 6 | % value double, in degrees 7 | % 8 | % Example: rotate all (Vec3) elements in t by 90 degrees about the x axisString. 9 | % t_r = rotateTableData(t, 'x', -90) 10 | 11 | % Written by: James Dunne 12 | 13 | %% import java libraries 14 | import org.opensim.modeling.* 15 | 16 | %% set up the transform 17 | if strcmp(axisString, 'x') 18 | axis = CoordinateAxis(0); 19 | elseif strcmp(axisString, 'y') 20 | axis = CoordinateAxis(1); 21 | elseif strcmp(axisString, 'z') 22 | axis = CoordinateAxis(2); 23 | else 24 | error(['Axis must be either x,y or z']) 25 | end 26 | 27 | %% instantiate a transform object 28 | R = Rotation( deg2rad(value) , axis ) ; 29 | 30 | %% rotate the elements in each row 31 | % clone the table. 32 | table_rotated = table.clone(); 33 | 34 | for iRow = 0 : table_rotated.getNumRows() - 1 35 | % get a row from the table 36 | rowVec = table_rotated.getRowAtIndex(iRow); 37 | % rotate each Vec3 element of row vector, rowVec, at once 38 | rowVec_rotated = R.multiply(rowVec); 39 | % overwrite row with rotated row 40 | table_rotated.setRowAtIndex(iRow,rowVec_rotated) 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /misc/plotMuscleFLCurves.m: -------------------------------------------------------------------------------- 1 | function plotMuscleFLCurves(modelpath) 2 | %% Function computes and plots the active and passive force--length curves 3 | % for a specified muscle over the range of possible fiber lengths. (This range 4 | % is only approximate for muscles that cross more than one degree of freedom.) 5 | % Input is a path to a model. A list of muscles will be generated in the 6 | % Matlab Command Window for you to select. A plot will be generated of the 7 | % possible muscle active and passive force-length capacity in the model. 8 | % 9 | % Inputs - modelpath ? path to an OSIM file (string) 10 | % 11 | % e.g. plotMuscleFLCurves('myInputModel.osim') 12 | 13 | 14 | % Author: James Dunne, Chris Dembia, Tom Uchida, Ajay Seth. 15 | % -------------------------------------------------------------------------- % 16 | % plotMuscleFLCurves.m % 17 | % -------------------------------------------------------------------------- % 18 | % The OpenSim API is a toolkit for musculoskeletal modeling and simulation. % 19 | % See http://opensim.stanford.edu and the NOTICE file for more information. % 20 | % OpenSim is developed at Stanford University and supported by the US % 21 | % National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA % 22 | % through the Warrior Web program. % 23 | % % 24 | % Copyright (c) 2005-2017 Stanford University and the Authors % 25 | % Author(s): James Dunne % 26 | % % 27 | % Licensed under the Apache License, Version 2.0 (the "License"); you may % 28 | % not use this file except in compliance with the License. You may obtain a % 29 | % copy of the License at http://www.apache.org/licenses/LICENSE-2.0. % 30 | % % 31 | % Unless required by applicable law or agreed to in writing, software % 32 | % distributed under the License is distributed on an "AS IS" BASIS, % 33 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 34 | % See the License for the specific language governing permissions and % 35 | % limitations under the License. % 36 | % -------------------------------------------------------------------------- % 37 | 38 | %% import Java Libraries 39 | import org.opensim.modeling.* 40 | 41 | %% Get input model 42 | display('Loading the model...'); 43 | if nargin < 1 44 | [filein, pathname] = ... 45 | uigetfile('*.osim', 'Please select an OpenSim model file...'); 46 | model = Model(fullfile(pathname,filein)); 47 | elseif nargin == 1 48 | model = Model(modelpath); 49 | elseif nargin > 1 50 | error('Too many inputs to function. Input Model path'); 51 | end 52 | 53 | display('Creating the Simbody system...'); 54 | state = model.initSystem(); 55 | 56 | %% Ensure the model contains at least one muscle. 57 | if (model.getMuscles().getSize() < 1) 58 | display('No muscles found; exiting.'); 59 | return; 60 | end 61 | 62 | %% Display all muscle names. 63 | musclelist = {}; 64 | fprintf('%d muscles found:\n', model.getMuscles().getSize()); 65 | for i = 0 : model.getMuscles().getSize() - 1 66 | thisName = char(model.getMuscles().get(i).getName()); 67 | musclelist = [ musclelist; {thisName} ]; 68 | display([ ' ', thisName ]); 69 | end 70 | 71 | %% Prompt the user to select a muscle. 72 | stopLoop = false; 73 | 74 | while (~stopLoop) 75 | validName = false; 76 | 77 | while (~validName) 78 | string = input('Type a muscle name to plot, or ''exit'' to close: ', 's'); 79 | 80 | % Get a valid name or 'exit'. 81 | nameIndex = ... 82 | find(cellfun(@(s) ~isempty(strmatch(string, s)), musclelist) == 1); 83 | 84 | if strmatch(string, 'exit'); 85 | stopLoop = true; 86 | break; 87 | elseif isempty(nameIndex); 88 | display('Muscle name not found.'); 89 | else 90 | validName = true; 91 | musclename = char( musclelist(nameIndex) ); 92 | end 93 | end 94 | 95 | if (stopLoop) 96 | display('Exiting.'); 97 | close all; 98 | return; 99 | end 100 | 101 | % Find the coordinates that the muscle crosses. 102 | muscle = getMuscleCoordinates(model, state, musclename); 103 | 104 | % Get the force--length curves of the muscle. 105 | [fl_active, fl_passive] = getForceLength(model, state, muscle); 106 | 107 | % Plot the results. 108 | fig = figure(1); 109 | clf(fig); 110 | 111 | % Make scatter plots for the active and passive components. 112 | hold on; 113 | title(musclename); 114 | scatter(fl_active(:,1), fl_active(:,2), 'b', ... 115 | 'DisplayName', 'Active'); 116 | scatter(fl_passive(:,1), fl_passive(:,2), 'r', ... 117 | 'DisplayName', 'Passive'); 118 | xlim([0.4, 1.6]); 119 | xlabel('Fiber Length (Normalised)'); 120 | ylabel('Fiber Force (N)'); 121 | legend('show'); 122 | hold off; 123 | 124 | end 125 | end 126 | 127 | 128 | function muscle = getMuscleCoordinates(model, state, muscleName) 129 | % Returns a structure containing the coordinates that a muscle crosses and the 130 | % range of values for which the muscle can generate a moment. This is done by 131 | % examining the moment arm of the muscle across all coordinates in the model 132 | % and recording where the moment arm is nonzero. 133 | 134 | %% Import OpenSim libraries. 135 | import org.opensim.modeling.* 136 | 137 | % Get a reference to the concrete muscle class. 138 | force = model.getMuscles().get(muscleName); 139 | muscleClass = char(force.getConcreteClassName()); 140 | eval(['muscle = ' muscleClass '.safeDownCast(force);']); 141 | 142 | % Initialize. 143 | nCoord = model.getCoordinateSet().getSize(); 144 | muscCoord = []; % For storing coordinate values. 145 | 146 | % Iterate through coordinates, finding nonzero moment arms. 147 | for k = 0 : nCoord - 1 148 | % Get a reference to a coordinate. 149 | aCoord = model.getCoordinateSet().get(k); 150 | % Get coordinate's max and min values. 151 | rMax = aCoord.getRangeMax(); 152 | rMin = aCoord.getRangeMin(); 153 | rDefault = aCoord.getDefaultValue(); 154 | % Define three points in the range to test the moment arm. 155 | totalRange = rMax - rMin; 156 | p(1) = rMin + totalRange/2; 157 | p(2) = rMin + totalRange/3; 158 | p(3) = rMin + 2*(totalRange/3); 159 | 160 | for i = 1 : 3 161 | aCoord.setValue(state, p(i)); 162 | 163 | % Compute the moment arm of the muscle for this coordinate. 164 | momentArm = muscle.computeMomentArm(state, aCoord); 165 | 166 | % Avoid false positives due to roundoff error. 167 | tol = 1e-6; 168 | if ( abs(momentArm) > tol ) 169 | muscCoord = [muscCoord; k]; 170 | break; 171 | end 172 | end 173 | 174 | % Set the coordinate back to its default value. 175 | aCoord.setValue(state, rDefault); 176 | end 177 | 178 | % Initialize the structure that will be returned. 179 | muscle = struct(); 180 | muscle.name = muscleName; 181 | 182 | % Cycle through each coordinate found above and save its range of values. These 183 | % will get used later to calculate muscle forces. 184 | for u = 1 : length(muscCoord) 185 | % Get a reference to the coordinate. 186 | aCoord = model.getCoordinateSet().get(muscCoord(u)); 187 | % Create an array of radian values for the range. 188 | coordRange = (aCoord.getRangeMin() : 0.01 : aCoord.getRangeMax())'; 189 | % Store the coordinate and its range of values in the structure. 190 | eval(['muscle.coordinates.', ... 191 | char(model.getCoordinateSet().get(muscCoord(u))), ' = [coordRange];']); 192 | end 193 | 194 | end %function getMuscleCoordinates 195 | 196 | %% 197 | function [fl_active, fl_passive] = getForceLength(model, s, muscle) 198 | % Force Length Finder 199 | % Function gets the active and passive force--length values for muscle. 200 | % Input is a Model(), State(), and a structure of muscle names 201 | % ie muscle. = 'TibAnt'; 202 | % Returns arrays of the muslce normalized active and passive force-length. 203 | 204 | %% Import OpenSim libraries. 205 | import org.opensim.modeling.* 206 | 207 | %% Get the number of coordinates for the muscle. 208 | coordNames = fieldnames(muscle.coordinates); 209 | nCoords = length( coordNames ); 210 | 211 | %% Get a reference to the concrete muscle class. 212 | force = model.getMuscles().get(muscle.name); 213 | muscleClass = char(force.getConcreteClassName()); 214 | eval(['myMuscle = ' muscleClass '.safeDownCast(force);']); 215 | 216 | %% Initilize a matrix for storing the complete force--length curve. 217 | flMatrix = zeros(1,3); 218 | 219 | for k = 1 : nCoords 220 | 221 | % Get the name and range of the coordinate. 222 | updCoord = model.updCoordinateSet().get( char(coordNames(k)) ); 223 | coordRange = muscle.coordinates.(coordNames{k}); 224 | storageData = zeros( length(coordRange), 5 ); 225 | 226 | % Loop through each value of the coordinate and compute the fiber length and 227 | % force of the muscle. 228 | for j = 1 : length( coordRange ) 229 | 230 | % Set the coordinate value. 231 | coordValue = coordRange(j); 232 | updCoord.setValue(s, coordValue); 233 | updCoord.setSpeedValue(s, 0); 234 | 235 | % Set the activation and fiber length 236 | myMuscle.setActivation( s, 1 ); 237 | myMuscle.setDefaultFiberLength( 0.01 ); 238 | myMuscle.setFiberLength( s, myMuscle.getOptimalFiberLength() ); 239 | 240 | % Equilibrate the muscle and tendon forces. 241 | model.equilibrateMuscles( s ); 242 | 243 | % Store all the data in the result matrix. This is ineffecient, but 244 | % demonstrates what can be stored. 245 | storageData(j,:) = [... 246 | rad2deg(coordValue) ... % Coordinate value 247 | myMuscle.getFiberLength(s) ... % Fiber length 248 | myMuscle.getNormalizedFiberLength(s) ... % Normalized fiber length 249 | myMuscle.getActiveFiberForce(s) ... % Active fiber force 250 | myMuscle.getPassiveFiberForce(s) ]; % Passive fiber force 251 | 252 | % Check for redundancy in fiber length. 253 | if isempty( find( myMuscle.getNormalizedFiberLength(s) == flMatrix(:,1), 1 ) ) 254 | flMatrix = [flMatrix ; storageData(j,3:5)]; 255 | end 256 | end 257 | 258 | % Reset the coordinate back to its default value. 259 | updCoord.setValue(s, updCoord.getDefaultValue()); 260 | end 261 | 262 | fl_active = flMatrix(:,1:2); 263 | fl_passive = flMatrix(:,[1 3]); 264 | 265 | end 266 | -------------------------------------------------------------------------------- /misc/prescribeMotionInModel.m: -------------------------------------------------------------------------------- 1 | function prescribeMotionInModel(Model_In, Mot_In, Model_Out) 2 | %% Function to take an existing model file and coordinate data accessed 3 | % from an IK solution and write it as a Natural Cubic Spline Function to 4 | % the Prescribed Function method of a Coordinate to a model file. 5 | % 6 | % Inputs - Model_In - Existing model stored in osim file 7 | % - Mot_In - A file contains motion data for the particular model 8 | % - Model_Out - The output file with prescribed motion 9 | % 10 | % e.g. prescribedMotionInModel('myInputModel.osim','myMotionFile', 'myOutputModel.osim') 11 | 12 | % Author - Dominic Farris 13 | % ----------------------------------------------------------------------- % 14 | % The OpenSim API is a toolkit for musculoskeletal modeling and % 15 | % simulation. See http://opensim.stanford.edu and the NOTICE file % 16 | % for more information. OpenSim is developed at Stanford University % 17 | % and supported by the US National Institutes of Health (U54 GM072970, % 18 | % R24 HD065690) and by DARPA through the Warrior Web program. % 19 | % % 20 | % Copyright (c) 2005-2017 Stanford University and the Authors % 21 | % Author(s): Dominic Farris % 22 | % % 23 | % Licensed under the Apache License, Version 2.0 (the "License"); % 24 | % you may not use this file except in compliance with the License. % 25 | % You may obtain a copy of the License at % 26 | % http://www.apache.org/licenses/LICENSE-2.0. % 27 | % % 28 | % Unless required by applicable law or agreed to in writing, software % 29 | % distributed under the License is distributed on an "AS IS" BASIS, % 30 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or % 31 | % implied. See the License for the specific language governing % 32 | % permissions and limitations under the License. % 33 | % ----------------------------------------------------------------------- % 34 | 35 | %% import java libraries 36 | import org.opensim.modeling.* 37 | 38 | %% Argument checking 39 | error(nargchk(0, 3, nargin)); 40 | 41 | % If there aren't enough arguments passed in system will ask user to 42 | % manually select file(s) 43 | if nargin < 1 44 | [Model_In, modelpath] = uigetfile('.osim', 'Please select a model file'); 45 | [Mot_In, motpath] = uigetfile('.mot', 'Please select a motion file'); 46 | fileoutpath = [Model_In(1:end-5),'_Prescribed.osim']; 47 | modelfilepath = [modelpath Model_In]; 48 | motfilepath = [motpath Mot_In]; 49 | elseif nargin < 2 50 | [Mot_In, motpath] = uigetfile('.mot', 'Please select a motion file'); 51 | fileoutpath = [Model_In(1:end-5),'_Prescribed.osim']; 52 | motfilepath = [motpath Mot_In]; 53 | modelfilepath = Model_In; 54 | elseif nargin < 3 55 | fileoutpath = [Model_In(1:end-5),'_Prescribed.osim']; 56 | modelfilepath = Model_In; 57 | motfilepath = Mot_In; 58 | else 59 | modelfilepath = Model_In; 60 | motfilepath = Mot_In; 61 | fileoutpath = Model_Out; 62 | end 63 | 64 | % Initialize model 65 | osimModel = Model(modelfilepath); 66 | 67 | % Create the coordinate storage object from the input .sto file 68 | coordinateSto = Storage(motfilepath); 69 | 70 | % Rename the modified Model 71 | osimModel.setName('modelWithPrescribedMotion'); 72 | 73 | % get coordinate set from model, and count the number of coordinates 74 | modelCoordSet = osimModel.getCoordinateSet(); 75 | nCoords = modelCoordSet.getSize(); 76 | 77 | % for all coordinates in the model, create a function and prescribe 78 | for i=0:nCoords-1 79 | 80 | % construct ArrayDouble objects for time and coordinate values 81 | Time=ArrayDouble(); 82 | coordvalue = ArrayDouble(); 83 | 84 | % Get the coordinate set from the model 85 | currentcoord = modelCoordSet.get(i); 86 | 87 | % Get the Time stamps and Coordinate values 88 | coordinateSto.getTimeColumn(Time); 89 | coordinateSto.getDataColumn(currentcoord.getName(),coordvalue); 90 | 91 | % Check if it is a rotational or translational coordinate 92 | motion = currentcoord.getMotionType(); 93 | 94 | % construct a SimmSpline object (previously NaturalCubicSpline) 95 | Spline = SimmSpline(); 96 | 97 | %Now to write Time and coordvalue to Spline 98 | if strcmp(motion,'Rotational') 99 | % if the motion type is rotational we must convert to radians from degrees 100 | for j = 0:coordvalue.getSize()-1 101 | Spline.addPoint(Time.getitem(j),coordvalue.getitem(j)/(180/pi)); 102 | end 103 | else % else we assume it's translational and can be left 'as is' 104 | for j = 0:coordvalue.getSize()-1 105 | Spline.addPoint(Time.getitem(j),coordvalue.getitem(j)); 106 | end 107 | end 108 | 109 | % Add the SimmSpline to the PrescribedFunction of the Coordinate 110 | % being edited 111 | currentcoord.setPrescribedFunction(Spline); 112 | currentcoord.setDefaultIsPrescribed(1); 113 | end 114 | 115 | % Save the Modified Model to a file 116 | osimModel.print(fileoutpath); 117 | disp(['The new model has been saved at ' fileoutpath]); 118 | -------------------------------------------------------------------------------- /misc/set_coordinate_from_states.m: -------------------------------------------------------------------------------- 1 | %% Clear all variables from the workspace 2 | clear all; close all; clc; format long; 3 | import org.opensim.modeling.* 4 | 5 | 6 | model = Model('Copy_of_Walker_Model.osim'); 7 | state = model.initSystem(); 8 | 9 | %% 10 | sto = STOFileAdapter().readFile('fwd_results.sto'); 11 | time = 1.257; 12 | row = sto.getNearestRowIndexForTime(time); 13 | %% 14 | clabels = sto.getColumnLabels(); 15 | 16 | for i = 0 : model.getCoordinateSet().getSize() - 1 17 | cname = model.getCoordinateSet().get(i).getName(); 18 | for u = 0 : clabels.size - 1 19 | if contains(char(clabels.get(u)),char(cname)) 20 | if contains(char(clabels.get(u)),'value') 21 | if contains(char(model.getCoordinateSet().get(i).getMotionType()),'Rotational') 22 | model.getCoordinateSet().get(i).set_default_value(deg2rad(sto.getDependentColumnAtIndex(u).get(row))); 23 | else 24 | model.getCoordinateSet().get(i).set_default_value(sto.getDependentColumnAtIndex(u).get(row)) 25 | end 26 | elseif contains(char(clabels.get(u)),'speed') 27 | if contains(char(model.getCoordinateSet().get(i).getMotionType()),'Rotational') 28 | model.getCoordinateSet().get(i).set_default_speed_value(deg2rad(sto.getDependentColumnAtIndex(u).get(row))) 29 | else 30 | model.getCoordinateSet().get(i).set_default_speed_value(sto.getDependentColumnAtIndex(u).get(row)) 31 | end 32 | end 33 | end 34 | end 35 | end 36 | 37 | model.print('Copy_of_Walker_Model_posed.osim') -------------------------------------------------------------------------------- /misc/set_coordinates_add_noise.m: -------------------------------------------------------------------------------- 1 | clear all; close all; clc; format long; 2 | import org.opensim.modeling.* 3 | 4 | model = Model('Copy_of_Walker_Model_posed.osim'); 5 | state = model.initSystem(); 6 | 7 | %% 8 | 9 | for i = 0 : model.getCoordinateSet().getSize() - 1 10 | coordinate = model.getCoordinateSet().get(i); 11 | if contains(char(coordinate.getName()), 'Pelvis') 12 | continue 13 | end 14 | 15 | new_value = coordinate.getDefaultValue() + (0.2*rand-0.2); 16 | new_Speed = coordinate.getDefaultSpeedValue + (0.2*rand-0.2); 17 | 18 | coordinate.set_default_value(new_value); 19 | coordinate.set_default_speed_value(new_Speed) 20 | end 21 | 22 | model.print('Copy_of_Walker_Model_posed_noise.osim') -------------------------------------------------------------------------------- /misc/set_coordinates_random_values.m: -------------------------------------------------------------------------------- 1 | clear all; close all; clc; format long; 2 | import org.opensim.modeling.* 3 | 4 | 5 | model = Model('Copy_of_Walker_Model.osim'); 6 | state = model.initSystem(); 7 | 8 | %% 9 | sto = STOFileAdapter().readFile('fwd_results.sto'); 10 | time = 1.257; 11 | row = sto.getNearestRowIndexForTime(time); 12 | %% 13 | clabels = sto.getColumnLabels(); 14 | 15 | for i = 0 : model.getCoordinateSet().getSize() - 1 16 | cname = model.getCoordinateSet().get(i).getName(); 17 | for u = 0 : clabels.size - 1 18 | if contains(char(clabels.get(u)),char(cname)) 19 | if contains(char(clabels.get(u)),'value') 20 | if contains(char(model.getCoordinateSet().get(i).getMotionType()),'Rotational') 21 | model.getCoordinateSet().get(i).set_default_value(deg2rad(sto.getDependentColumnAtIndex(u).get(row))); 22 | else 23 | model.getCoordinateSet().get(i).set_default_value(sto.getDependentColumnAtIndex(u).get(row)) 24 | end 25 | elseif contains(char(clabels.get(u)),'speed') 26 | if contains(char(model.getCoordinateSet().get(i).getMotionType()),'Rotational') 27 | model.getCoordinateSet().get(i).set_default_speed_value(deg2rad(sto.getDependentColumnAtIndex(u).get(row))) 28 | else 29 | model.getCoordinateSet().get(i).set_default_speed_value(sto.getDependentColumnAtIndex(u).get(row)) 30 | end 31 | end 32 | end 33 | end 34 | end 35 | 36 | model.print('Copy_of_Walker_Model_posed.osim') -------------------------------------------------------------------------------- /misc/writeMOT.m: -------------------------------------------------------------------------------- 1 | classdef writeMOT < matlab.mixin.SetGet 2 | properties 3 | table 4 | filename 5 | directory 6 | end 7 | methods 8 | function obj = writeMOT(osimtable) 9 | 10 | import org.opensim.modeling.* 11 | 12 | if isempty(strfind(osimtable.getClass, 'TimeSeriesTable')) 13 | disp('Input is not an OpenSim Times Series Table') 14 | end 15 | 16 | if ~isempty(strfind(osimtable.getClass, 'Vec3')) 17 | postfix = StdVectorString(); 18 | postfix.add('_x'); 19 | postfix.add('_y'); 20 | postfix.add('_z'); 21 | osimtable = osimtable.flatten(postfix); 22 | disp('TimesSeriesVec3 converted to TimesSeriesTable') 23 | end 24 | 25 | obj.table = osimtable; 26 | 27 | 28 | 29 | end 30 | 31 | function setFileName(obj,filename) 32 | obj.filename = filename; 33 | end 34 | 35 | function setFileDirectory(obj, directory) 36 | obj.directory = directory; 37 | end 38 | 39 | function write(obj) 40 | if isempty(obj.filename) 41 | error('filename property has not been set') 42 | end 43 | if isempty(obj.directory) 44 | error('directory property has not been set') 45 | end 46 | 47 | import org.opensim.modeling.* 48 | 49 | fullpath = fullfile(obj.directory,[obj.filename '.mot']); 50 | 51 | STOFileAdapter().write(obj.table,fullpath); 52 | display([[obj.filename '.mot'] ' written to dir: ' fullpath]); 53 | end 54 | % function convertToMeters(obj, 55 | % 56 | % 57 | % end 58 | 59 | end 60 | methods (Access = private, Hidden = true) 61 | 62 | 63 | end 64 | end 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /mocapDataConversion/convertC3D_to_osim.m: -------------------------------------------------------------------------------- 1 | function C3D2Opensim() 2 | %% Convert a selected C3D file(s) to TRC and MOT format. 3 | 4 | %% Get the full path to the C3d file 5 | % Open a dialog to select the c3d file 6 | [filenames, path] = uigetfile('.c3d', 'Pick C3D File', 'Multiselect', 'on'); 7 | 8 | %% Determine the number of selected files 9 | if iscell(filenames) 10 | nFiles = length(filenames); 11 | else 12 | nFiles = 1; 13 | end 14 | 15 | %% Convert each file. 16 | for i = 1 : nFiles 17 | % Determine full path name 18 | if iscell(filenames) 19 | fullpath = fullfile(path, filenames{i}); 20 | [p filename] = fileparts(fullpath); 21 | else 22 | fullpath = fullfile(path, filenames); 23 | filename = filenames; 24 | end 25 | % Instantiate a osimC3D object 26 | c3d = osimC3D(fullpath,1); 27 | % Rotate the c3d data (slow) 28 | c3d.rotateData('x', -90); 29 | % Write the Mot and TRC to file 30 | c3d.writeTRC(); c3d.writeMOT(); 31 | % Display result 32 | disp(['TRC and MOT file for ' filename ' successfully writen']) 33 | end 34 | 35 | end -------------------------------------------------------------------------------- /mocapDataConversion/read_trcFile.m: -------------------------------------------------------------------------------- 1 | function q = matlab_trcRead(fname) 2 | % read_trcFile() uses Matlab methods ONLY 3 | % Reads data from a trc file. Does not require OpenSim Libraries 4 | 5 | fin = fopen(fname, 'r'); 6 | if fin == -1 7 | error(['unable to open ', fname]) 8 | end 9 | 10 | nextline = fgetl(fin); 11 | trcversion = sscanf(nextline, 'PathFileType %d'); 12 | if trcversion ~= 4 13 | disp('trc PathFileType is not 4, aborting'); 14 | return; 15 | end 16 | 17 | nextline = fgetl(fin); 18 | 19 | nextline = fgetl(fin); 20 | values = sscanf(nextline, '%f %f %f %f'); 21 | numframes = values(3); 22 | q.nummarkers = values(4); 23 | numcolumns=3*q.nummarkers+2; 24 | 25 | nextline = fgetl(fin); 26 | q.labels = cell(1, numcolumns); 27 | [q.labels{1}, nextline] = strtok(nextline); % should be Frame# 28 | [q.labels{2}, nextline] = strtok(nextline); % should be Time 29 | for i = 1 : q.nummarkers 30 | [markername, nextline] = strtok(nextline); 31 | q.labels{2+i} = markername; 32 | end 33 | 34 | nextline = fgetl(fin); 35 | if isspace(nextline(1)) 36 | while true 37 | nextline = fgetl(fin); 38 | if ~isspace(nextline(1)) 39 | break 40 | end 41 | end 42 | end 43 | 44 | columns_in_table = length(sscanf(nextline, '%f')); 45 | markers_in_table = (columns_in_table - 2) /3; 46 | if markers_in_table ~= q.nummarkers 47 | warning(['Number of Marker labels in file (' num2str(q.nummarkers) ') doesnt equal number of columns of marker data (' num2str(markers_in_table) '). ']) 48 | end 49 | % Update the number of markers 50 | q.nummarkers = markers_in_table; 51 | % Put the data in an array 52 | data = zeros(numframes,columns_in_table); 53 | for i = 1 : numframes 54 | data(i,:) = sscanf(nextline, '%f')'; 55 | nextline = fgetl(fin); 56 | end 57 | q.time = data(:,2); 58 | q.data = data(:,3:end); 59 | q.labels = q.labels(3:end); 60 | q.datarate = 1/(q.time(2) - q.time(1)); 61 | end -------------------------------------------------------------------------------- /modelEditing/simplyfy_model_and_data.m: -------------------------------------------------------------------------------- 1 | cd('/Users/jimmy/repository/optimalModelFitting/010 - Scaling_gait_model') 2 | 3 | import org.opensim.modeling.* 4 | 5 | model = Model('gait2392_simbody.osim'); 6 | 7 | %% Remove all muscles 8 | ms = model.getForceSet(); 9 | 10 | while ms.getSize() > 0 11 | ms.remove(ms.get(0)); 12 | end 13 | 14 | %% Remove the bodies 15 | bodyList = {}; 16 | bs = model.getBodySet(); 17 | for i = 0 : model.getBodySet().getSize() - 1 18 | bodyList = [bodyList; {char(model.getBodySet().get(i))}] 19 | end 20 | deleteBodies = [{'torso'} {'femur_l'} {'tibia_l'} {'talus_l'} {'calcn_l'} {'toes_l'}]; 21 | 22 | for i = 1 : length(deleteBodies) 23 | bs.remove(bs.get(deleteBodies{i})); 24 | end 25 | 26 | bodyList = {}; 27 | bs = model.getBodySet(); 28 | for i = 0 : model.getBodySet().getSize() - 1 29 | bodyList = [bodyList; {char(model.getBodySet().get(i))}]; 30 | end 31 | %% Remove joints 32 | jointList = {}; 33 | js = model.getJointSet(); 34 | for i = 0 : model.getJointSet().getSize() - 1 35 | jointList = [jointList; {char(model.getJointSet().get(i))}]; 36 | end 37 | deleteJoints = [{'hip_l'} {'knee_l'} {'ankle_l'} {'subtalar_l'} {'mtp_l'} {'back'}]; 38 | 39 | for i = 1 : length(deleteJoints) 40 | js.remove(js.get(deleteJoints{i})); 41 | end 42 | 43 | %% Remove markers 44 | MarkerList = {}; 45 | ms = model.getMarkerSet(); 46 | for i = 0 : model.getMarkerSet().getSize() - 1 47 | MarkerList = [MarkerList; {char(model.getMarkerSet().get(i))}]; 48 | end 49 | 50 | ms_b = ms.clone(); 51 | ms = ms_b.clone; 52 | 53 | MarkerList = {}; 54 | ms = model.getMarkerSet(); 55 | for i = 0 : model.getMarkerSet().getSize() - 1 56 | parentBodyName = strrep(char(ms.get(i).getParentFrameName), '/bodyset/',''); 57 | if sum(contains(bodyList, parentBodyName)) ~= 1 58 | MarkerList = [MarkerList; {char(ms.get(i))} ]; 59 | end 60 | end 61 | 62 | for i = 1 : length(MarkerList) 63 | ms.remove(ms.get(MarkerList{i})); 64 | end 65 | 66 | %% 67 | s = model.initSystem(); 68 | 69 | model.print('single_leg.osim') 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /solvers/solverIK.m: -------------------------------------------------------------------------------- 1 | function [locations, errors, angles,anglesPacked] = solverIK(model, trcpath, markerList, weights) 2 | %% solverIK is a Matlab interface to the OpenSim IKSolver(). 3 | % Inputs are an OpenSim Model, path to a trc file, list of markers to be 4 | % tracked, and an array of weights corresponding with each marker. 5 | % 6 | % Outputs are the locations of the model markers, the errors between the 7 | % model and experimental markers, a coordinate value array (without labels), 8 | % and a struct of coordinate values (allocated labels). 9 | % 10 | 11 | % use the IK solver and report back the individual marker errors. 12 | import org.opensim.modeling.* 13 | % Initialize OpenSim model 14 | s = model.initSystem(); 15 | nM = length(markerList); 16 | %% get lists of the marker and coordinate names 17 | % markerNames = []; 18 | % for i = 0 : model.getMarkerSet().getSize()-1; 19 | % markerNames = [markerNames {char(model.getMarkerSet().get(i).getName() )}]; 20 | % end 21 | % 22 | % trcNames = []; 23 | % for i = 0 : t.getNumColumns() - 1 24 | % trcNames = [trcNames {char(t.getColumnLabels().get(i))}]; 25 | % end 26 | % Generate a final list of Markers to track 27 | % markerList = intersect(markerNames,trcNames); 28 | 29 | coordName = []; 30 | for i = 0 : model.getCoordinateSet().getSize()-1; 31 | coordName = [coordName {char(model.getCoordinateSet().get(i).getName() )}]; 32 | end 33 | 34 | %% Populate markers reference object with desired marker weights 35 | markerWeights = SetMarkerWeights(); 36 | for i = 1 : length(markerList) 37 | markerWeights.cloneAndAppend( MarkerWeight(markerList{i}, weights(i) ) ); 38 | end 39 | 40 | % Set marker weights 41 | markerref = MarkersReference(); 42 | markerref.setMarkerWeightSet(markerWeights) 43 | % Create an arry of blank coordinate reference objects 44 | coordref = SimTKArrayCoordinateReference(); 45 | 46 | % Populate coordinate references object with desired coordinate values 47 | % and weights 48 | for i = 1 : length(coordName) 49 | coordRef = CoordinateReference(coordName{i} , Constant() ); 50 | coordRef.setWeight(0); 51 | coordRef.markAdopted(); 52 | coordref.push_back(coordRef); 53 | end 54 | 55 | %% Define kinematics reporter for output 56 | % Load marker data 57 | % markerref.loadMarkersFile(trcpath) % , Units('Millimeters')); 58 | markerref.loadMarkersFile(trcpath) 59 | 60 | % Get start and end times 61 | timeRange = markerref.getValidTimeRange(); 62 | startTime = timeRange.get(0); 63 | endTime = timeRange.get(1); 64 | 65 | % Define constraint weight 66 | constweight = Inf; 67 | 68 | %% Instantiate the ikSolver and set some values. 69 | ikSolver = InverseKinematicsSolver(model,markerref, coordref,constweight); 70 | % Set ikSolver accuracy 71 | accuracy = 1e-5; 72 | ikSolver.setAccuracy(accuracy); 73 | % Assemble the model 74 | s.setTime(startTime); 75 | ikSolver.assemble(s); 76 | 77 | %% Loop through markers and define weights 78 | % for i = 0 : model.getMarkerSet().getSize() - 1 79 | % ikSolver.updateMarkerWeight(i,1); 80 | % end 81 | 82 | % Loop through IK coordinate tasks and define values and weights 83 | for i = 1 : model.getCoordinateSet().getSize() 84 | ikSolver.updateCoordinateReference(coordName{i},0); 85 | end 86 | 87 | %% Compute dt and nFrames 88 | dt = 1.0/markerref.getSamplingFrequency(); 89 | nFrames = round(( (endTime-startTime)/dt )+1); 90 | 91 | %% Perform IK analysis 92 | disp('Starting IK analysis') 93 | errors = []; 94 | angles = []; 95 | locations = []; 96 | for i = 0 : nFrames - 1 97 | % set the time 98 | s.setTime(startTime+i*dt); 99 | % run the iksolver for the time 100 | ikSolver.track(s); 101 | % Get the marker errors 102 | for u = 0 : nM - 1 103 | errors(i+1,u+1) = ikSolver.computeCurrentMarkerError(u); 104 | end 105 | % Get the Model Marker Locations 106 | for u = 0 : nM - 1 107 | location = ikSolver.computeCurrentMarkerLocation(u); 108 | locations(i+1,(u+1)*3-2:(u+1)*3) = [location.get(0) location.get(1) location.get(2)]; 109 | end 110 | % Get the Coordinates Values 111 | model.realizeVelocity(s); 112 | % Get the coordinate Set 113 | cs = model.getCoordinateSet(); 114 | nvalues = cs.getSize(); 115 | for u = 0 : nvalues - 1 116 | angles(i+1,u+1) = cs().get(u).getValue(s); 117 | end 118 | end 119 | 120 | %% Pack the angles 121 | anglesPacked = struct(); 122 | for u = 0 : nvalues - 1 123 | name = char(cs.get(u).getName()); 124 | if ~isempty(strfind(name,'tx')) || ~isempty(strfind(name,'ty')) || ~isempty(strfind(name,'tz')) 125 | eval(['anglesPacked.' char(cs.get(u).getName()) '= angles(:,u+1);']) 126 | else 127 | % Angles are in rad. COnvert to deg 128 | eval(['anglesPacked.' char(cs.get(u).getName()) '= rad2deg(angles(:,u+1));']) 129 | end 130 | end 131 | 132 | anglesPacked.time = [startTime:dt:endTime]'; 133 | 134 | 135 | end -------------------------------------------------------------------------------- /support/TRCFileFixer.m: -------------------------------------------------------------------------------- 1 | function TRCFileFixer(trcPath) 2 | %% Fix issues with a TRC File 3 | 4 | %% Get file parts for the input TRC 5 | [FILEPATH,NAME,EXT] = fileparts(trcPath); 6 | if isempty(FILEPATH) 7 | FILEPATH = cd; 8 | end 9 | 10 | %% Read data in and format into a struct 11 | q = read_trcFile(trcPath); 12 | 13 | markers = struct(); 14 | for i = 1 : q.nummarkers 15 | markers.(q.labels{i}) = q.data(:, i*3-2:i*3); 16 | end 17 | markers.time = q.time; 18 | 19 | %% Convert the stucture to an OpenSim Table 20 | % import opensim libraries 21 | import org.opensim.modeling.* 22 | 23 | % Display a message saying that this may take awhile 24 | display('If your trc file is large, this may take awhile :('); 25 | 26 | % Convert using function found in opensim code/Matlab/utilities folder 27 | mTable = osimTableFromStruct(markers); 28 | % Add Necessary MetaData 29 | mTable.addTableMetaDataString('DataRate', num2str(q.datarate)); 30 | mTable.addTableMetaDataString('Units', 'mm'); 31 | 32 | %% Write to file using the TRCFileAdapter 33 | outputPath = fullfile(FILEPATH, strrep(trcPath, '.trc', '_fixed.trc')); 34 | TRCFileAdapter().write( mTable, outputPath) 35 | display(['TRC File Written to ' outputPath ]); 36 | end 37 | 38 | function q = read_trcFile(fname) 39 | 40 | fin = fopen(fname, 'r'); 41 | if fin == -1 42 | error(['unable to open ', fname]) 43 | end 44 | 45 | nextline = fgetl(fin); 46 | trcversion = sscanf(nextline, 'PathFileType %d'); 47 | if trcversion ~= 4 48 | disp('trc PathFileType is not 4, aborting'); 49 | return; 50 | end 51 | 52 | nextline = fgetl(fin); 53 | 54 | nextline = fgetl(fin); 55 | values = sscanf(nextline, '%f %f %f %f'); 56 | numframes = values(3); 57 | q.nummarkers = values(4); 58 | numcolumns=3*q.nummarkers+2; 59 | 60 | nextline = fgetl(fin); 61 | q.labels = cell(1, numcolumns); 62 | [q.labels{1}, nextline] = strtok(nextline); % should be Frame# 63 | [q.labels{2}, nextline] = strtok(nextline); % should be Time 64 | for i = 1 : q.nummarkers 65 | [markername, nextline] = strtok(nextline); 66 | q.labels{2+i} = markername; 67 | end 68 | 69 | nextline = fgetl(fin); 70 | if isspace(nextline(1)) 71 | while true 72 | nextline = fgetl(fin); 73 | if ~isspace(nextline(1)) 74 | break 75 | end 76 | end 77 | end 78 | 79 | columns_in_table = length(sscanf(nextline, '%f')); 80 | markers_in_table = (columns_in_table - 2) /3; 81 | if markers_in_table ~= q.nummarkers 82 | warning(['Number of Marker labels in file (' num2str(q.nummarkers) ') doesnt equal number of columns of marker data (' num2str(markers_in_table) '). ']) 83 | end 84 | % Update the number of markers 85 | q.nummarkers = markers_in_table; 86 | % Put the data in an array 87 | data = zeros(numframes,columns_in_table); 88 | for i = 1 : numframes 89 | data(i,:) = sscanf(nextline, '%f')'; 90 | nextline = fgetl(fin); 91 | end 92 | q.time = data(:,2); 93 | q.data = data(:,3:end); 94 | q.labels = q.labels(3:end); 95 | q.datarate = 1/(q.time(2) - q.time(1)); 96 | end -------------------------------------------------------------------------------- /tests/testC3Dconverter.m: -------------------------------------------------------------------------------- 1 | % 2 | % Author: James Dunne 3 | 4 | 5 | 6 | 7 | 8 | 9 | tic 10 | %% Load libraries 11 | import org.opensim.modeling.* 12 | 13 | %% get path to file 14 | filepath = 'walking2.c3d'; 15 | [path, file, ext] = fileparts(filepath); 16 | if isempty(exist('walking2.c3d', 'file')) 17 | error('cannot find test file (walking2.c3d) at walking2.c3d'); 18 | end 19 | 20 | %% Instantiate the file readers 21 | trc = TRCFileAdapter(); 22 | sto = STOFileAdapter(); 23 | 24 | %% Test script for utility function 25 | osimC3Dconverter('filepath', filepath); 26 | 27 | %% Test if trc and mot file were printed. 28 | assert( exist(fullfile(path,[file '.trc']), 'file') == 2, 'TRC was not printed ') 29 | assert( exist(fullfile(path,[file '.mot']), 'file') == 2, 'TRC was not printed ') 30 | 31 | %% Test rotations 32 | % test if rotations about X, Y, and Z maintain the correct 33 | % components. ie if rotatiing about X, X values remain the same. 34 | 35 | %% Get the unrotated reference values 36 | mkr = trc.read(fullfile(path,[file '.trc'])); 37 | ana = sto.read(fullfile(path,[file '.mot'])); 38 | 39 | mkr_Xvalue_ref = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(0); 40 | mkr_Yvalue_ref = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(1); 41 | mkr_Zvalue_ref = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(2); 42 | 43 | ana_Xvalue_ref = ana.getDependentColumnAtIndex(0).getElt(238,0); 44 | ana_Yvalue_ref = ana.getDependentColumnAtIndex(1).getElt(238,0); 45 | ana_Zvalue_ref = ana.getDependentColumnAtIndex(2).getElt(238,0); 46 | 47 | %% Rotate about X 48 | osimC3Dconverter('filepath', filepath, 'value', -90, 'axis', 'x'); 49 | mkr = trc.read(fullfile(path,[file '.trc'])); 50 | ana = sto.read(fullfile(path,[file '.mot'])); 51 | 52 | % Set the new marker and force values 53 | mkr_Xvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(0); 54 | mkr_Yvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(1); 55 | mkr_Zvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(2); 56 | ana_Xvalue = ana.getDependentColumnAtIndex(0).getElt(238,0); 57 | ana_Yvalue = ana.getDependentColumnAtIndex(1).getElt(238,0); 58 | ana_Zvalue = ana.getDependentColumnAtIndex(2).getElt(238,0); 59 | % Assess if the rotation is correct 60 | assert(mkr_Xvalue_ref == mkr_Xvalue, 'X axis marker rotation is incorrect ') 61 | assert(mkr_Yvalue_ref ~= mkr_Yvalue, 'Y axis marker rotation is incorrect ') 62 | assert(mkr_Zvalue_ref ~= mkr_Zvalue, 'Z axis marker rotation is incorrect ') 63 | assert(abs(round(mkr_Zvalue_ref)) == abs(round(mkr_Yvalue)), 'Y axis marker rotation is incorrect') 64 | assert(abs(round(mkr_Yvalue_ref)) == abs(round(mkr_Zvalue)), 'Z axis marker rotation is incorrect') 65 | assert(ana_Xvalue_ref == ana_Xvalue, 'X axis force rotation is incorrect ') 66 | assert(ana_Yvalue_ref ~= ana_Yvalue, 'Y axis force rotation is incorrect ') 67 | assert(ana_Zvalue_ref ~= ana_Zvalue, 'Z axis force rotation is incorrect ') 68 | assert(abs(round(ana_Zvalue_ref)) == abs(round(ana_Yvalue)), 'Y axis force rotation is incorrect') 69 | assert(abs(round(ana_Yvalue_ref)) == abs(round(ana_Zvalue)), 'Z axis force rotation is incorrect') 70 | 71 | %% Rotate about Y 72 | osimC3Dconverter('filepath', filepath, 'value', -90, 'axis', 'y'); 73 | mkr = trc.read(fullfile(path,[file '.trc'])); 74 | ana = sto().read(fullfile(path,[file '.mot'])); 75 | % Set the new marker and force values 76 | mkr_Xvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(0); 77 | mkr_Yvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(1); 78 | mkr_Zvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(2); 79 | ana_Xvalue = ana.getDependentColumnAtIndex(0).getElt(238,0); 80 | ana_Yvalue = ana.getDependentColumnAtIndex(1).getElt(238,0); 81 | ana_Zvalue = ana.getDependentColumnAtIndex(2).getElt(238,0); 82 | % Assess if the rotation is correct 83 | assert(mkr_Yvalue_ref == mkr_Yvalue, 'Y axis marker rotation is incorrect ') 84 | assert(mkr_Xvalue_ref ~= mkr_Xvalue, 'X axis marker rotation is incorrect ') 85 | assert(mkr_Zvalue_ref ~= mkr_Zvalue, 'Z axis marker rotation is incorrect ') 86 | assert(abs(round(mkr_Zvalue_ref)) == abs(round(mkr_Xvalue)), 'X axis marker rotation is incorrect') 87 | assert(abs(round(mkr_Xvalue_ref)) == abs(round(mkr_Zvalue)), 'Z axis marker rotation is incorrect') 88 | assert(ana_Yvalue_ref == ana_Yvalue, 'Y axis force rotation is incorrect ') 89 | assert(ana_Xvalue_ref ~= ana_Xvalue, 'X axis force rotation is incorrect ') 90 | assert(ana_Zvalue_ref ~= ana_Zvalue, 'Z axis force rotation is incorrect ') 91 | assert(abs(round(ana_Zvalue_ref)) == abs(round(ana_Xvalue)), 'X axis force rotation is incorrect') 92 | assert(abs(round(ana_Xvalue_ref)) == abs(round(ana_Zvalue)), 'Z axis force rotation is incorrect') 93 | 94 | %% Rotate about Z 95 | osimC3Dconverter('filepath', filepath, 'value', -90, 'axis', 'z'); 96 | mkr = trc.read(fullfile(path,[file '.trc'])); 97 | ana = sto().read(fullfile(path,[file '.mot'])); 98 | % Set the new marker and force values 99 | mkr_Xvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(0); 100 | mkr_Yvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(1); 101 | mkr_Zvalue = mkr.getDependentColumnAtIndex(0).getElt(238,0).get(2); 102 | ana_Xvalue = ana.getDependentColumnAtIndex(0).getElt(238,0); 103 | ana_Yvalue = ana.getDependentColumnAtIndex(1).getElt(238,0); 104 | ana_Zvalue = ana.getDependentColumnAtIndex(2).getElt(238,0); 105 | % Assess if the rotation is correct 106 | assert(mkr_Zvalue_ref == mkr_Zvalue, 'Z axis marker rotation is incorrect ') 107 | assert(mkr_Yvalue_ref ~= mkr_Yvalue, 'Y axis marker rotation is incorrect ') 108 | assert(mkr_Xvalue_ref ~= mkr_Xvalue, 'X axis marker rotation is incorrect ') 109 | assert(abs(round(mkr_Xvalue_ref)) == abs(round(mkr_Yvalue)), 'Y axis marker rotation is incorrect') 110 | assert(abs(round(mkr_Yvalue_ref)) == abs(round(mkr_Xvalue)), 'X axis marker rotation is incorrect') 111 | assert(ana_Zvalue_ref == ana_Zvalue, 'Z axis force rotation is incorrect ') 112 | assert(ana_Yvalue_ref ~= ana_Yvalue, 'Y axis force rotation is incorrect ') 113 | assert(ana_Xvalue_ref ~= ana_Xvalue, 'X axis force rotation is incorrect ') 114 | assert(abs(round(ana_Xvalue_ref)) == abs(round(ana_Yvalue)), 'Y axis force rotation is incorrect') 115 | assert(abs(round(ana_Yvalue_ref)) == abs(round(ana_Xvalue)), 'X axis force rotation is incorrect') 116 | 117 | %% clean up files 118 | delete(fullfile(path,[file '.trc'])); 119 | delete(fullfile(path,[file '.mot'])); 120 | toc -------------------------------------------------------------------------------- /tests/test_data/gait10dof18musc_ik_CRLF_line_ending.mot: -------------------------------------------------------------------------------- 1 | Coordinates 2 | version=1 3 | nRows=15 4 | nColumns=11 5 | inDegrees=yes 6 | 7 | Units are S.I. units (second, meters, Newtons, ...) 8 | Angles are in degrees. 9 | 10 | endheader 11 | time pelvis_tilt pelvis_tx pelvis_ty hip_flexion_r knee_angle_r ankle_angle_r hip_flexion_l knee_angle_l ankle_angle_l lumbar_extension 12 | 0.00000000 10.32995988 0.61213494 1.01790250 -29.10815989 -5.12860733 12.81530059 11.53587638 -0.62251583 -4.61417904 -26.13945065 13 | 0.01666667 10.07837430 0.61303298 1.01659780 -29.10828057 -6.95176330 12.82380037 12.22232385 -2.96171734 -5.65381238 -25.87606155 14 | 0.03333333 9.78090558 0.61456262 1.01551839 -28.98988200 -8.88661482 12.52241192 12.77083247 -5.23610151 -6.55319866 -25.45129547 15 | 0.05000000 9.47134096 0.61612871 1.01478810 -28.55138332 -11.40851839 12.08208254 13.37423991 -7.69512731 -7.14786344 -25.01635156 16 | 0.06666667 9.55771980 0.61844579 1.01516096 -28.34079025 -14.27068674 11.07748074 13.49818948 -10.33838510 -7.10362855 -24.89436085 17 | 0.08333333 9.47473463 0.62071925 1.01615418 -27.47430797 -17.89208038 9.77809067 13.42615397 -12.37257297 -6.91081600 -24.67909458 18 | 0.10000000 9.63837718 0.62331989 1.01778759 -26.40662175 -22.24201951 7.97355002 13.08125460 -14.62302017 -6.04532255 -24.68013609 19 | 0.11666667 9.78754006 0.62558693 1.02017897 -24.84259035 -27.15735000 5.44324025 12.37490319 -16.15459269 -5.16221752 -24.69896145 20 | 0.13333333 9.58002046 0.62704771 1.02225863 -22.22199995 -32.89992812 2.50696607 11.82019094 -17.16583386 -4.20039524 -24.39238820 21 | 0.15000000 9.28271220 0.62749723 1.02453142 -19.02080168 -38.96097466 -1.04561699 11.02117001 -17.39381306 -3.32387506 -24.03907915 22 | 0.16666667 9.03614427 0.62820629 1.02699450 -15.80758310 -44.61994450 -4.52936097 9.93351291 -17.23168474 -2.31590657 -23.70940664 23 | 0.18333333 8.56915870 0.62689554 1.02921058 -12.12924512 -50.07250438 -6.88760787 9.09789651 -16.82696406 -1.54636361 -23.31896373 24 | 0.20000000 8.22811608 0.62584770 1.03152359 -8.73182185 -54.92373007 -7.57804640 8.09381316 -16.41766828 -0.70129940 -22.92240009 25 | 0.21666667 7.82752111 0.62420254 1.03366789 -5.32356642 -59.27415163 -6.57440091 7.17726869 -15.97896869 0.03516065 -22.54013706 26 | 0.23333333 7.66380363 0.62336835 1.03638462 -2.45566140 -62.71873112 -4.70976293 5.74426081 -15.11460988 0.62270913 -22.39156625 27 | -------------------------------------------------------------------------------- /tests/test_data/gait10dof18musc_walk_CRLF_line_ending.trc: -------------------------------------------------------------------------------- 1 | PathFileType 4 (X/Y/Z) subject01_walk1.trc 2 | DataRate CameraRate NumFrames NumMarkers Units OrigDataRate OrigDataStartFrame OrigNumFrames 3 | 60.00 60.00 10 41 mm 60.00 1 10 4 | Frame# Time R.ASIS L.ASIS V.Sacral R.Thigh.Upper R.Thigh.Front R.Thigh.Rear L.Thigh.Upper L.Thigh.Front L.Thigh.Rear R.Shank.Upper R.Shank.Front R.Shank.Rear L.Shank.Upper L.Shank.Front L.Shank.Rear R.Heel R.Midfoot.Sup R.Midfoot.Lat R.Toe.Tip L.Heel L.Midfoot.Sup L.Midfoot.Lat L.Toe.Tip Sternum R.Acromium L.Acromium R.Bicep L.Bicep R.Elbow L.Elbow R.Wrist.Med R.Wrist.Lat L.Wrist.Med L.Wrist.Lat R.Toe.Lat R.Toe.Med L.Toe.Lat L.Toe.Med R.Temple L.Temple Top.Head 5 | X1 Y1 Z1 X2 Y2 Z2 X3 Y3 Z3 X4 Y4 Z4 X5 Y5 Z5 X6 Y6 Z6 X7 Y7 Z7 X8 Y8 Z8 X9 Y9 Z9 X10 Y10 Z10 X11 Y11 Z11 X12 Y12 Z12 X13 Y13 Z13 X14 Y14 Z14 X15 Y15 Z15 X16 Y16 Z16 X17 Y17 Z17 X18 Y18 Z18 X19 Y19 Z19 X20 Y20 Z20 X21 Y21 Z21 X22 Y22 Z22 X23 Y23 Z23 X24 Y24 Z24 X25 Y25 Z25 X26 Y26 Z26 X27 Y27 Z27 X28 Y28 Z28 X29 Y29 Z29 X30 Y30 Z30 X31 Y31 Z31 X32 Y32 Z32 X33 Y33 Z33 X34 Y34 Z34 X35 Y35 Z35 X36 Y36 Z36 X37 Y37 Z37 X38 Y38 Z38 X39 Y39 Z39 X40 Y40 Z40 X41 Y41 Z41 6 | 7 | 1 0.000000 617.247620 1055.275020 170.781980 639.606380 1044.258420 -88.909790 430.869840 1051.264650 29.966750 517.332700 741.096010 212.083370 570.201480 666.705570 123.685540 480.064270 626.514830 199.553850 659.578920 745.057980 -145.972180 750.480900 735.850100 -73.485050 697.429630 642.681820 -137.369600 360.903900 474.040040 186.849290 420.867430 412.366030 134.719330 343.737370 388.036680 189.831620 750.326230 446.176970 -128.527770 819.763850 415.132170 -81.700000 750.045840 397.940980 -138.884000 156.442760 113.073070 104.002570 297.180880 88.122130 67.068500 288.246640 73.766230 176.630140 429.092860 43.086100 110.597690 815.764160 63.397880 -51.758690 967.989930 122.580540 -32.770400 943.789250 105.337200 -122.344420 1078.709350 143.547960 -60.935870 660.826780 1353.775270 20.198390 566.598390 1449.579590 229.996520 596.423830 1468.968140 -186.700210 593.641480 1249.107910 279.776400 580.734680 1233.741330 -222.927320 567.002500 1143.109250 315.566310 518.102780 1146.324830 -260.958280 771.563290 973.779110 273.787600 746.206970 944.378110 327.452820 619.823060 916.169800 -218.327270 574.162540 905.877320 -276.121460 366.122960 35.908210 193.140780 375.865840 39.868800 81.171850 1022.039610 113.138240 -136.458110 1034.970460 125.078770 -34.938210 736.522340 1571.581540 106.420870 748.242000 1574.964110 -31.667230 749.332460 1747.607670 46.741460 8 | 2 0.017000 617.998110 1053.217530 168.513170 641.236210 1042.278560 -90.932130 432.340610 1050.237430 26.846790 516.613770 740.425900 211.219420 570.518920 664.198730 123.393650 479.640380 625.653080 199.315280 661.613100 743.567320 -146.438720 756.852230 736.423030 -77.160840 700.719790 641.492980 -135.753070 357.694060 474.357210 187.046230 415.392180 411.818080 134.787280 336.911320 390.057340 190.880170 755.121090 443.931430 -128.734700 820.419740 409.886230 -79.031710 750.565120 396.968080 -137.307860 141.983630 121.290870 105.037800 281.978730 91.634580 68.466230 271.807310 75.749180 177.510510 409.883610 43.139170 110.563590 799.819890 65.800630 -49.946300 957.451660 113.746440 -27.677100 943.789250 105.337200 -122.344420 1069.276610 128.480790 -56.201500 661.329160 1352.708250 17.243570 566.924800 1448.941530 226.132840 596.420230 1466.414920 -191.477110 593.204530 1248.558350 276.043640 582.396420 1230.638430 -225.945140 566.137330 1142.562130 312.590550 519.930420 1142.172850 -262.841610 767.166440 969.574220 272.552610 742.405520 941.010620 325.924410 623.054810 912.317320 -220.418560 576.285830 902.639040 -278.463500 346.245030 35.811000 193.414950 358.949890 39.805740 80.935070 1011.082150 101.083560 -132.527340 1024.002200 111.614400 -30.679700 736.041870 1570.830570 101.785740 748.411620 1574.041500 -36.665130 750.679810 1746.670410 41.164230 9 | 3 0.033000 620.292240 1051.771240 165.859380 643.596920 1041.060790 -94.307220 434.099430 1049.341430 23.819360 517.778930 739.680910 209.929780 570.455080 663.090940 123.093710 479.470610 625.036680 199.232740 663.777160 742.559390 -147.206860 760.838620 737.404660 -80.506140 702.586000 640.568480 -134.511340 355.966030 476.074310 187.729060 411.189450 410.485350 135.654970 332.246430 392.039550 191.390080 755.766360 441.964970 -126.803730 821.314880 407.066130 -76.997910 750.775880 396.232850 -136.232160 128.058360 130.381680 106.092020 267.076810 95.341160 69.879100 255.805770 78.122710 178.352940 390.767520 43.101560 110.350460 784.396790 68.058780 -48.836530 946.333250 105.409500 -23.485970 932.771240 97.336270 -120.643270 1059.063960 113.935060 -52.284060 663.198120 1351.786870 13.631070 567.569700 1448.222290 221.828410 596.462100 1463.917850 -196.019380 593.008850 1248.748410 272.547940 585.184450 1227.726070 -228.905010 564.973450 1142.939940 308.379270 523.074520 1139.112790 -266.437650 762.157470 964.989500 271.422970 735.976990 937.316220 324.738190 626.505070 909.226810 -223.191270 579.662290 899.121220 -281.073090 328.922580 34.778720 193.968580 341.756870 39.430590 80.787350 999.318420 89.325510 -129.324200 1012.506290 98.882810 -27.288000 736.570860 1570.542240 96.864830 748.854680 1571.859500 -41.940810 751.039670 1746.680180 36.059210 10 | 4 0.050000 621.540410 1050.552120 163.532500 646.751040 1040.356810 -96.861880 436.279940 1048.707150 20.952020 519.197450 739.325810 208.325210 571.931270 661.637510 123.224230 481.819180 624.230160 198.056850 666.235050 742.390320 -148.493100 763.567630 737.954160 -84.020150 703.218810 640.386410 -133.903430 356.086670 476.893160 187.230710 409.443730 410.433780 135.696300 329.610750 394.471250 191.915270 758.634460 441.582490 -127.015460 821.669010 405.638150 -75.786090 750.514220 395.895660 -136.164900 115.332880 141.108140 107.070240 252.839020 99.488570 71.288980 240.509050 81.288460 179.090060 371.835020 42.888710 109.902530 769.445980 70.037540 -48.768340 934.096920 97.975190 -20.897740 920.937990 90.006970 -119.476440 1047.431270 100.489810 -49.765160 664.717710 1351.305050 9.243790 568.009460 1448.125610 216.410840 599.003850 1461.877810 -201.063890 592.682070 1249.016110 268.268010 587.178590 1225.284180 -232.171010 562.626890 1143.382200 304.280610 526.087160 1135.987550 -268.874390 756.536870 960.192750 270.024320 729.973750 933.632810 323.821110 629.702330 906.313720 -225.578340 581.977540 895.941040 -283.059140 310.683750 34.731330 194.065190 324.278960 38.879560 80.764400 986.249820 78.367200 -127.329610 999.945920 87.508250 -25.276780 736.536250 1571.208250 92.581090 749.982240 1572.002440 -45.996900 751.068420 1747.012820 30.698870 11 | 5 0.067000 624.588440 1050.928340 161.246140 649.254150 1041.425170 -98.484610 438.827940 1048.451050 18.272670 522.168460 738.279050 206.223540 577.197880 661.205260 122.122270 485.720400 623.187560 197.993480 669.024960 743.210330 -150.405120 766.526370 737.576110 -86.548530 706.448610 641.321410 -135.479970 359.100430 478.782710 187.310710 409.768550 409.989720 136.622990 328.795900 397.801030 192.135210 764.306760 441.880950 -129.775440 819.406800 403.626710 -75.057770 749.661990 395.971590 -137.468700 104.669980 154.010060 107.811000 239.742050 104.378020 72.631480 226.079570 85.658600 179.645800 353.209260 42.461980 109.340610 754.430300 71.636760 -49.643900 920.410160 91.703790 -20.194990 907.756770 83.828000 -119.121990 1034.057620 88.697920 -48.798420 666.132510 1351.515630 4.628110 568.555970 1448.636470 211.908680 600.127260 1460.291500 -206.097440 591.977600 1249.313840 263.233830 590.491820 1223.499880 -236.037950 560.859860 1144.384640 300.735020 528.632200 1134.045040 -271.920650 750.106320 955.174440 269.175260 721.467770 930.058110 323.391390 633.410340 904.049440 -227.971250 586.006770 894.022830 -285.905460 292.770320 33.787990 194.147090 306.888700 38.662980 80.807630 971.722960 68.749270 -126.639880 985.938290 77.908320 -24.668100 737.625490 1572.048340 87.804470 750.345700 1572.990230 -51.104570 750.734190 1748.232790 25.321170 12 | 6 0.083000 628.158630 1051.420170 158.448990 652.041260 1043.046510 -101.857370 441.572050 1048.661250 15.770330 526.802800 738.126100 205.653310 584.087340 660.597960 120.847050 490.793640 622.241580 197.319820 671.815490 744.888060 -152.950500 766.966800 739.853030 -85.032910 709.177310 643.279050 -136.130540 366.042110 481.020420 188.673520 413.341310 408.717530 136.338440 330.846560 400.647670 193.439000 759.475890 442.173430 -130.737760 816.065430 402.276180 -75.444730 747.885310 396.323910 -140.116320 97.064280 169.387220 108.161000 228.389510 110.307750 73.808850 212.842180 91.667360 179.952120 335.073210 41.768600 108.900650 738.832400 72.809520 -51.153690 905.336360 86.733850 -21.041400 893.109800 79.002090 -119.562520 1019.033330 78.890880 -49.124400 667.783870 1352.009890 -0.131340 570.762570 1450.026610 206.862260 600.595580 1460.497190 -211.407200 590.940120 1250.751220 259.042850 593.760560 1223.083250 -239.714430 558.846010 1145.637450 295.842770 533.799440 1131.967160 -274.530730 742.861330 950.519170 268.833560 712.263000 929.030090 323.789580 635.945860 902.428530 -228.987780 588.334780 891.757260 -287.015930 276.405880 34.303540 194.019680 290.229950 39.311170 80.831730 955.870060 60.793510 -127.015210 970.424560 70.228080 -25.115320 738.612000 1573.103390 82.110920 751.778260 1575.626830 -55.814700 751.360840 1749.582520 19.812450 13 | 7 0.100000 630.807740 1051.996830 155.282730 654.943360 1045.552490 -104.842580 444.306520 1049.387570 13.387430 535.103210 738.089840 203.626390 592.515010 659.992430 121.333150 501.206850 620.826050 196.245770 673.898440 747.017880 -156.034230 772.351750 742.257870 -89.250050 713.161070 646.654970 -139.520660 375.777950 482.223360 189.335010 419.001340 407.600280 138.397250 336.908840 403.774540 193.350800 756.084410 442.234310 -133.993790 810.973330 400.244540 -77.594500 744.599180 396.737300 -143.634430 93.536490 187.300230 107.966110 219.475040 117.488010 74.716320 201.419720 99.718580 179.930130 317.679440 40.652490 108.828650 722.454530 73.577770 -52.950340 889.225160 83.068370 -22.647180 877.139040 75.461080 -120.586680 1002.748660 71.092540 -50.288770 669.505800 1354.105470 -5.019890 572.244510 1451.800050 201.812730 602.060420 1461.080440 -216.387600 590.792050 1252.994750 254.131150 595.745790 1222.859250 -242.970700 557.370360 1148.675900 291.073180 537.132020 1131.831670 -277.639040 734.742610 946.598510 269.146120 702.835140 926.271730 323.484040 640.106930 901.144350 -232.701070 588.760130 890.197570 -287.251620 260.437350 35.309230 193.346420 274.952850 41.205250 80.875720 939.072270 54.592980 -128.034910 953.660710 64.369800 -26.148970 739.540100 1575.362920 78.139550 752.881040 1577.243410 -60.551320 751.645260 1751.115720 15.086650 14 | 8 0.117000 634.357300 1053.598880 151.485310 656.464110 1048.434810 -108.355420 446.830750 1050.622310 11.014020 544.722960 738.212100 201.644840 604.509700 661.620360 121.057740 513.229860 619.928590 196.533050 674.531680 749.128170 -159.464230 773.977050 743.049930 -93.604750 711.735840 648.349370 -143.104520 387.181120 484.598570 188.882770 428.801240 406.893100 139.403850 345.485530 408.369840 193.096530 753.821230 442.047640 -138.771990 802.932070 398.629270 -80.644920 739.241460 397.034580 -147.341260 94.988320 207.490400 107.033990 213.699080 125.969960 75.265980 192.584460 110.038060 179.484660 301.425260 38.937480 109.337910 705.337650 74.033430 -54.661310 872.379520 80.522810 -24.272180 860.032410 72.967900 -121.863200 985.631710 65.123340 -51.842970 670.833130 1356.671140 -9.292580 572.758360 1454.599610 196.928040 602.858830 1462.021850 -221.106230 590.007870 1255.537720 250.092860 601.241880 1223.485230 -246.667330 554.968990 1151.483400 286.397250 542.949340 1130.975590 -280.456940 725.075440 942.785830 269.307310 692.728700 924.337710 323.419680 643.682250 900.946780 -234.154860 590.582030 888.882930 -288.937040 243.861860 38.164410 193.589710 261.573640 44.615090 81.126850 921.759160 50.097720 -129.250520 936.063960 60.114940 -27.366380 739.606990 1577.742190 73.244360 753.179570 1579.518190 -65.440610 752.397090 1753.568850 10.225100 15 | 9 0.133000 636.586060 1055.256590 148.460540 658.681400 1051.142090 -111.495770 448.952150 1052.288210 8.533190 554.573610 738.072200 201.587720 617.510310 662.074520 121.778390 526.785580 618.589900 197.483570 673.341980 750.943180 -162.992900 771.897030 742.336430 -96.904780 709.098750 649.058530 -147.662770 402.690370 485.767640 188.444810 442.540220 406.667140 140.140630 358.568790 411.945950 193.130040 746.613040 442.079250 -142.189940 794.797850 397.891080 -83.963120 731.433720 397.145450 -150.631760 101.895610 229.252200 105.104580 211.664430 135.612900 75.403720 187.059540 122.540120 178.549590 287.033290 36.682520 110.605430 687.623410 74.293130 -55.974680 854.960570 78.810710 -25.521920 842.020690 71.285560 -123.033750 967.953860 60.735840 -53.419360 672.251400 1359.225340 -13.845720 573.248600 1458.172610 192.645900 604.147950 1463.293580 -225.733220 588.669130 1259.120730 245.033980 605.931210 1224.268800 -249.367130 551.073910 1155.105710 281.793120 548.084960 1131.099240 -281.663730 715.241520 940.146180 269.769040 680.812930 923.017400 323.196750 649.446530 900.480900 -236.199940 597.427490 890.090330 -290.828340 230.538940 44.006780 193.995500 250.701450 49.750680 81.763050 904.150270 47.125640 -130.316410 918.011470 57.208110 -28.491270 740.341190 1580.117310 68.047650 754.192020 1582.021120 -69.934880 752.819460 1756.186160 5.613640 16 | 10 0.150000 637.739260 1057.854370 144.716320 660.529910 1054.052980 -115.064610 450.499790 1054.273560 5.887690 563.958620 737.617740 199.395420 632.102970 663.874020 122.623010 543.715940 617.548400 197.328350 670.473270 752.457150 -166.391140 766.674870 741.152710 -100.993680 701.967290 649.322630 -149.936290 422.952670 488.474330 188.635860 458.140780 406.715330 140.770570 373.537320 415.870270 192.305050 736.604190 441.154300 -144.483720 783.635560 396.668980 -85.919440 720.987490 397.089900 -153.146190 113.946330 251.355760 101.898840 213.778490 146.093080 75.119860 185.430040 136.789930 177.140980 275.709320 34.465340 112.730060 669.496950 74.456830 -56.781350 837.116520 77.713630 -26.307000 823.430480 70.253580 -123.872540 949.860230 57.662050 -54.747880 673.318120 1362.276490 -16.974510 573.645750 1461.291500 188.830580 603.489070 1465.218750 -229.001020 587.182430 1262.355960 241.462140 610.590330 1225.608030 -252.145320 547.875370 1159.117310 276.408050 554.207580 1132.036870 -284.904270 704.802610 938.801820 270.118260 669.296140 922.381710 322.034120 654.290710 900.933350 -237.275090 605.250180 890.510070 -294.287570 217.735990 52.185520 193.077560 243.332900 56.695750 82.826910 886.224060 45.357070 -131.082050 899.703920 55.343910 -29.368700 740.636110 1582.931150 64.227160 754.625060 1584.873780 -74.390680 752.891780 1758.745480 1.274000 17 | -------------------------------------------------------------------------------- /tests/test_data/walking2.c3d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimmyDunne/opensim-matlab/71bc661dee27a5c62e0cba6962830dcfee21bcc0/tests/test_data/walking2.c3d -------------------------------------------------------------------------------- /tests/test_data/walking5.c3d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimmyDunne/opensim-matlab/71bc661dee27a5c62e0cba6962830dcfee21bcc0/tests/test_data/walking5.c3d -------------------------------------------------------------------------------- /tests/test_ikHelper.m: -------------------------------------------------------------------------------- 1 | %% test_ikHelper.m 2 | dataFolder = 'test_data'; 3 | model_name = 'single_leg.osim'; 4 | markerFile_name = 'subject01_walk1.trc'; 5 | 6 | %% Instantiate a helper 7 | ik = ikHelper(fullfile(dataFolder,model_name),fullfile(dataFolder,markerFile_name)); 8 | 9 | %% Get a copy of the markerweightSet that you can print to file 10 | mws = ik.getMarkerWeightSet(); 11 | 12 | %% Get a cell array of character labels 13 | ml = ik.getMarkerLabels(); 14 | 15 | %% Change the weights of some markers 16 | ik.setMarkerWeight('R.ASIS', 10); 17 | ik.setMarkerWeight('L.ASIS', 10); 18 | ik.setMarkerWeight(ml{end}, 10); 19 | 20 | %% 21 | ik.run() 22 | 23 | e = ik.getErrors(); 24 | a = ik.getAngles(); 25 | 26 | ik.printMot(fullfile(dataFolder,'output.mot')) 27 | 28 | %% 29 | markerFile_name = 'subject01_static.trc'; 30 | ik = ikHelper(fullfile(dataFolder,model_name),fullfile(dataFolder,markerFile_name)); 31 | ik.run(); 32 | e = sum(ik.getErrors()); 33 | ik.printMot(fullfile(dataFolder,'subject01_static.mot')) 34 | -------------------------------------------------------------------------------- /tests/testosimTableStruct.m: -------------------------------------------------------------------------------- 1 | 2 | %% clear working space 3 | clear all;close all;clc; 4 | %% import opensim libraries 5 | import org.opensim.modeling.* 6 | %% Build a vec3 times series table programmatically 7 | table = DataTableVec3(); 8 | labels = StdVectorString(); 9 | labels.add('marker1');labels.add('marker2'); 10 | labels.add('marker3');labels.add('marker4'); 11 | table.setColumnLabels(labels); 12 | 13 | R = Rotation(pi/3, Vec3(0.1, 0.2, 0.3)); 14 | 15 | for i = 1 : 10 16 | elem = Vec3(randi(10,1),randi(10,1),randi(10,1)); 17 | elems = StdVectorVec3(); 18 | elems.add(elem); elems.add(elem); elems.add(elem); elems.add(elem); 19 | row = RowVectorOfVec3(elems); 20 | 21 | rotatedRow = R.multiply(row); 22 | table.appendRow(0.1,rotatedRow); 23 | end 24 | 25 | % Set the indpendentColumn (Time) values 26 | indCol = table.getIndependentColumn(); 27 | for i = 0 : 9 28 | indCol.set(i, i/100) 29 | end 30 | 31 | %% Turn DataTable to a timesSeriesTable, then flatten 32 | tsTable = TimeSeriesTableVec3(table); 33 | tsTable_d = tsTable().flatten(); 34 | 35 | %% Convert to OpenSim Tables to Matlab data type 36 | mData = osimTableToStruct(tsTable); 37 | mData_d = osimTableToStruct(tsTable_d); 38 | % Convert Matlab Structs back to OpenSim tables 39 | tsTable_2 = osimTableFromStruct(mData); 40 | tsTable_d_2 = osimTableFromStruct(mData_d); 41 | 42 | %% Check the number of columns and rows are maintained 43 | nCol = tsTable.getNumColumns();nRow = tsTable.getNumRows(); 44 | nCold = tsTable_d.getNumColumns();nRowd = tsTable_d.getNumRows(); 45 | nCol_2 = tsTable_2.getNumColumns();nRow_2 = tsTable_2.getNumRows(); 46 | nCold_2 = tsTable_d_2.getNumColumns();nRowd_2 = tsTable_d_2.getNumRows(); 47 | 48 | assert(nCol == nCol_2 & nRow == nRow_2,'Vec3 conversion OpenSim-Matlab_OpenSim incorrect: Rows or Columns not preserved'); 49 | assert(nCold == nCold_2 & nRowd == nRowd_2,'dbl conversion OpenSim-Matlab_OpenSim incorrect: Rows or Columns not preserved'); 50 | 51 | %% Check data across is conserved across conversions. 52 | 53 | for u = 0 : 9 54 | for i = 0 : 3 55 | % get the data from the element 56 | d = tsTable.getRowAtIndex(u).getElt(0,i); 57 | d2 = tsTable_2.getRowAtIndex(u).getElt(0,i); 58 | 59 | assert( d.get(0) == d2.get(0) & d.get(1) == d2.get(1) & d.get(2) == d2.get(2),['Data at row= ' num2str(u) ' & column= ' num2str(i) ' is not retained during conversion']) 60 | end 61 | end 62 | 63 | for u = 0 : 9 64 | for i = 0 : 11 65 | % get the data from the element 66 | d = tsTable_d.getRowAtIndex(u).getElt(0,i); 67 | d2 = tsTable_d_2.getRowAtIndex(u).getElt(0,i); 68 | 69 | assert(d == d2,['Data at row= ' num2str(u) ' & column= ' num2str(i) ' is not retained during conversion']) 70 | end 71 | end 72 | 73 | disp('New Table is the same as the original') 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | --------------------------------------------------------------------------------