% This function is part of the NMSM Pipeline, see file for full license.
%
% This function uses a spring model with damping to calculate the modeled
% vertical GRF force as the summation of the forces applied by each
% individual spring
%
% (Array of double, double, double, struct, Array of double)
% -> (double, Array of double)
% Returns the sum of the modeled vertical GRF forces at the given state
function [modeledVerticalGrf, springForces] = ...
calcModeledVerticalGroundReactionForce(springConstants, ...
dampingFactor, springRestingLength, ...
markerKinematics, springForces)
modeledVerticalGrf = 0;
for i=1:length(springConstants)
height = markerKinematics.height(i);
verticalVelocity = markerKinematics.yVelocity(i);
% The freglyVerticalGrf model closely approximates a linear spring
% during contact while allowing a small force with a small slope to
% exist for spring markers out of contact. This can help the
% optimization algorithm find a better search direction when springs
% are incorrectly out of contact.
klow = 1e-1;
h = 1e-3;
c = 5e-4;
ymax = 1e-2;
Kval = springConstants(i);
height = height - springRestingLength;
numFrames = length(height);
v = ones(numFrames, 1)' .* ((Kval + klow) ./ (Kval - klow));
s = ones(numFrames, 1)' .* ((Kval - klow) ./ 2);
constant = -s .* (v .* ymax - c .* log(cosh((ymax + h) ./ c)));
freglyVerticalGrf = -s .* (v .* height - c .* ...
log(cosh((height + h) ./ c))) - constant;
% Account for potential errors in force model
freglyVerticalGrf(isnan(freglyVerticalGrf)) = ...
min(min(freglyVerticalGrf));
freglyVerticalGrf(isinf(freglyVerticalGrf)) = ...
min(min(freglyVerticalGrf));
springForces(2, i) = freglyVerticalGrf * (1 + dampingFactor * ...
verticalVelocity);
modeledVerticalGrf = modeledVerticalGrf + springForces(2, i);
end
end