/* * * TorqueMuscle * Copyright (c) 2016 Matthew Millard * * Licensed under the zlib license. See LICENSE for more details. */ //============================================================================== // INCLUDES //============================================================================== #include "../Millard2016TorqueMuscle.h" #include "../csvtools.h" #include "../../geometry/tests/numericalTestFunctions.h" #include #include #include #include #include #include #include #include #include #include using namespace RigidBodyDynamics::Addons::Muscle; using namespace RigidBodyDynamics::Addons::Geometry; using namespace std; /* Constructor tests: 1. Coefficients are copied over correctly. 2. Curves are made correctly calcTorqueMuscleInfo test stiffness calculation power calculation */ TEST(ConstructorRegularCallCheck) { //Check that the 3 constructors when called properly //do not abort Millard2016TorqueMuscle test0 = Millard2016TorqueMuscle(); SubjectInformation subjectInfo; subjectInfo.gender = GenderSet::Male; subjectInfo.ageGroup = AgeGroupSet::Young18To25; subjectInfo.heightInMeters = 1.732; subjectInfo.massInKg = 69.0; Millard2016TorqueMuscle test2 = Millard2016TorqueMuscle( DataSet::Anderson2007, subjectInfo, Anderson2007::HipExtension, 0.0, 1.0, 1.0, "test_easyConstructor"); CHECK(abs( test2.getPassiveTorqueScale()-1.0) < TOL); } TEST(calcJointTorqueCorrectnessTests){ double jointAngleOffset = 0; double signOfJointAngle = 1; double signOfJointTorque = 1; double err = 0.0; std::string name("test"); SubjectInformation subjectInfo; subjectInfo.gender = GenderSet::Male; subjectInfo.ageGroup = AgeGroupSet::Young18To25; subjectInfo.heightInMeters = 1.732; subjectInfo.massInKg = 69.0; Millard2016TorqueMuscle tq = Millard2016TorqueMuscle(DataSet::Anderson2007, subjectInfo, Anderson2007::HipExtension, jointAngleOffset, signOfJointAngle, signOfJointTorque, name); bool flagMakeTestVector = false; if(flagMakeTestVector){ Millard2016TorqueMuscle tqG = Millard2016TorqueMuscle(DataSet::Gymnast, subjectInfo, Gymnast::HipExtension, jointAngleOffset, signOfJointAngle, signOfJointTorque, name); TorqueMuscleInfo tmiG; tqG.calcTorqueMuscleInfo(M_PI/3.0,0.1,0.77,tmiG); printf("%f\n",tmiG.fiberAngle); printf("%f\n",tmiG.fiberAngularVelocity); printf("%f\n",tmiG.activation); printf("%f\n",tmiG.fiberTorque); printf("%f\n",tmiG.fiberStiffness); printf("%f\n",tmiG.fiberPassiveTorqueAngleMultiplier); printf("%f\n",tmiG.fiberActiveTorqueAngleMultiplier); printf("%f\n",tmiG.fiberActiveTorqueAngularVelocityMultiplier); printf("%f\n",tmiG.fiberPassiveTorque); printf("%f\n",tmiG.fiberActiveTorque); printf("%f\n",tmiG.fiberDampingTorque); printf("%f\n",tmiG.fiberNormDampingTorque); printf("%f\n",tmiG.fiberActivePower); printf("%f\n",tmiG.fiberPassivePower); printf("%f\n",tmiG.fiberPower); printf("%f\n",tmiG.DjointTorqueDjointAngle); printf("%f\n",tmiG.DjointTorqueDjointAngularVelocity); printf("%f\n",tmiG.DjointTorqueDactivation); } //Zero out the passive forces so that calcMuscleTorque reports //just the active force - this allows us to test its correctness. tq.setPassiveTorqueScale(0.0); //Test that the get and set functions work for //maximum isometric torque double tauMaxOld = tq.getMaximumActiveIsometricTorque(); double tauMax = tauMaxOld*10.0; tq.setMaximumActiveIsometricTorque(tauMax); CHECK(abs( tq.getMaximumActiveIsometricTorque()-tauMax) < TOL ); //getParametersC1C2C3C4C5C6() has been removed and so this //test is no longer possible. It is the responsibility of //the underlying active-torque-angle curve to ensure that //it peaks at 1.0 /* RigidBodyDynamics::Math::VectorNd c1c2c3c4c5c6 = tq.getParametersC1C2C3C4C5C6(); double thetaAtTauMax = c1c2c3c4c5c6[2]; */ //TorqueMuscleInfo tqInfo; //getParametersC1C2C3C4C5C6() has been removed. It is the //responsibility of the underlying curve test code to //check for correctness. //double torque = tq.calcJointTorque(thetaAtTauMax,0.0,1.0); //err = abs(torque -tauMax); //CHECK(err< TOL); //These tests have been updated because Anderson //torque velocity curve had to be replaced because it //can behave badly (e.g. the concentric curve of the ankle //extensors of a young man does not interest the x axis.) // //The new curves do not pass exactly through the points //0.5*tauMax and 0.75*tauMax, but within 5% of this //value. //getParametersC1C2C3C4C5C6() has been removed. It is the //responsibility of the underlying curve test code to //check for correctness. //double omegaAt75TauMax = c1c2c3c4c5c6[3]; //torque = tq.calcJointTorque(thetaAtTauMax,omegaAt75TauMax,1.0); //err = abs(torque - 0.75*tauMax)/tauMax; //CHECK( err < 0.05); //double omegaAt50TauMax = c1c2c3c4c5c6[4]; //torque = tq.calcJointTorque(thetaAtTauMax,omegaAt50TauMax,1.0); //err = abs(torque -0.50*tauMax)/tauMax; //CHECK(err < 0.05); } TEST(calcTorqueMuscleInfoCorrectnessTests){ double jointAngleOffset = 0; double signOfJointAngle = 1; double signOfJointTorque = 1; double signOfJointVelocity = signOfJointTorque; std::string name("test"); SubjectInformation subjectInfo; subjectInfo.gender = GenderSet::Female; subjectInfo.ageGroup = AgeGroupSet::SeniorOver65; subjectInfo.heightInMeters = 1.732; subjectInfo.massInKg = 69.0; Millard2016TorqueMuscle tq = Millard2016TorqueMuscle(DataSet::Anderson2007, subjectInfo, Anderson2007::HipExtension, jointAngleOffset, signOfJointAngle, signOfJointTorque, name); double jointAngle = 0.; double jointVelocity = 0.; double activation = 1.0; tq.setPassiveTorqueScale(0.5); tq.calcJointTorque(0,0,1.0); tq.setPassiveTorqueScale(1.0); tq.calcJointTorque(0,0,1.0); double tauMax = tq.getMaximumActiveIsometricTorque(); //RigidBodyDynamics::Math::VectorNd c1c2c3c4c5c6 = // tq.getParametersC1C2C3C4C5C6(); //RigidBodyDynamics::Math::VectorNd b1k1b2k2 = // tq.getParametersB1K1B2K2(); /* int idx = -1; if(b1k1b2k2[0] > 0){ idx = 0; }else if(b1k1b2k2[2] > 0){ idx = 2; } */ /* double b = b1k1b2k2[idx]; double k = b1k1b2k2[idx+1]; double thetaAtPassiveTauMax = log(tauMax/b)/k; double thetaAtTauMax = c1c2c3c4c5c6[2]; double omegaAt75TauMax = c1c2c3c4c5c6[3]; double omegaAt50TauMax = c1c2c3c4c5c6[4]; double jointAngleAtTauMax = signOfJointAngle*thetaAtTauMax+jointAngleOffset; */ double jointAngleAtTauMax = tq.getJointAngleAtMaximumActiveIsometricTorque(); TorqueMuscleInfo tmi; tq.calcTorqueMuscleInfo(jointAngleAtTauMax, 0., activation, tmi); //Keypoint check: active force components + fiber kinematics CHECK(abs(tmi.activation-1) < EPSILON); CHECK(abs(tmi.jointAngle-jointAngleAtTauMax)< TOL); CHECK(abs(tmi.jointAngularVelocity-0.) < TOL); CHECK(abs(tmi.activation-1) < EPSILON); //CHECK(abs(tmi.fiberAngle-thetaAtTauMax) < TOL); CHECK(abs(tmi.fiberAngularVelocity-0.) < TOL); CHECK(abs(tmi.fiberActiveTorque - tauMax) < TOL); CHECK(abs(tmi.fiberActiveTorqueAngleMultiplier-1.0) < TOL); CHECK(abs(tmi.fiberActiveTorqueAngularVelocityMultiplier-1.0) muscleVector; bool exception = false; double angleTorqueSigns[][2] = {{-1, 1}, {-1,-1}, { 1,-1}, { 1, 1}, {-1, 1}, {-1,-1}}; Millard2016TorqueMuscle tqMuscle; std::stringstream tqName; int tqIdx; for(int i=0; i < Anderson2007::LastJointTorque; ++i){ tqName.str(""); tqName << DataSet.names[0] <