1 /* -------------------------------------------------------------------------- *
2  *              OpenSim:  FirstOrderMuscleActivationDynamics.cpp              *
3  * -------------------------------------------------------------------------- *
4  * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
5  * See http://opensim.stanford.edu and the NOTICE file for more information.  *
6  * OpenSim is developed at Stanford University and supported by the US        *
7  * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
8  * through the Warrior Web program.                                           *
9  *                                                                            *
10  * Copyright (c) 2005-2017 Stanford University and the Authors                *
11  * Author(s): Thomas Uchida, Matthew Millard, Ajay Seth                       *
12  *                                                                            *
13  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
14  * not use this file except in compliance with the License. You may obtain a  *
15  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
16  *                                                                            *
17  * Unless required by applicable law or agreed to in writing, software        *
18  * distributed under the License is distributed on an "AS IS" BASIS,          *
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
20  * See the License for the specific language governing permissions and        *
21  * limitations under the License.                                             *
22  * -------------------------------------------------------------------------- */
23 
24 #include "FirstOrderMuscleActivationDynamics.h"
25 
26 using namespace std;
27 using namespace OpenSim;
28 using namespace SimTK;
29 
30 const std::string FirstOrderMuscleActivationDynamics::
31                   STATE_NAME_ACTIVATION = "activation";
32 
33 //==============================================================================
34 // CONSTRUCTORS
35 //==============================================================================
FirstOrderMuscleActivationDynamics()36 FirstOrderMuscleActivationDynamics::FirstOrderMuscleActivationDynamics() :
37 MuscleActivationDynamics()
38 {
39     setNull();
40     constructProperties();
41     setName("default_FirstOrderMuscleActivationDynamics");
42 }
43 
44 FirstOrderMuscleActivationDynamics::
FirstOrderMuscleActivationDynamics(const std::string & name,ExcitationGetter * getter)45 FirstOrderMuscleActivationDynamics(const std::string& name,
46                                    ExcitationGetter* getter) :
47 MuscleActivationDynamics(name, getter)
48 {
49     setNull();
50     constructProperties();
51 }
52 
53 //==============================================================================
54 // ACCESSORS AND MUTATORS
55 //==============================================================================
getActivationTimeConstant() const56 double FirstOrderMuscleActivationDynamics::getActivationTimeConstant() const
57 {   return get_activation_time_constant(); }
getDeactivationTimeConstant() const58 double FirstOrderMuscleActivationDynamics::getDeactivationTimeConstant() const
59 {   return get_deactivation_time_constant(); }
60 
61 void FirstOrderMuscleActivationDynamics::
setActivationTimeConstant(double activationTimeConstant)62 setActivationTimeConstant(double activationTimeConstant)
63 {
64     set_activation_time_constant(max(SimTK::SignificantReal,
65                                      activationTimeConstant));
66 }
67 
68 void FirstOrderMuscleActivationDynamics::
setDeactivationTimeConstant(double deactivationTimeConstant)69 setDeactivationTimeConstant(double deactivationTimeConstant)
70 {
71     set_deactivation_time_constant(max(SimTK::SignificantReal,
72                                        deactivationTimeConstant));
73 }
74 
75 //==============================================================================
76 // MODELCOMPONENT INTERFACE REQUIREMENTS
77 //==============================================================================
78 void FirstOrderMuscleActivationDynamics::
extendAddToSystem(SimTK::MultibodySystem & system) const79 extendAddToSystem(SimTK::MultibodySystem& system) const
80 {
81     Super::extendAddToSystem(system);
82     addStateVariable(STATE_NAME_ACTIVATION, SimTK::Stage::Dynamics);
83 }
84 
85 void FirstOrderMuscleActivationDynamics::
extendInitStateFromProperties(SimTK::State & s) const86 extendInitStateFromProperties(SimTK::State& s) const
87 {
88     Super::extendInitStateFromProperties(s);
89     setActivation(s, getDefaultActivation());
90 }
91 
92 void FirstOrderMuscleActivationDynamics::
extendSetPropertiesFromState(const SimTK::State & s)93 extendSetPropertiesFromState(const SimTK::State& s)
94 {
95     Super::extendSetPropertiesFromState(s);
96     setDefaultActivation(getActivation(s));
97 }
98 
99 void FirstOrderMuscleActivationDynamics::
computeStateVariableDerivatives(const SimTK::State & s) const100 computeStateVariableDerivatives(const SimTK::State& s) const
101 {
102      double adot =
103          calcActivationDerivative(getExcitation(s), getActivation(s));
104 
105      setStateVariableDerivativeValue(s, STATE_NAME_ACTIVATION, adot);
106 }
107 
108 //==============================================================================
109 // STATE-DEPENDENT METHODS
110 //==============================================================================
111 double FirstOrderMuscleActivationDynamics::
getActivation(const SimTK::State & s) const112 getActivation(const SimTK::State& s) const
113 {
114     return clampToValidInterval(getStateVariableValue(s, STATE_NAME_ACTIVATION));
115 }
116 
setActivation(SimTK::State & s,double activation) const117 void FirstOrderMuscleActivationDynamics::setActivation(SimTK::State& s,
118                                                        double activation) const
119 {
120     setStateVariableValue(s, STATE_NAME_ACTIVATION,
121                      clampToValidInterval(activation));
122 }
123 
124 //==============================================================================
125 // PRIVATE METHODS
126 //==============================================================================
setNull()127 void FirstOrderMuscleActivationDynamics::setNull()
128 {
129     setAuthors("Thomas Uchida, Matthew Millard, Ajay Seth");
130 }
131 
constructProperties()132 void FirstOrderMuscleActivationDynamics::constructProperties()
133 {
134     constructProperty_activation_time_constant(0.010);
135     constructProperty_deactivation_time_constant(0.040);
136 }
137 
138 double FirstOrderMuscleActivationDynamics::
calcActivationDerivative(double excitation,double activation) const139 calcActivationDerivative(double excitation, double activation) const
140 {
141     excitation = clampToValidInterval(excitation);
142     activation = clampToValidInterval(activation);
143     double tau = (excitation > activation)
144                  ? getActivationTimeConstant() * (0.5 + 1.5*activation)
145                  : getDeactivationTimeConstant() / (0.5 + 1.5*activation);
146     return (excitation-activation)/tau;
147 }
148