def __init__(self, param, captive_dt=0.5): # Setup force model self.param = param self.force_model = ForceModel(param) self.drag_func = self.force_model.get_square_model() # Initialize External force function self.force_func = zero_force_func # Time step of realtime system integrating the measured forces self.captive_dt = captive_dt
def get_time_const(v0, param): """ Calculates the systems time constant as a function of the operating velocity. """ # Setup force model and predict gain and phase force_model = ForceModel(param) m = param.sub_body_mass + param.sub_mount_mass dummy, b = force_model.get_linear_coef(v0) return m / b
def __init__(self, param, inertial_dt=0.1, pgain=5.0): # Setup force model self.param = param self.force_model = ForceModel(param) self.drag_func = self.force_model.get_square_model() # Initialize External force function self.force_func = zero_force_func # Time step of realtime system integrating the measured forces self.inertial_dt = inertial_dt self.pgain = pgain
# -------------------------------------------------------------------------- # Part 1 Compute example bode plots for system frequency response as a # function of the operatiing point. Based on linearized force model. # -------------------------------------------------------------------------- # Test frequency range - f0 must be low enough that there is no phase shift f0 = 0.001 f1 = 10.0 # Test velocities num_test_v0 = 2 min_vel, max_vel = param.sub_velocity_range test_v0 = scipy.linspace(0.05 * max_vel, max_vel, num_test_v0) # Setup force model and predict gain and phase force_model = ForceModel(param) m = param.sub_body_mass + param.sub_mount_mass for i, v0 in enumerate(test_v0): # Compute the frequency response of the system dummy, b = force_model.get_linear_coef(v0) gain, phase, f = get_freq_response(f0, f1, m, b, n=10000) # Normalize gains - note, input and output don't have same units gain = gain - gain[0] # Plot results pylab.figure(1) pylab.subplot(211) pylab.semilogx(f, gain, label='v0 = %1.2f m/s' % (v0, ))
class CaptiveTrajSim(object): """ Encapsulates a simulation of a captive trajectory system modeling a the first order dynamics of the sled system. Simulates normal and captive trajectory system for comparison. System update_dt can be varied to determine the effect of the realtime system update interval. """ def __init__(self, param, captive_dt=0.5): # Setup force model self.param = param self.force_model = ForceModel(param) self.drag_func = self.force_model.get_square_model() # Initialize External force function self.force_func = zero_force_func # Time step of realtime system integrating the measured forces self.captive_dt = captive_dt def normal_system_func(self, v, t): """ Function governing normal system dynamics, i.e., f(v,t) where dv/dt = f(v,t). """ # Get mass and damping m = param.sub_body_mass + param.sub_mount_mass # Compute function value val = -scipy.sign(v) * self.drag_func(v) / m + self.force_func(v, t) / m return val def captive_system_func(self, v, t, v_cap): """ Function governing the captive trajectory system dynamics , i.e., f(v,t) where dv/dt = f(v,t). Note, In this case v is ignored and v_cap is used as the forces remain constant between realtime system updates. The system is simulated by running an odeint integration for the system evolution between every realtime system update. """ # Get mass and damping m = param.sub_body_mass + param.sub_mount_mass # Compute function value val = -scipy.sign(v_cap) * self.drag_func(v_cap) / m + self.force_func( v_cap, t) / m return val def run_normal(self, v0, T, num=1000): """ Runs a simulation of the system reponse to the external force function self.force_func. This is the normal system response - not the captive trajectory model. Inputs: v0 = initial velocity dt = sample interval for output values T = duration of simulation """ t = scipy.linspace(0, T, num) v = scipy.integrate.odeint(self.normal_system_func, v0, t) return t, v def run_captive(self, v0, T, num=100): """ Run a simulation of the captive trajectory system response to the external force function self.force_func. This is a prediction of the captive trajectory system response. v0 = """ t_curr = 0.0 v_curr = v0 t = [] v = [] while t_curr < T: # Integrate system forward to next realtime update t_next = t_curr + self.captive_dt if t_next > T: t_next = T t_sim = scipy.linspace(0, t_next - t_curr, num) v_sim = scipy.integrate.odeint(self.captive_system_func, v_curr, t_sim, args=(v_curr, )) # Add simulation segments to t and velcity lists t_sim = [val + t_curr for val in t_sim] t.extend(t_sim) v.extend(v_sim) # Update t_curr and v_curr t_curr = t_next v_curr = v_sim[-1] # Convert lists to arrays t = scipy.array(t) v = scipy.array(v) return t, v def get_verror_est(self, f0, f1, num=5): """ Get velocity error estimate as a function of the captive trajectory system update frequency. Note, the force_func must be set to something reasonable for this to work. A step function is a good choice. """ capt_f_array = scipy.linspace(f0, f1, num) capt_dt_array = 1.0 / capt_f_array verror_array = scipy.zeros(capt_dt_array.shape) for i, capt_dt in enumerate(capt_dt_array): # Run simulation for given captive trajectory update interval self.captive_dt = capt_dt v0 = 0.0 t_norm, v_norm = self.run_normal(v0, T, num=2000) t_capt, v_capt = self.run_captive(v0, T, num=100) # Interpolate normal trajectory onto captive trajectory time base v_norm = scipy.reshape(v_norm, t_norm.shape) v_capt = scipy.reshape(v_capt, t_capt.shape) interp_func = scipy.interpolate.interp1d(t_norm, v_norm) v_norm_interp = interp_func(t_capt) # Compute maximum absolute velocity error verror = scipy.absolute((v_capt - v_norm_interp)) verror_array[i] = verror.max() return capt_f_array, verror_array
'subject_1', 'subject_2', 'subject_3', 'subject_4', 'subject_5', 'subject_6', 'tau_1_rest+1STD', 'tau_1_rest+2STD', 'tau_1_rest+3STD', 'tau_2-1STD', 'tau_2-2STD', 'tau_2+1STD', 'tau_2+2STD', 'tau_fat+1STD', 'tau_fat+2STD', 'tau_fat-1STD', 'tau_fat-2STD'] SUB_FOLDER = 'sensitivity_analysis/' CONFIG_FOLDER = 'configs/' validated_configuration = 'model_configuration.csv' total_time = (0 * 1000, 230 * 1000) validation_train = get_validation_train() config = load_model_configuration(validated_configuration) tau_c, tau_2, tau_fat, alpha_scale_factor, alpha_Km, alpha_tau_1, \ CN0, F0, scale_factor_rest, tau_1_rest, Km_rest = config.values() validated_force_model = ForceModel(scale_factor_rest, Km_rest, tau_1_rest, tau_2) validated_initial_state = [CN0, F0, scale_factor_rest, Km_rest, tau_1_rest] V_CN, V_F, V_A, V_Km, V_tau_1, V_t = simulate(validated_force_model, total_time, validation_train, validated_initial_state, tau_c, tau_fat, alpha_scale_factor, alpha_Km, alpha_tau_1) V_t = V_t / 1000 validated_f60_time = V_t[np.where(V_t <= 60)] validated_f60_data = V_F[np.where(V_t <= 60)] validated_l60_time = V_t[np.logical_and(170 <= V_t, V_t <= 230)] validated_l60_data = V_F[np.logical_and(170 <= V_t, V_t <= 230)] for CONFIG in CONFIGS: config = load_model_configuration(SUB_FOLDER + CONFIG_FOLDER + CONFIG + '.csv') tau_c, tau_2, tau_fat, alpha_scale_factor, alpha_Km, alpha_tau_1, \ CN0, F0, scale_factor_rest, tau_1_rest, Km_rest = config.values()
class InertialSledSim(object): """ Encapsulates a simulation of the inertial sled system. A PID controller is used to try and keep the sled in position with the model. """ def __init__(self, param, inertial_dt=0.1, pgain=5.0): # Setup force model self.param = param self.force_model = ForceModel(param) self.drag_func = self.force_model.get_square_model() # Initialize External force function self.force_func = zero_force_func # Time step of realtime system integrating the measured forces self.inertial_dt = inertial_dt self.pgain = pgain def normal_system_func(self, w, t): """ Function governing normal system dynamics. Basic second order system with square law fluid dynamic drag. """ v = w[0] x = w[1] m = param.sub_body_mass + param.sub_mount_mass dvdt = -scipy.sign(v) * self.drag_func(v) / m + self.force_func(v, t) / m dxdt = v return scipy.array([dvdt, dxdt]) def inertial_system_func(self, x, t, vel_setpt): """ Function governing the dynamics of the sled system. We are setting sled velocity so this is first order in position. Currenlty doesn't incorporate sled/controller dynamics assumes we can control the sleds velocity with reasonable accuracy. Will need to add sled + controller dynamics later. Currently, just integration of the velocity setput. """ dx = vel_setpt return dx def run_normal(self, x0, v0, T, num=100): """ Runs a simulation of the system reponse to the external force function self.force_func. This is the normal system response - not the captive trajectory model. """ w0 = scipy.array([v0, x0]) t = scipy.linspace(0, T, num) w = scipy.integrate.odeint(self.normal_system_func, w0, t) x = w[:, 1] v = w[:, 0] return t, x, v def run_inertial(self, x0, v0, t_sled, x_sled, v_sled, T, num=30): """ Run a simulation of inertial sled system. Used a proportional controller with feed forward velocity term. """ t_sled = t_sled - t_sled[0] x_sled_func = scipy.interpolate.interp1d(t_sled, x_sled) v_sled_func = scipy.interpolate.interp1d(t_sled, v_sled) t_curr = 0.0 x_curr = x0 v_setpt = v0 t = [] x = [] v = [] while t_curr < T: # Update velocity set point x_error = x_sled_func(t_curr) - x_curr v_setpt = self.pgain * x_error + v_sled_func(t_curr) t_next = t_curr + self.inertial_dt if t_next > T: t_next = T t_sim = scipy.linspace(0, t_next - t_curr, num) x_sim = scipy.integrate.odeint(self.inertial_system_func, x_curr, t_sim, args=(v_setpt, )) # Add simulation segments to t and velcity lists N = t_sim.shape[0] t_sim = [val + t_curr for val in t_sim] t.extend(list(t_sim)) v.extend(list(v_setpt * scipy.ones((N, )))) x.extend(list(x_sim)) # Update t_curr and v_curr t_curr = t_next x_curr = x_sim[-1] # Convert lists to arrays t = scipy.array(t) x = scipy.array(x) v = scipy.array(v) return t, x, v def get_perror_est(self, f0, f1, num=5): """ Computes the maximum absolute positon error over a range of realtime loop update frequencies form f0 to f1 with the number of step given by num. """ f_array = scipy.linspace(f0, f1, num) dt_array = 1.0 / f_array perror_array = scipy.zeros(f_array.shape) for i, dt in enumerate(dt_array): print 'f: ', 1.0 / dt # Run simulation for given realtime loop update interval self.inertial_dt = dt x0 = 0.0 v0 = 0.0 t_model, x_model, v_model = self.run_normal(x0, v0, T, num=1000) t_sled, x_sled, v_sled = self.run_inertial(x0, v0, t_model, x_model, v_model, T) # Interpolate normal trajectory onto captive trajectory time base x_model = scipy.reshape(x_model, t_model.shape) x_sled = scipy.reshape(x_sled, t_sled.shape) interp_func = scipy.interpolate.interp1d(t_model, x_model) x_model_interp = interp_func(t_sled) # Compute maximum absolute velocity error perror = scipy.absolute((x_sled - x_model_interp)) perror_array[i] = perror.max() return f_array, perror_array