def long_modes(aircraft, x_0, u_0): """longitudinal mode calculations.""" j = aircraft['weight']['inertia'] m = aircraft['weight']['weight'] / g # [slug] x_ss = [0, 2, 4, 7] a, b, c, d = nonlinear_eom_to_ss(aircraft, x_ss, [1], x_0, u_0, m, j) sys = StateSpace(a, b, c, d) wn, zeta, poles = damp(sys) wn_sp = unique(max(wn)) zeta_sp = unique(zeta[wn == wn_sp]) wn_ph = unique(min(wn)) zeta_ph = unique(zeta[wn == wn_ph]) return wn_sp, zeta_sp, wn_ph, zeta_ph
def latdir_modes(aircraft, x_0, u_0): """calculate lateral-directional modal parameters.""" j = aircraft['weight']['inertia'] m = aircraft['weight']['weight'] / g # slug # x = [u v w phi theta psi p q r p_n p_e h] x_ss = [1, 3, 6, 8] a, b, c, d = nonlinear_eom_to_ss(aircraft, x_ss, [0, 2], x_0, u_0, m, j) sys = StateSpace(a, b, c, d) wn, zeta, poles = damp(sys) wn_dr = unique(max(wn[abs(zeta) != 1])) # [rad/s] zeta_dr = unique(max(zeta[wn == wn_dr])) # [] re = real(poles) t = unique(re[abs(zeta) == 1]) if len(t) == 2: t_r = -1 / min(t) t_s = -1 / max(t) else: t_r = float("nan") t_s = float("nan") return wn_dr, zeta_dr, t_r, t_s
def step_info(sysc): wn, damping, poles = ct.damp(sysc, doprint=False) z = damping[0] wn = wn[0] wd = wn * m.sqrt(1 - (z)**2) theta = m.atan(m.sqrt(1 - (z)**2) / (z)) tr = (m.pi - theta) / wd print('RiseTime:', format(tr, '.4f')) ts = 4 / ((z) * (wn)) print('SettlingTime:', format(ts, '.4f')) Mp = (m.exp(-z * m.pi / m.sqrt(1 - (z)**2))) * 100 print('Overshoot:', format(Mp, '.4f'), '%') tp = m.pi / wd print('PeakTime:', format(tp, '.4f')) print('') print('') return
u = np.array([dutch[4], dutch[5]]) #Calculate response to arbitrary input t, y, x = control.forced_response(system, dutch[0], u, dutch[6], transpose=False) #Change dimensionless pb/(2V) and rb/(2V) to p and r y[1, :] = -y[1, :] + 2 * y[1, 0] y[2, :] = -(2 * abs(V0) * y[2, :] / b) + 2 * y[2, 0] y[3, :] = -(2 * abs(V0) * y[3, :] / b) + 2 * y[3, 0] control.damp(system, doprint=True) fig = plt.figure(figsize=(12, 9)) fig.suptitle('Dutch Roll', fontsize=16) ax1 = fig.add_subplot(221) ax1.plot(t, y[0, :], label='Simulated response') ax1.plot(t, dutch[8], label='Test Flight Data Response', color='tab:orange', linestyle='--') ax1.legend() ax1.set_xlabel("Time [s]") ax1.set_ylabel("beta (yaw angle) [deg]") ax1.grid()
#--------------------------------------------------------- #---------------------Phugoid------------------------------ #Short, sharp deflection followed by a return to the centered position #xinit = np.array([Vtrue[25360]*np.cos(vane_AOA[25360]*(np.pi/180)), vane_AOA[25360]*(np.pi/180), pitch[25360]*(np.pi/180), pitch_rate[25360]*(np.pi/180)]) xinit = np.array([0,0,0,0]) Udeltae = deltae[25360:26910]*(np.pi/180) #Generating an output vector with velocity C = np.array([[1,0,0,0]]) D = np.array([[0]]) sys = ctrl.ss(A_sym,B_sym,C,D) ctrl.damp(sys) T, u_sim, xout = ctrl.forced_response(sys, T=np.arange(0,155,0.1), U=Udeltae.T, X0=xinit) u_sim = u_sim + Vtrue[25360]*np.cos(vane_AOA[25360]*(np.pi/180)) #For the initial condition #Generating an output vector with angle of attack C = np.array([[0,1,0,0]]) D = np.array([[0]]) sys = ctrl.ss(A_sym,B_sym,C,D) T, aoa_sim, xout = ctrl.forced_response(sys, T=np.arange(0,155,0.1), U=Udeltae.T, X0=xinit) aoa_sim = aoa_sim + vane_AOA[25360]*(np.pi/180) #For the initial condition #Generating an output vector with pitch angle
import matplotlib.pyplot as plt from scipy import signal from matplotlib.ticker import (MultipleLocator) Gp = ct.tf(100, [1, 0, 100]) ts = 0.05 Gz = ct.sample_system(Gp, ts) sym.pprint(Gz) t = np.arange(0.0, 50 * ts, ts) (num, den) = ct.tfdata(Gp) ## por que GP???? lsim no funciona con Gz num = np.array(num) ##np.asarray hace lo mismo convierte tuple/list a array den = np.array(den) num = num.flatten() den = den.flatten() do = ct.damp( Gz, doprint=True ) ##damp me devuelve en vez de un vector, un tuple (parecido a una matriz) que contiene todos los datos sys = signal.lti( num, den) ##transformo Gp en lti que es lo que acepta la syntax de lsim wn = do[ 0] ## 0 contiene wn, 1 contiene damping, 2 contiene eigen de los dos polos x = np.sin(wn[0] * t) ##escojo el valor de wn de un polo fig, ax = plt.subplots() tout, a, b = signal.lsim(sys, x, t) plt.plot(t, x) plt.step(t, a) plt.show()
t_function = con.tf(num, den) #linear simulation we can see a response to input of system #we need u(t)= input of system and x(t) inicial condition # u =! 0 and x == 0 homogeny solucion # u == 0 and x =! 0 forced solution # u =! 0 and x =! 0 full solution #plot response sys_state = con.ss(a, b, c, d) time_simulation = np.arange(0, 30, 0.01, dtype=float) #time start 0 input_u = 2 * np.ones(np.size(time_simulation)) #input of 2 volts start_condition = np.array([[1], [0]]) t, y_out, x_out = con.forced_response(sys_state, time_simulation, input_u, start_condition) [wn, zetas, poles] = con.damp(sys_state) #t,y_out, = con.initial_response(sys_state,time_simulation,start_condition) [time2, yout2] = con.step_response(t_function, time_simulation, start_condition) plt.figure(1) plt.plot(time2, yout2, 'r') plt.xlabel('time') plt.ylabel('volts') plt.figure(2) plt.plot(t, y_out, 'b*', t, input_u, 'g-') #ploting time x output and time x input plt.xlabel('time') plt.ylabel('volts') plt.show()
def compute_assymetric_ss_representation_error(self, stability_coeffs_array): """ :param stability_coeffs_array: [Cnb, Cnr, CYb] :return: """ forced_response_inputs = self.maneuver_vals() # spiral = maneuver_vals(3305, 30, 'Spiral') # aperiodic = maneuver_vals(3380, 30, 'Aperiodic') g = 9.80665 # State-space representation of asymmetric EOM: V0 = forced_response_inputs[7] mub, muc, m, h, rho = self.get_flight_conditions() mub = float(mub[0]) muc = float(muc[0]) m = float(m[0]) h = float(h[0]) rho = float(rho[0]) CX0 = m * g * sin(forced_response_inputs[3][0] * np.pi / 180.0) / (0.5 * rho * (V0 ** 2) * S) CZ0 = -m * g * cos(forced_response_inputs[3][0] * np.pi / 180.0) / (0.5 * rho * (V0 ** 2) * S) c = 2.0569 C1 = np.array([[(CYbdot - 2.0 * mub) * b / V0, 0.0, 0.0, 0.0], [0.0, -0.5 * b / V0, 0.0, 0.0], [0.0, 0.0, -4.0 * mub * KX2 * b / V0, 4.0 * mub * KXZ * b / V0], [Cnbdot * b / V0, 0.0, 4.0 * mub * KXZ * b / V0, -4.0 * mub * KZ2 * b / V0]]) C2 = np.array([[-stability_coeffs_array[2], -CL, -CYp, -(CYr - 4.0 * mub)], [0.0, 0.0, -1.0, 0.0], [-Clb, 0.0, -Clp, -Clr], [-stability_coeffs_array[0], 0.0, -Cnp, -stability_coeffs_array[1]]]) C3 = np.array([[-CYda, -CYdr], [0.0, 0.0], [-Clda, -Cldr], [-Cnda, -Cndr]]) A = np.matmul(np.linalg.inv(C1), C2) B = np.matmul(np.linalg.inv(C1), C3) C = np.identity(4) # y = x, meaning we output the state D = np.array([[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]) # Make control.ss state-space system = control.ss(A, B, C, D) # t = np.linspace(0.0, 200.0, num = 201) # Input: # u = np.zeros((2, t.shape[0])) # for i in range(t.shape[0]): # u[0, i] = da[i] #Insert magnitude of "da" (aileron deflection) or comment out if none # u[1, i] = dr[i] #Insert magnitude of "dr" (rudder deflection) or comment out if none u = np.array([forced_response_inputs[4], forced_response_inputs[5]]) # Calculate response to arbitrary input t, y, x = control.forced_response(system, forced_response_inputs[0], u, forced_response_inputs[6], transpose=False) # Change dimensionless pb/(2V) and rb/(2V) to p and r y[1, :] = -y[1, :] + 2 * y[1, 0] y[2, :] = -(2 * abs(V0) * y[2, :] / b) + 2 * y[2, 0] y[3, :] = -(2 * abs(V0) * y[3, :] / b) + 2 * y[3, 0] control.damp(system, doprint=True) eigen_motion_error_beta = self.L2error(forced_response_inputs[8], y[0, :]) eigen_motion_error_phi = self.L2error(forced_response_inputs[1], y[1, :]) eigen_motion_error_p = self.L2error(forced_response_inputs[2], y[2, :]) eigen_motion_error_r = self.L2error(forced_response_inputs[3], y[3, :]) avg_eigen_motion_error = (eigen_motion_error_beta + eigen_motion_error_p + eigen_motion_error_phi + eigen_motion_error_r) / 4.0 print("The Average Error Computed for the {0} is: {1}".format(self.maneuver_name, avg_eigen_motion_error)) return avg_eigen_motion_error
def create_assymetric_ss_representation(self): forced_response_inputs = self.maneuver_vals() g = 9.80665 # DUTCH ROLL: # State-space representation of asymmetric EOM: # C1*x' + C2*x + C3*u = 0 V0 = forced_response_inputs[7] mub, muc, m, h, rho = self.get_flight_conditions() mub = float(mub[0]) muc = float(muc[0]) m = float(m[0]) h = float(h[0]) rho = float(rho[0]) CX0 = m * g * sin(forced_response_inputs[3][0] * np.pi / 180.0) / (0.5 * rho * (V0 ** 2) * S) CZ0 = -m * g * cos(forced_response_inputs[3][0] * np.pi / 180.0) / (0.5 * rho * (V0 ** 2) * S) c = 2.0569 C1 = np.array([[(CYbdot - 2.0 * mub) * b / V0, 0.0, 0.0, 0.0], [0.0, -0.5 * b / V0, 0.0, 0.0], [0.0, 0.0, -4.0 * mub * KX2 * b / V0, 4.0 * mub * KXZ * b / V0], [Cnbdot * b / V0, 0.0, 4.0 * mub * KXZ * b / V0, -4.0 * mub * KZ2 * b / V0]]) C2 = np.array([[-CYb, -CL, -CYp, -(CYr - 4.0 * mub)], [0.0, 0.0, -1.0, 0.0], [-Clb, 0.0, -Clp, -Clr], [-Cnb, 0.0, -Cnp, -Cnr]]) C3 = np.array([[-CYda, -CYdr], [0.0, 0.0], [-Clda, -Cldr], [-Cnda, -Cndr]]) # x' = A*x + B*u # y = C*x + D*u # now u = [da] # [dr] A = np.matmul(np.linalg.inv(C1), C2) B = np.matmul(np.linalg.inv(C1), C3) C = np.identity(4) # y = x, meaning we output the state D = np.array([[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]) # Make control.ss state-space system = control.ss(A, B, C, D) # t = np.linspace(0.0, 200.0, num = 201) # Input: # u = np.zeros((2, t.shape[0])) # for i in range(t.shape[0]): # u[0, i] = da[i] #Insert magnitude of "da" (aileron deflection) or comment out if none # u[1, i] = dr[i] #Insert magnitude of "dr" (rudder deflection) or comment out if none u = np.array([forced_response_inputs[4], forced_response_inputs[5]]) # Calculate response to arbitrary input t, y, x = control.forced_response(system, forced_response_inputs[0], u, forced_response_inputs[6], transpose=False) # Change dimensionless pb/(2V) and rb/(2V) to p and r y[1, :] = -y[1, :] + 2 * y[1, 0] y[2, :] = -(2 * abs(V0) * y[2, :] / b) + 2 * y[2, 0] y[3, :] = -(2 * abs(V0) * y[3, :] / b) + 2 * y[3, 0] control.damp(system, doprint=True) fig = plt.figure(figsize=(12, 9)) # fig.suptitle(self.maneuver_name, fontsize=16, ) ax1 = fig.add_subplot(221) ax1.plot(t, y[0, :], label='Simulated response') ax1.plot(t, forced_response_inputs[8], label='Test Flight Data Response', color='tab:orange', linestyle='--') ax1.legend(loc='upper right') ax1.set_xlabel("Time [s]") ax1.set_ylabel("beta (yaw angle) [deg]") print("{0} Error in Beta:".format(self.maneuver_name)) eigen_motion_error_beta = self.L2error(forced_response_inputs[8], y[0, :]) print(eigen_motion_error_beta) plt.grid("True") ax2 = fig.add_subplot(222) ax2.plot(t, y[1, :], label='Simulated response') ax2.plot(t, forced_response_inputs[1], label='Test Flight Data Response', color='tab:orange', linestyle='--') ax2.legend(loc='upper right') ax2.set_xlabel("Time [s]") ax2.set_ylabel("phi (roll angle) [deg]") print("{0} Error in Phi:".format(self.maneuver_name)) eigen_motion_error_phi = self.L2error(forced_response_inputs[1], y[1, :]) print(eigen_motion_error_phi) plt.grid("True") ax3 = fig.add_subplot(223) ax3.plot(t, y[2, :], label='Simulated response') ax3.plot(t, forced_response_inputs[2], label='Test Flight Data Response', color='tab:orange', linestyle='--') ax3.legend(loc='upper right') ax3.set_xlabel("Time [s]") ax3.set_ylabel("p (roll rate) [deg/sec]") print("{0} Error in p:".format(self.maneuver_name)) eigen_motion_error_p = self.L2error(forced_response_inputs[2], y[2, :]) print(eigen_motion_error_p) plt.grid("True") ax4 = fig.add_subplot(224) ax4.plot(t, y[3, :], label='Simulated response') ax4.plot(t, forced_response_inputs[3], label='Test Flight Data Response', color='tab:orange', linestyle='--') ax4.legend(loc='upper right') ax4.set_xlabel("Time [s]") ax4.set_ylabel("r (yaw rate) [deg/s]") print("{0} Error in r:".format(self.maneuver_name)) eigen_motion_error_r = self.L2error(forced_response_inputs[3], y[3, :]) print(eigen_motion_error_r) plt.grid("True") print("Avg. {0} Error:".format(self.maneuver_name)) avg_eigen_motion_error = (eigen_motion_error_beta + eigen_motion_error_p + eigen_motion_error_phi + eigen_motion_error_r) / 4.0 print(avg_eigen_motion_error) # plt.grid("True") plt.show()