[38ba34]: / Tools / ModelUtilities / Rhythms / SimpleRhythms.any

Download this file

298 lines (229 with data), 10.5 kB

#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