def exercise2a(): """ Exercise 2a The goal of this exercise is to understand the relationship between muscle length and tension. Here you will re-create the isometric muscle contraction experiment. To do so, you will have to keep the muscle at a constant length and observe the force while stimulating the muscle at a constant activation.""" # Defination of muscles parameters = MuscleParameters() biolog.warning("Loading default muscle parameters") biolog.info(parameters.showParameters()) # Create muscle object muscle = Muscle.Muscle(parameters) muscle.l_opt = 0.11 activation = 0.05 stretch=np.arange(-0.09, 0.09, 0.001) res = isometric_contraction(muscle, stretch, activation) plt.title('Force-Length when activation is %s' %activation) plt.title('Force-Length when Lopt is %s' %muscle.l_opt) plt.ylim(0,1.7*max(res[1])) # plt.ylim(0,2500) plt.plot(res[0],res[1]) plt.plot(res[0],res[2]) plt.plot(res[0],res[2]+res[1]) plt.legend(['active force','passive force','total force']) plt.xlabel('Length(m)') plt.ylabel('Force(N)') plt.grid() plt.show() """ Example for plotting graphs using matplotlib. """
def mass(self, value): """Keyword Arguments: value -- Set the value of pendulum's mass [kg] """ self.parameters['mass'] = value self.setInertia() biolog.info('Changed pendulum mass to {} [kg]'.format( self.parameters['mass']))
def calc(a, b, op='add'): if op == 'add': return a + b elif op == 'sub': return a - b else: biolog.info('valid operations are add and sub')
def L(self, value): """ Keyword Arguments: value -- Set the value of pendulum's length [m] """ self.parameters['L'] = value self.setInertia() biolog.info('Changed pendulum length to {} [m]'.format( self.parameters['L']))
def exercise_compile(master_file, **kwargs): """ Compile exercise master file Kwargs: - folder_s: Statement output folder - folder_c: Corrections output folder """ master_name, master_extension = master_file.split(".") statement_file = "{}/{}{}.{}".format( kwargs.pop("folder_s", "Statement/Python"), master_name, kwargs.pop("end_s", ""), master_extension ) corrections_file = "{}/{}{}.{}".format( kwargs.pop("folder_c", "Corrections/Python"), master_name, kwargs.pop("end_c", ""), master_extension ) for filename, symbol_insert, symbol_remove in [ [statement_file, SYM_STAT, SYM_CORR], [corrections_file, SYM_CORR, SYM_STAT] ]: biolog.info("Compiling {}".format(filename)) check_and_create_dir(filename) _compile(master_file, filename, symbol_insert, symbol_remove) return
def main(): """Main function that runs all the exercises.""" biolog.info('Implementing Lab 5 : Exercise 3') exercise3() biolog.info('Implementing Lab 5 : Exercise 4') exercise4() return
def s_theta_ref2(self, value): """ Keyword Arguments: value -- Set the value of spring 2 reference angle [rad] """ self.parameters['s_theta_ref2'] = value biolog.info( 'Changed spring 2 reference angle to {} [rad]'.format( self.parameters['s_theta_ref2']))
def ode_integrate_rk(fun_rk, x0, time_max, time_step): """ Integrate function using Euler method - fun: Function df/dt = f(x, t) to integrate - x0: Initial state - time_tot: Total time to simulate [s] - time_step: Time step [s] For Runge-Kutta, use: solver = ode(fun) solver.set_integrator('dopri5') solver.set_initial_value(x0, time[0]) xi = solver.integrate(ti) Note that solver.integrate(ti) only integrates for one time step at time ti (where ti is the current time), so you will need to use a for loop Make sure to use the Result class similarly to the example_integrate found above (i.e. Result(x, time)) """ time = np.arange(0, time_max, time_step) x = np.zeros([len(time), len(x0)]) x[0] = float(x0) solver = ode(fun_rk) solver.set_integrator('dopri5') solver.set_initial_value(x0, time[0]) for i, ti in enumerate( time[:]): # time[:] = copy of the array time, with all elements x[i] = solver.integrate(ti) biolog.info("ODE integration with RK implemented") return Result(x, time)
def main(): """Main function that runs all the exercises.""" biolog.info('Implementing Lab 4 : Exercise 1') exercise1() biolog.info('Implementing Lab 4 : Exercise 2') exercise2() return
def __init__(self, **kwargs): super(PendulumParameters, self).__init__() self.g = kwargs.pop("g", 9.81) # Gravity constant self.L = kwargs.pop("L", 1.) # Length self.d = kwargs.pop("d", 0.3) # damping origin = 0.3 self.sin = kwargs.pop("sin", np.sin) # Sine function self.dry = kwargs.pop("dry", True) # Use dry friction (True or False) biolog.info(self) return
def exercise2b(): """ Exercise 2b Under isotonic conditions external load is kept constant. A constant stimulation is applied and then suddenly the muscle is allowed contract. The instantaneous velocity at which the muscle contracts is of our interest""" # Definition of muscles muscle_parameters = MuscleParameters() print(muscle_parameters.showParameters()) mass_parameters = MassParameters() print(mass_parameters.showParameters()) # Create muscle object muscle = Muscle.Muscle(muscle_parameters) # Point 2d. Different load values. biolog.info("Calling for point 2d") isoK = isotonic_contraction(muscle) lineV = np.arange(-1, 2500, 1) zerV = np.zeros(np.size(lineV)) plt.figure("Plot of Force vs Velocity") plt.plot(isoK[0], isoK[1]) plt.title("Tension vs Normalised Velocity", fontsize=18) plt.plot(zerV, lineV, linestyle=':', color='red') plt.xlabel('Normalised Velocity [-]') plt.ylabel('Total Force of the Muscle [N]') plt.legend(['Force/Velocity [N]']) plt.minorticks_on() plt.grid(which='major', linestyle='-', linewidth='0.5', color='black') plt.grid(which='minor', linestyle=':', linewidth='0.5', color='black') save_figure('velociplot') # plt.plot(isoK[0], isoK[1], 'o', markersize = 5) # Point 2f. Different muscle activation values. activations = np.arange(0.5, 1.05, 0.05) plt.figure( 'Muscle Force vs Normalised velocity for varying activation time') legend2 = list() #print(activations) for i, a in enumerate(activations): muscle1 = Muscle.Muscle(muscle_parameters) #print("Activation = {} [s]".format(a)) iso = isotonic_contraction(muscle1, activation=a) #print("lapin \n {}".format(iso[2])) legend2.append("Activation = {} [-]".format(a)) plt.plot(iso[0], iso[1]) # plot for active force plt.xlabel('Normalised Velocity [-]') plt.ylabel('Total Force [N]') plt.plot(zerV, lineV, linestyle=':', color='red') plt.legend(legend2) plt.grid() plt.minorticks_on() plt.grid(which='major', linestyle='-', linewidth='0.5', color='black') plt.grid(which='minor', linestyle=':', linewidth='0.5', color='black') save_figure('F_vs_Vel_Activations')
def k2(self, value): """ Keyword Arguments: value -- Set the value of spring constant for spring 2[N/rad] """ if (value < 0.0): biolog.warning('Setting bad spring constant. Should be positive!') else: self.parameters['k2'] = value biolog.info( 'Changed spring constant of spring 1 to {} [N/rad]'.format(self.parameters['k2']))
def b2(self, value): """ Keyword Arguments: value -- Set the value of damping constant for damper 2. [N-s/rad] """ if (value < 0.0): biolog.warning('Setting bad damping values. Should be positive!') else: self.parameters['b2'] = value biolog.info( 'Changed damping constant for damper 2 to {} [N-s/rad]'.format(self.parameters['b2']))
def isometric_contraction(): iso_sys = MusculoSkeletalSystem( '../../../musculo_skeletal_generator/conf/muscles.yaml') #: Initialize network parameters #: pylint: disable=invalid-name dt = 1 #: Time step _time = np.arange(0, 100, dt) #: Time #: Vector to store results res = np.empty([len(_time), len(iso_sys.muscle_sys.dae.x)]) res_deep = np.empty([len(_time), len(iso_sys.muscle_sys.dae.z)]) muscle_stretch = np.concatenate( (np.linspace(0.0, -0.05, 25), np.linspace(-0.1, 0.05, 50))) length = np.empty(np.shape(muscle_stretch)) force = np.empty(np.shape(muscle_stretch)) active_force = np.empty(np.shape(muscle_stretch)) passive_force = np.empty(np.shape(muscle_stretch)) start_time = time.time() #: Integrate the network muscle_act = {'m1': 0.75} for idxx, stretch in enumerate(muscle_stretch): iso_sys.muscle_sys.dae.p[0] = stretch for idx, _ in enumerate(_time): iso_sys.step(muscle_act) res[idx] = iso_sys.state['muscles']['xf'].full()[:, 0] res_deep[idx] = iso_sys.state['muscles']['zf'].full()[:, 0] length[idxx] = res[-1, 0] force[idxx] = res_deep[-1, 0] active_force[idxx] = res_deep[-1, 1] passive_force[idxx] = res_deep[-1, 2] l_opt = iso_sys.muscle_sys.muscles['m1'].l_opt.val f_max = iso_sys.muscle_sys.muscles['m1'].f_max.val end_time = time.time() biolog.info('Execution Time : {}'.format(end_time - start_time)) # Plotting plt.figure('2a Force-Length') plt.plot(length / l_opt, force) plt.plot(length / l_opt, active_force) plt.plot(length / l_opt, passive_force) plt.plot(np.ones((25, 1)), np.linspace(0., f_max, 25), '--') plt.text(0.6, 600, 'Below \n optimal \n length', fontsize=14) plt.text(1.1, 600, 'Above \n optimal \n length', fontsize=14) plt.title('Force-Length Relationship') plt.xlabel('Muscle CE Length') plt.ylabel('Muscle Force') plt.legend(('Force', 'Active Force', 'Passive Force'), loc=2) plt.grid() plt.show()
def plot_integration_methods(**kwargs): """ Plot integration methods results """ biolog.info("Plotting integration results") # Results analytical = kwargs.pop("analytical", None) euler = kwargs.pop("euler", None) ode = kwargs.pop("ode", None) ode_rk = kwargs.pop("ode_rk", None) euler_ts_small = kwargs.pop("euler_ts_small", None) # Figures fig_all = kwargs.pop("figure", "Integration methods".replace(" ", "_")) fig_ts = "Integration methods smaller ts".replace(" ", "_") fig_euler = "Euler integration".replace(" ", "_") d = "." # Time steps information et_val = kwargs.pop("euler_timestep", None) ets_val = kwargs.pop("euler_timestep_small", None) et = " (ts={})".format(et_val) if et_val is not None else "" ets = " (ts={})".format(ets_val) if ets_val is not None else "" # Analytical if analytical is not None: analytical.plot_state(figure=fig_euler, label="Analytical", marker=d) # Euler if euler is not None: euler.plot_state(figure=fig_euler, label="Euler" + et, marker=d) # ODE ls = " " ode_plot = False if ode is not None: if ode_plot is False: analytical.plot_state(figure=fig_all, label="Analytical", marker=d) euler.plot_state(figure=fig_all, label="Euler" + et, marker=d) ode_plot = True ode.plot_state(figure=fig_all, label="LSODA", linestyle=ls, marker="x") # ODE Runge-Kutta if ode_rk is not None: if ode_plot is False: analytical.plot_state(figure=fig_all, label="Analytical", marker=d) euler.plot_state(figure=fig_all, label="Euler" + et, marker=d) ode_rk.plot_state(figure=fig_all, label="RK", linestyle=ls, marker=d) # Euler with lower time step if euler_ts_small is not None: euler_ts_small.plot_state(figure=fig_ts, label="Euler" + ets) analytical.plot_state(figure=fig_ts, label="Analytical", marker=d) return
def isometric_contraction( muscle, stretch=np.arange(-0.05, 0.05, 0.001), # !!! stretch is in percent! activation=0.25): # activation original = 0.05 """ This function implements the isometric contraction of the muscle. Parameters: ----------- muscle : <Muscle> Instance of Muscle class stretch : list/array A list/array of muscle stretches to be evaluated activation : float Muscle activation Returns: ------- """ stretch = np.array(stretch) biolog.warning('Exercise 2b isotonic contraction to be implemented') # Time settings t_start = 0.0 # Start time t_stop = 0.25 # Stop time dt = 0.0001 # Time step timesteps = np.arange(t_start, t_stop, dt) # Useless?? # Empty vectors for further isometric representations Fp = np.zeros(np.size(stretch)) # passive force Fa = np.zeros(np.size(stretch)) # active force F = np.zeros(np.size(stretch)) # total force totLen = np.zeros(np.size( stretch)) # total length of the CONTRACTILE ELEMENT (l_CE + stretch) stabs = np.zeros(np.size(timesteps)) biolog.info("Muscle Isometric implemented") for i, s in enumerate(stretch): for j, t in enumerate(timesteps): effect = muscle_integrate(muscle, s, activation, dt) stabs[j] = effect['activeForce'] # effect=muscle_integrate(muscle, s, activation, dt) # effect=muscle_integrate(muscle, s, activation, dt) Fp[i] = effect['passiveForce'] Fa[i] = effect['activeForce'] F[i] = effect['force'] totLen[i] = effect['l_CE'] + s * effect['l_CE'] #print("Length of the contractile element is: {} \n and its TOTAL length+stretch is: {}".format(effect['l_CE'],totLen[i])) #print("LIMIT: {} \n {}".format(muscle.l_MTC-muscle.l_CE, muscle.l_slack)) c = np.array([totLen, Fp, Fa, F, timesteps, stabs]) #print(c) return c
def fixed_point(A): """ Compute fixed point """ x = sympy.symbols( ["x{}".format(i) for i in range(2)] ) # used to denominate the x = (x,y) vector just as follow: x = (x[0], x[1]) sol = sympy.solve( np.dot(A, x), x ) # Use solve() to solve algebraic equations. We suppose all equations are equaled to 0, so solving x**2 == 1 translates into the following code: solve(x**2 - 1, x) x0 = sol[x[0]], sol[x[1]] biolog.info("Fixed point: {}".format(x0)) biolog.info("x is = to: {}".format(x0)) return
def euler_integrate(fun, x0, time_max, time_step): """ Integrate function using Euler method - fun: Function df/dt = f(x, t) to integrate - x0: Initial state - time_tot: Total time to simulate [s] - time_step: Time step [s] For loop in Python: >>> a = [0, 0, 0] # Same as [0 for _ in range(3)] (List comprehension) >>> for i in range(3): ... a[i] = i >>> print(a) [0, 1, 2] Creating a matrix of zeros in python: >>> state = np.zeros([3, 2]) >>> print(state) [[0. 0.] [0. 0.] [0. 0.]] For loop for a state in python >>> state = np.zeros([3, 2]) >>> state[0, 0], state[0, 1] = 1, 2 >>> for i, time in enumerate([0, 0.1, 0.2]): ... state[i, 0] += time ... state[i, 1] -= time >>> print(state) [[ 1. 2. ] [ 0.1 -0.1] [ 0.2 -0.2]] Make sure to use the Result class similarly to the example_integrate found above (i.e. Result(x, time)) """ time = np.arange(0, time_max, time_step) x = np.zeros([len(time), len(x0)]) x[0] = float(x0) for i, ti in enumerate( time[:-1] ): # time[:-1] = copy of array "time", w/o the last element x[i + 1] = x[i] + 2. * (5. - x[i]) * (time_step) # biolog.info(ti) biolog.info("Euler integration implemented") return Result(x, time)
def initialize_musculoskeletal_system(self,config_file = '../../../modeling/configFiles/human-config.yaml'): """ Initialize musculoskeletalsystem. """ biolog.info('Initializing musculoskeletalsystem') dt = 0.001 opts = {'tf': dt, 'jit': False, "enable_jacobian": True, "print_time": False, "print_stats": False, "reltol": 1e-6, "abstol": 1e-6} musculo_sys = MusculoSkeletalSystem(config_file, opts=opts) return musculo_sys
def add_pendulum_system(self, system): """Add the pendulum system. Parameters ---------- system: Pendulum Pendulum system """ if self.systems_list.count('pendulum') == 1: biolog.warning( 'You have already added the pendulum model to the system.') return else: biolog.info('Added pedulum model to the system') self.systems_list.append('pendulum') self.pendulum_sys = system
def add_neural_system(self, system): """Add the neural network system. Parameters ---------- system: NeuralSystem Neural Network system """ if self.systems_list.count('neural') == 1: biolog.warning( 'You have already added the neural model to the system.') return else: biolog.info('Added neural network to the system') self.systems_list.append('neural') self.neural_sys = system
def add_muscle_system(self, system): """Add the muscle system. Parameters ---------- system: MuscleSystem Muscle system """ if self.systems_list.count('muscle') == 1: biolog.warning( 'You have already added the muscle model to the system.') return else: biolog.info('Added muscle model to the system') self.systems_list.append('muscle') self.muscle_sys = system
def analytic_function(t): """ Analytic funtion x(t) (To be written) Notes: - To write exponential(x) in Python with numpy: np.exp(x) Example: >>> np.exp(0.0) 1.0 This function should simply return the state with same shape as input t (i.e. as a list or an areray) """ # COMPLETE CODE import biolog biolog.info("Analytical function implemented") return 5-4*(np.exp(-2*t)) # the point . is to cast floats
def error(errors, n=0): """ Compute and return error This function should receive a vector of errors of same size as the time vector in the integration. It should return a single value based on these errors. The variable n can be optionally be used to implement different errors and compare them. """ # COMPLETE CODE biolog.info("Error computation code completed") mean_Err = np.abs(np.mean(errors)) print(mean_Err) return mean_Err
def hopf_ocillator(): """ 4a - Hopf oscillator simulation """ biolog.info("Hopf oscillator implemented") params = HopfParameters(mu=1., omega=1.0) time = np.arange(0, 30, 0.01) title = "Hopf oscillator {} (x0={})" label = ["x0", "x1"] x0_list = [[1e-3, 1e-3], [1.0, 1.0]] # x0 = x -direction, x-1 = y-direction for x0 in x0_list: hopf = integrate(hopf_equation, x0, time, args=(params, )) hopf.plot_state(title.format("state", x0), label) hopf_multiple = integrate_multiple( # to display different graphs on the same plot hopf_equation, x0_list, time, args=(params, )) hopf_multiple.plot_phase(title.format("phase", x0_list), label=label) return
def exercise1b(): """ Exercise 1 """ biolog.info("Executing Lab 4 : Exercise 1") parameters = PendulumParameters() ### With damping t_start = 0.0 t_stop = 10.0 dt = 0.05 biolog.warning("Using large time step dt={}".format(dt)) time = np.arange(t_start, t_stop, dt) parameters.b1 = 0.5 parameters.b2 = 0.5 x0 = [np.pi / 3, 0] biolog.info(parameters.showParameters()) res = integrate(pendulum_integration, x0, time, args=(parameters, )) res.plot_state("State")
def ode_integrate(fun, x0, time_max, time_step): """ Integrate function using Euler method - fun: Function df/dt = f(x, t) to integrate - x0: Initial state - time_tot: Total time to simulate [s] - time_step: Time step [s] Use odeint from the scipy library for integration Make sure to then use the Result class similarly to the example_integrate found above (i.e. Result(x, time)) """ time = np.arange(0, time_max, time_step) x = np.zeros([len(time), len(x0)]) x[0] = float(x0) x = odeint(fun, x0, time) biolog.info("ODE integration implemented") return Result(x, time)
def show_system_properties(self): """Function prints the system properties in the system. """ for sys in self.systems_list: if (sys == 'pendulum'): biolog.info(self.pendulum_sys.parameters.showParameters()) elif (sys == 'muscle'): biolog.info( self.muscle_sys.Muscle1.parameters.showParameters()) biolog.info( self.muscle_sys.Muscle2.parameters.showParameters()) elif (sys == 'neural'): biolog.info(self.neural_sys.parameters.showParameters())
def __init__(self, **kwargs): super(PendulumParameters, self).__init__('Pendulum') self.parameters = {} self.units = {} self.units['g'] = 'N-m/s2' self.units['L'] = 'm' self.units['sin'] = '' self.units['k1'] = 'N/rad' self.units['k2'] = 'N/rad' self.units['s_theta_ref1'] = 'rad' self.units['s_theta_ref2'] = 'rad' self.units['b1'] = 'N-s/rad' self.units['b2'] = 'N-s/rad' # Pendulum parameters self.parameters['g'] = kwargs.pop("g", 9.81) # Gravity constant self.parameters['L'] = kwargs.pop("L", 1.) # Length self.parameters['sin'] = kwargs.pop("sin", np.sin) # Sine function # Spring parameters self.parameters['k1'] = kwargs.pop( "k1", 500.) # Spring constant of Spring 1 self.parameters['k2'] = kwargs.pop( "k2", 500.) # Spring constant of Spring 2 self.parameters['s_theta_ref1'] = kwargs.pop( "s_theta_ref1", 0.0) # Spring 1 reference angle self.parameters['s_theta_ref2'] = kwargs.pop( "s_theta_ref2", 0.0) # Spring 2 reference angle # Damping parameters self.parameters['b1'] = kwargs.pop( "b1", 50.0) # Damping constant of Damper 1 self.parameters['b2'] = kwargs.pop( "b2", 5.0) # Damping constant of Damper 2 biolog.info(self) return
def exercise3(): """ Exercise 3 """ parameters = PendulumParameters() # Checkout pendulum.py for more info biolog.info(parameters) # Simulation parameters time = np.arange(0, 30, 0.01) # Simulation time x0 = [0.1, 0.0] # Initial state # To use/modify pendulum parameters (See PendulumParameters documentation): # parameters.g = 9.81 # Gravity constant # parameters.L = 1. # Length # parameters.d = 0.3 # damping # parameters.sin = np.sin # Sine function # parameters.dry = False # Use dry friction (True or False) # Example of system integration (Similar to lab1) # (NOTE: pendulum_equation must be imlpemented first) biolog.debug("Running integration example") res = integrate(pendulum_integration, x0, time, args=(parameters, )) res.plot_state("State") res.plot_phase("Phase") # Evolutions # Write code here (You can add functions for the different cases) biolog.warning( "Evolution of pendulum in normal conditions must be implemented") biolog.warning("Evolution of pendulum without damping must be implemented") biolog.warning( "Evolution of pendulum with perturbations must be implemented") biolog.warning( "Evolution of pendulum with dry friction must be implemented") # Show plots of all results if DEFAULT["save_figures"] is False: plt.show() return