示例#1
0
def run_simulation():
  """Run a simulation of the controller."""
  
  # Define system parameters
  p_atm = 14.0  # psi
  t_step = 0.01  # simulation time step, seconds
  t_step_ctrl = 0.1  # controller update rate, seconds
  K = 0.1  # static pressure sensor gain, V/psi (?)
  offset = 1.0  # static pressure sensor offset, V (?)
  K_mfcs = [99.21, 7.968, 8.007]  # MFC gains: [air, pilot, outer], SLPM/V
  zeta_mfcs = [0.7054, 0.6, 0.6]  # MFC damping ratios: [air, pilot, outer]
  wn_mfcs = [1.3501, 1, 1]  # MFC natural frequencies: [air, pilot, outer], rad/sec
  td_mfcs = [1.8, 0.139, 0.306]  # MFC time delays: [air, pilot, outer], sec
  K_mid = 7.964  # middle fuel MFC static gain, SLPM/V
  tau_mid = 0.516  # middle fuel MFC time constant, sec (first-order)
  td_mid = 0.194  # middle fuel MFC time delay, sec
  y0 = [0.0, 0.0, 0.0, 0.0]  # initial value, 2nd order sys with 3,2 order Pade approximation of time delay
  mfc_list = []
  control_law_list = []
  Q = np.ndarray([[100, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0] [0, 0, 0, 1]])
  R = np.ndarray([[1]])
  sensor_locations = [43.81, 76.2, 236.728, 609.6]  # dynamic P sensor locations from base, mm
    
  # Initialize sensor list
  sensor_list = [lab_hardware.StaticSensor(model=lambda y: sim_functions.static_model(y, K, offset),
                              location=0.0)]
  for loc in sensor_locations:
    sensor_list.append(lab_hardware.DynamicSensor(model=tf1, location=loc))
  # TODO figure out sensor transfer functions or models!
  
  # Initialize mass flow controller (MFC) list and control law list
  for K, zeta, wn, td in zip(K_mfcs, zeta_mfcs, wn_mfcs, td_mfcs):
    A, B, C = sim_functions.get_second_ord_matrices(K, zeta, wn, td)
    K_lqr = sim_functions.make_lqr_law(A, B, Q, R)
    mfc_list.append(lab_hardware.MFC(lambda t, y, u: sim_functions.system_state_update(t, y, u, A, B),
                                     lambda y: sim_functions.system_output(y, C),
                                     y0))
    control_law_list.append(lambda e:-K_lqr.dot(e))
    
  # Insert our first-order-modeled middle fuel MFC
  A, B, C = sim_functions.get_state_matrices(K_mid, tau_mid, td_mid)
  K_lqr = sim_functions.make_lqr_law(A, B, Q[:2, :2], R)  # smaller Q matrix, only 3 states
  mfc_list.insert(2, lab_hardware.MFC(lambda t, y, u: sim_functions.system_state_update(t, y, u, A, B),
                                     lambda y: sim_functions.system_output(y, C),
                                     y0[:2]))  # shorter y0, only 3 states
  control_law_list.insert(2, lambda e:-K_lqr.dot(e))
  
  # mfc and control law list should be in order: [air, pilot, middle, outer]
  # Initialize the combustor object
  combustor = lab_hardware.Combustor(p_atm, t_step, t_step_ctrl, sensor_list,
                                     mfc_list, control_law_list)
 def test_make_lqr_law(self):
   """Tests for make_lqr_law function."""
   
   # Define constants
   tau_list = [0.3, 1, 3]
   delay_list = [0.1, 0.3]
   param_list = set(itertools.chain(*[zip(tau_list, x) for x in
                                      itertools.permutations(delay_list, len(tau_list))]))
   Q = np.array([[100, 0, 0], [0, 1, 0], [0, 0, 1]])  # state error weight
   R = np.array([[1]])  # control effort weight
   
   for tau, delay in param_list:
     den = tau * delay ** 2
     A = np.array([[0, 1, 0], [0, 0, 1], [-12 / den, -(6 * delay + 12 * tau) / den, -(6 * tau + delay) / tau / delay]])
     B = np.array([[0], [0], [12 / den]])
     
     # Create control law
     K_lqr, _, eig_vals = sim_functions.make_lqr_law(A, B, Q, R)
     print(eig_vals)
   
     # Test return type
     self.assertIsInstance(K_lqr, np.ndarray,
                           "LQR law not returned as ndarray.")
     
     # Test return dimensions
     self.assertTupleEqual(K_lqr.shape, (1, 3),
                      "LQR law not the correct shape: {}, expected (1, 3).".format(K_lqr.shape))
     
     # Test that controlled system is stable
     self.assertTrue(all([np.real(item) < 0 for item in eig_vals]),
                     "All LQR-controlled poles not in left-half plane.")