示例#1
0
    def setUp(self):
        """Run repeated setup code once."""

        # Define class and local parameters
        unittest.TestCase.setUp(self)
        self.K_list = [3, 10, 99.21]
        self.tau_list = [0.3, 1]
        self.delay_list = [0.03, 0.1, 0.3]
        self.t_step = 0.01
        self.stop_time = 20.0
        self.input_val = 1.0
        self.t_step_ctrl = 0.1
        self.zeta = 0.7054  # air MFC damping ratio
        self.wn = 1.3501  # air MFC natural frequency, rad/s
        self.td = 1.8  # air MFC time delay, sec
        self.y0_1 = [0]
        self.y0_2 = [0] * 3  # for first-order model
        self.y0_3 = [0] * 4  # for second-order model
        A, B, self.C = sim_functions.get_state_matrices(
            self.K_list[1], self.tau_list[-1], self.delay_list[0])
        A2, B2, self.C2 = sim_functions.get_second_ord_matrices(
            self.K_list[-1], self.zeta, self.wn, self.td)
        self.Kp_list = [4.0, 5.0]
        self.mass_flow_des = [4.0, 2.0]
        self.std = 1.0
        self.Ks = 2.0  # filter static gain (?)
        Q = 1e-5 * np.identity(A2.shape[0])  # process noise covariance
        R = self.std  # measurement noise covariance
        self.P = Q  # initial estimate of error covariance
        self.offset = 0.0
        mean = 0.0

        # Define objects
        self.test_mfc1 = lab_hardware.MFC(
            lambda t, y, u: test_ode(t, y, u, self.K_list[1], self.tau_list[-1]
                                     ), lambda x: x[0], self.y0_1)
        self.test_mfc2 = lab_hardware.MFC(
            lambda t, y, u: sim_functions.system_state_update(t, y, u, A, B),
            lambda y: sim_functions.system_output(y, self.C), self.y0_2)
        self.test_mfc3 = lab_hardware.MFC(
            lambda t, y, u: sim_functions.system_state_update(t, y, u, A2, B2),
            lambda y: sim_functions.system_output(y, self.C2), self.y0_3)
        self.mfc_list = [
            lab_hardware.MFC(lambda t, y, u: test_ode(t, y, u, K, tau),
                             lambda x: x[0], self.y0_1)
            for K, tau in zip(self.K_list, self.tau_list)
        ]
        self.test_KF = lab_hardware.KalmanFilter(A2, B2, self.Ks * self.C2, Q,
                                                 R, self.P)
        self.test_sensor = lab_hardware.StaticSensor(
            lambda y: sim_functions.static_model(y, self.Ks, self.offset, mean,
                                                 self.std), 1.0)
示例#2
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 setUp(self):
   """Run repeated setup code once."""
   
   # Define class and local parameters
   unittest.TestCase.setUp(self)
   self.K_list = [3, 10, 99.21]
   self.tau_list = [0.3, 1]
   self.delay_list = [0.03, 0.1, 0.3]
   self.t_step = 0.01
   self.stop_time = 20.0
   self.input_val = 1.0
   self.t_step_ctrl = 0.1
   self.zeta = 0.7054  # air MFC damping ratio
   self.wn = 1.3501  # air MFC natural frequency, rad/s
   self.td = 1.8  # air MFC time delay, sec
   self.y0_1 = [0]
   self.y0_2 = [0] * 3  # for first-order model
   self.y0_3 = [0] * 4  # for second-order model
   A, B, self.C = sim_functions.get_state_matrices(self.K_list[1],
                                              self.tau_list[-1],
                                              self.delay_list[0])
   A2, B2, self.C2 = sim_functions.get_second_ord_matrices(self.K_list[-1],
                                                           self.zeta, self.wn,
                                                           self.td)
   self.Kp_list = [4.0, 5.0]
   self.mass_flow_des = [4.0, 2.0]
   self.std = 1.0
   self.Ks = 2.0  # filter static gain (?)
   Q = 1e-5 * np.identity(A2.shape[0])  # process noise covariance
   R = self.std  # measurement noise covariance
   self.P = Q  # initial estimate of error covariance
   self.offset = 0.0
   mean = 0.0
   
   # Define objects
   self.test_mfc1 = lab_hardware.MFC(lambda t, y, u: test_ode(t, y, u, self.K_list[1], self.tau_list[-1]),
                                     lambda x: x[0], self.y0_1)
   self.test_mfc2 = lab_hardware.MFC(lambda t, y, u: sim_functions.system_state_update(t, y, u, A, B),
                                     lambda y: sim_functions.system_output(y, self.C),
                                     self.y0_2)
   self.test_mfc3 = lab_hardware.MFC(lambda t, y, u: sim_functions.system_state_update(t, y, u, A2, B2),
                                     lambda y: sim_functions.system_output(y, self.C2),
                                     self.y0_3)
   self.mfc_list = [lab_hardware.MFC(lambda t, y, u: test_ode(t, y, u, K, tau),
                                     lambda x: x[0], self.y0_1)
                    for K, tau in zip(self.K_list, self.tau_list)]
   self.test_KF = lab_hardware.KalmanFilter(A2, B2, self.Ks * self.C2, Q, R, self.P)
   self.test_sensor = lab_hardware.StaticSensor(lambda y: sim_functions.static_model(y, self.Ks, self.offset, mean, self.std),
                                                1.0)
 def test_first_order_output(self):
   """Tests for system_output function for first order ODE."""
   
   # Define constants
   y_list = itertools.combinations_with_replacement([-1, 0, 1], 3)
   bad_y_list = [0, 1, -1, [1, 0], [0, 0], [1, 1, 1, 1]]
   K_list = [1, 3, 10]
   delay_list = [0, 0.1, 0.3, 1]
   mean_list = [0, 1, -1]
   std_list = [0.01, 0.03, 0.1, 0.3]
   param_list = set(itertools.chain(*[zip(K_list, x) for x in
                                      itertools.permutations(delay_list, len(K_list))]))
   noise_list = set(itertools.chain(*[zip(mean_list, x) for x in
                                      itertools.permutations(std_list, len(mean_list))]))
   
   # Test response of the output function
   for K, delay in param_list:
     C = np.array([[K, -K * delay / 2, K * delay ** 2 / 12]])
     for y in y_list:
       self.assertEqual(sim_functions.system_output(np.array(y), C)[0],
                        y[0] * K - y[1] * K * delay / 2 + y[2] * K * delay ** 2 / 12,
                        "Unexpected output function response for y={}, K={}, delay={}".format(y, K, delay))
       for mean, std in noise_list:  # test response with noise
         self.assertAlmostEqual(sim_functions.system_output(np.array(y), C, mean, std),
                                y[0] * K - y[1] * K * delay / 2 + y[2] * K * delay ** 2 / 12 + mean,
                                delta=4 * std,
                                msg="Output function response not within 4 std of expected.\nNote this may not be an error since ~0.01% of values lie outside of this range.")
   
   # Test that function raises TypeError for inputs of wrong dimension
   with self.assertRaises(TypeError):
     for y in bad_y_list:
       sim_functions.system_output(np.array(y), np.array([[1]]))
   
   # Test that non-ndarray inputs raise AttributeError
   with self.assertRaises(AttributeError):
     for y in bad_y_list:
       sim_functions.system_output(y, np.array([[1]]))
       sim_functions.system_output(np.array(y), 1)
       sim_functions.system_output(np.array(y), [1, 1])