--- a +++ b/Tools/ModelUtilities/Rhythms/SimpleRhythms.any @@ -0,0 +1,297 @@ +#ifndef MODELUTILS_RHYTHMS_SIMPLERHYTHMS_ANY +#define MODELUTILS_RHYTHMS_SIMPLERHYTHMS_ANY +/* +--- +group: Rhythms +topic: Linear +descr: | + Collection of class templates for linear and bilinear rhythm drivers. + These are for example used to create the spine rhythms in the AMMR. +--- + +To use these drivers import the file: +#include "<ANYBODY_PATH_MODELUTILS>/Rhythms/SimpleRhythms.any" + +See the individual classes for more information. + +*/ + + +// Creates a linear rhythm between the degrees of freedom (DOF) of a kinematic measure. The rhythm is defined by +// a `RhythmCoefficients` vector which defines the relative movement of the DOFs. +// +// In the example below the rhythm constrains two DOFs of the arm to move in a 1:4 ratio. +// +// :::{rubric} Example +// ::: +// +// :::{code-block} AnyScriptDoc +// RhythmDriverLinear Rhythm = { +// RhythmCoefficients = {0.2, 0.8}; +// Measures.Input = { +// AnyJoint& ref1 = Main.HumanModel.BodyModel.Interface.Arm.Right.ShoulderElevation; +// AnyJoint& ref2 = Main.HumanModel.BodyModel.Interface.Arm.Right.GHElevation; +// }; +//::: +// +#class_template RhythmDriverLinear(__CLASS__=AnyKinMotion, RELATIVE_TO_DOF=1, _REDEFINE_VARIABLES=Off){ + + // Arguments: + // ---------------------- + //RhythmDriverLinear#RELATIVE_TO_DOF + // Specifies which kinematic input measure is used in the implementation of the rhythm. + // By default (RELATIVE_TO_DOF=1) the first measure is used as the reference for the rest. + // I.e. all other measures are linked to some ratio of the first measure in the underlying + // matrix defining the rhythm. + // It is also possible to set this value to -1, in which case the rhythm is implemented + // implicitly, i.e. all kinematic measures are linked together as in a chain. Note, that + // implicit implementation prevents the any of the RhythmCoefficients to be zero. + + + // _REDREFINE_VARIABLES is a 'internal' flag used in the AMMR to allow + // the `RhythmCoefficients` to be declared when the class is used. + // Hence allowing the final user to still overwrite `RhythmCoefficients` + // in the application examples. + #if _REDEFINE_VARIABLES != On + + /// RhythmDriverLinear + /// The Coefficient which defines the relative weights of the + /// kinematic measures in the Rhythm. The default value is a vector of ones. + #var AnyVector RhythmCoefficients = ones(1,Measures.Input.nDim)[0]; + + #endif + + + + AnyInt DependentDOFs = set_difference(iarr(0, InputDim-1), {RELATIVE_TO_DOF}); + + AnyIntVar InputDim = iffun(NumElemOf(Measures.Input.MeasureOrganizer), NumElemOf(Measures.Input.MeasureOrganizer), Measures.Input.nDim); + + AnyFolder Measures = + { + AnyKinMeasureOrg Input = + { + //RhythmDriverLinear.Measures.Input + // A number of AnyKinMeasures that are used to define the rhythm + // AnyKinMeaure MyMeasure = <...>; (1..Inf) + + #var MeasureOrganizer = #default; + }; + }; + + AnyKinMeasureLinComb RhythmMeasure = { + AnyKinMeasureOrg Dependent = { + AnyKinMeasure& ref = ..Measures.Input; + #var MeasureOrganizer = ..DependentDOFs; + }; + #if RELATIVE_TO_DOF != -1 + AnyKinMeasureOrg InDependent = { + AnyKinMeasure& ref = ..Measures.Input; + #var MeasureOrganizer = {RELATIVE_TO_DOF}; + }; + #endif + + OutDim = .InputDim-1; + #var Const = zeros(1, OutDim)[0]; + + #if RELATIVE_TO_DOF != -1 + AnyVector LinWeights = take(.RhythmCoefficients, .DependentDOFs)/take(.RhythmCoefficients, RELATIVE_TO_DOF); + #var Coef = reshape(arrcat(-eye(OutDim), {LinWeights})', {OutDim, OutDim+1}); + #else + AnyVector LinWeights = REPLACE_ZEROS(.RhythmCoefficients, 10^-3)^-1; + #var Coef = reshape( + arrcat(reshape(diag(take(LinWeights, iarr(0, OutDim-1)))',{OutDim,OutDim}), zeros(1,OutDim))' + - arrcat(zeros(1,OutDim), diag( take(LinWeights, iarr(1,OutDim))))' + , {OutDim,OutDim+1}); + #endif + + }; + + AnyFolder Weights = { + AnyFunConst Fun ={ + Value ??= repmat(..nDim, 0.01); + }; + }; + + CType ??= repmat(nDim, Hard); + WeightFun ??= {&Weights.Fun}; + + Reaction ={ + Type ??= repmat(nDim, Off); + }; + + }; + + +// Include wrapper template to call _RhythmDriverFunInterpol multiple times +#include "<AMMR_TOOLS>/Lib/classtools/MultipleSubTemplates.any" + +// This helper class template used by the `RhythmDriverBiLinear` class +// to implement the interpolation function used in the rhythm. +#class_template _RhythmDriverFunInterpol(IDX=0, ARG1=0.2, ARG2=0, ARG3=0, ARG4=0, + __CLASS__= AnyFunInterpol) { + + AnyVector x_arr = linspace(ARG1/2, max({20*ARG1/2, 2*pi}), 100); + Type=Bspline; + T = arrcat(-1*flip(x_arr), {0.0}, x_arr); + Data = { arrcat( + .CoefficientsNeg[IDX]*-1*flip(x_arr), + {0.0}, + .CoefficientsPos[IDX]* x_arr + )}; + +}; + +// Creates a bi-linear rhythm between a number of input kinematic measures where the +// RhythmCoefficients can be different between the positive and negative values of +// the input measures. The rhythm is similar to simple `RhythmDriverLinear` template +// but is defined by two sets of RhythmCoefficients. +// +// * `RhythmCoefficients`: for positive values of the input measures +// * `RhythmCoefficientsNegative`: for negative values of the input measures +// * `TransitionInterval`: The interval over which the transition between the two +// sets of RhythmCoefficients is performed. +// +// The RhythmCoefficients are defined as a vector of coefficients for each +// kinematic measure. The relative ratio between the coefficients defines the +// rhythm. If the coefficients sum to 1, then the coefficients can be interpreted +// as the relative fraction of the kinematic measures in the rhythm. +#class_template RhythmDriverBiLinear(__CLASS__=AnyKinEq, NDIM, RELATIVE_TO_DOF=1, _REDEFINE_VARIABLES=Off){ + +//RhythmDriverBiLinear#RELATIVE_TO_DOF +// Specifies which kinematic input measure is used in the implementation of the rhythm. +// By default (RELATIVE_TO_DOF=1) the first measure is used as the reference for the rest. +// I.e. all other measures are linked to some ratio of the first measure in the underlying +// matrix defining the rhythm. +// It is also possible to set this value to -1, in which case the rhythm is implemented +// implicitly, i.e. all kinematic measures are linked together as in a chain. Note, that +// implicit implementation prevents the any of the RhythmCoefficients to be zero. +// +//RhythmDriverBiLinear#NDIM +// The number of kinematic measures used in the implementation of the rhythm. Due to +// the implementation it of this class template it is necessary to specify this value +// explicitly. + + + +#if _REDEFINE_VARIABLES != On + + // RhythmDriverBiLinear + /// The coefficient which defines the relative weights of the + /// kinematic measures in the Rhythm for positive inputs. + #var AnyVector RhythmCoefficients; + + // RhythmDriverBiLinear + /// The coefficient which defines the relative weights of the + /// kinematic measures in the Rhythm for negative inputs. + #var AnyVector RhythmCoefficientsNegative; + + // RhythmDriverBiLinear + /// The interval over which the transition between the two + /// sets of RhythmCoefficients is performed. + #var AnyVar TransitionInterval=0.1; +#endif + + + + AnyInt DependentDOFs = set_difference(iarr(0, InputDim-1), {RELATIVE_TO_DOF}); + + AnyIntVar InputDim = iffun(NumElemOf(Measures.Input.MeasureOrganizer), NumElemOf(Measures.Input.MeasureOrganizer), Measures.Input.nDim); + + + AnyFolder Weights = { + AnyFunConst Fun ={ + Value ??= repmat(..nDim, 0.01); + }; + }; + + CType ??= repmat(nDim, Hard); + WeightFun ??= {&Weights.Fun}; + + Reaction ={ + Type ??= repmat(nDim, Off); + }; + + + + AnyKinMeasureLinComb CombinedMeasure = { + AnyKinMeasure& Dependent = .Measures.GearedMeasure; + #if RELATIVE_TO_DOF != -1 + AnyKinMeasureOrg InDependent = { + AnyKinMeasure& ref = ..Measures.Input; + MeasureOrganizer = {RELATIVE_TO_DOF}; + }; + #endif + + OutDim = NDIM-1; + Const = zeros(1, OutDim)[0]; + + #if RELATIVE_TO_DOF != -1 + + Coef = reshape(arrcat(-eye(OutDim), ones(1,OutDim))', {OutDim,OutDim+1}); + #else + Coef = reshape( + arrcat(eye(OutDim), zeros(1,OutDim))' + - arrcat(zeros(1,OutDim), eye(OutDim))' + , {OutDim,OutDim+1}); + #endif + + }; + + AnyFolder Measures = { + AnyKinMeasureOrg Input = + { + //RhythmDriverBiLinear.Measures.Input + // A number of AnyKinMeasures that are used to define the rhythm + // AnyKinMeasure MyMeasure = <...>; (1..Inf) + + + #var MeasureOrganizer = #default; + }; + + AnyKinMeasureFunComb1 GearedMeasure = + { + AnyKinMeasureOrg Dependent = + { + AnyKinMeasure& ref = ..Input; + MeasureOrganizer = ...DependentDOFs; + }; + + Functions = ObjSearch("ParamFuns.Fun*", "AnyFunInterpol"); + #if RELATIVE_TO_DOF != -1 + MultipleSubTemplates ParamFuns( + NUM=NDIM-1, + CLASS_TEMPLATE = "_RhythmDriverFunInterpol", + NAME_PREFIX=Fun, + ARG1 = ....TransitionInterval + ) = { + #var AnyVector CoefficientsPos = take(...RhythmCoefficients, RELATIVE_TO_DOF) /take(REPLACE_ZEROS(...RhythmCoefficients, 10^-3), ...DependentDOFs ); + #var AnyVector CoefficientsNeg = take(...RhythmCoefficientsNegative, RELATIVE_TO_DOF)/take(REPLACE_ZEROS(...RhythmCoefficientsNegative, 10^-3), ...DependentDOFs ); + }; + #endif + + #if RELATIVE_TO_DOF == -1 + MultipleSubTemplates ParamFuns( + NUM=NDIM, + CLASS_TEMPLATE="_RhythmDriverFunInterpol", + NAME_PREFIX=Fun, + ARG1 = ....TransitionInterval + ) = { + #var AnyVector CoefficientsPos = 1/REPLACE_ZEROS(...RhythmCoefficients, 10^-3); + #var AnyVector CoefficientsNeg = 1/REPLACE_ZEROS(...RhythmCoefficientsNegative, 10^-3); + }; + #endif + + }; + + + }; + +}; + + +#endif + + + +