def test_solve(): u = [0, 0, 0, 0] scenario = DoublePendulum(1, 1, 1, 1) t, theta1, omega1, theta2, omega2 = scenario.solve(u, 10, 1e-3) assert mean(theta1) <= 1e-6, ( f"Mean Theta is not zero when start values for Omega and Theta is zero" f", Mean Omega is {theta1}") assert mean(omega1) <= 1e-6, ( f"Mean Omega is not zero when start values for Omega and Theta is zero" f", Mean Omega is {omega1}") assert mean(theta2) <= 1e-6, ( f"Mean Theta is not zero when start values for Omega and Theta is zero" f", Mean Omega is {theta2}") assert mean(omega2) <= 1e-6, ( f"Mean Omega is not zero when start values for Omega and Theta is zero" f", Mean Omega is {omega2}") t, theta1, omega1, theta2, omega2 = scenario.solve(u, 10, 1e-3, "deg") assert mean(theta1) <= 1e-6, ( f"Mean Theta is not zero when start values for Omega and Theta is zero" f", Mean Omega is {theta1}") assert mean(omega1) <= 1e-6, ( f"Mean Omega is not zero when start values for Omega and Theta is zero" f", Mean Omega is {omega1}") assert mean(theta2) <= 1e-6, ( f"Mean Theta is not zero when start values for Omega and Theta is zero" f", Mean Omega is {theta2}") assert mean(omega2) <= 1e-6, ( f"Mean Omega is not zero when start values for Omega and Theta is zero" f", Mean Omega is {omega2}")
def test_DoublePendulumCartesian(): """Checks if the cartesian coordinates are correct.""" p = DoublePendulum(M1 = 2, L1 = 1.1, M2 = 0.5, L2 = 2.3) p.solve((np.pi/4, 0.1, np.pi/8, 0.2),10,0.1) for i in range(len(p.x1)): nt.assert_almost_equals(p.x1[i]**2 + p.y1[i]**2, 1.1**2) for i in range(len(p.x2)): nt.assert_almost_equals((p.x2[i] - p.x1[i])**2 + (p.y2[i] - p.y1[i])**2, 2.3**2)
def test_arrays_zero(): ''' test-function for checking if initial conditions y0=(0,0) yields zero-filled arrays ''' a = DoublePendulum() a.solve((0.0, 0, 0.0, 0), 10, 1001) assert np.all(a.theta1 == 0) and np.all(a.theta2 == 0), \ 'initial conditions y0=(0,0) does not yield arrays with zeros'
def test_DoublePendulum_zeroes_as_y0(): y0 = (0 ,0 ,0 , 0) obj = DoublePendulum() obj.solve(y0, 5, 0.0001) y = obj.y for i in y: assert all(i == 0), "all vals in y is not zero when they should be"
def test_DoublePendulum_null_mass(): obj = DoublePendulum(M1=1e-15, M2=1e-15) y0 = (1 ,1 ,1 , 1) obj.solve(y0, 5, 1e-4) K = obj.kinetic P = obj.potential eps = 1e-13 print(max(K), max(P)) assert all(abs(K) < eps) and all(abs(P) < eps)
def test_solve(): T = 10 dt = 0.1 pend = DoublePendulum() pend.solve([0.0, 0.0, 0.0, 0.0], T, dt, angles = "deg") t_act = np.linspace(0, T, int(T/dt)) print(pend.t) for i in range(len(t_act)): nt.assert_equal(pend.theta1[i], 0.) nt.assert_equal(pend.theta2[i], 0.) nt.assert_equal(pend.t[i], t_act[i])
def test_zeroes(): """Test if solved values are zeroes if initial state is stationary.""" var = DoublePendulum(2, 2, 2, 2) T = 5 dt = 0.1 var.solve((0, 0, 0, 0), T, dt) time = linspace(0, T, T / dt + 1) nt.assert_equal(time.all(), var.t.all()) nt.assert_equal(0, var.theta1.all()) nt.assert_equal(0, var.theta2.all()) nt.assert_equal(0, var.omega1.all()) nt.assert_equal(0, var.omega2.all())
def test_double_pendulum_total_energy(): double_pendulumtest = DoublePendulum() theta1 = np.pi/3; theta2 = 3*np.pi/2 omega1 = 0.15; omega2 = 0.075 T = 40 dt = 1e-3 eps = 0.2 double_pendulumtest.solve((theta1,omega1,theta2,omega2),T,dt) kinetic = double_pendulumtest.kinetic potential = double_pendulumtest.potential total_energy = kinetic[0] + potential[0] for i,j in zip(kinetic,potential): assert abs(i+j-total_energy) < eps """
def test_double_pendulum_solve_zero(): """Check if start in rest ((angle, angular vel) == (0,0)) returns zeros.""" test_T = 5 test_dt = 0.1 test_pend = DoublePendulum(L1=5, L2=5) test_pend.solve((0, 0, 0, 0), test_T, test_dt) test_ts = np.linspace(0, test_T, test_T/test_dt) test_zeros = np.zeros(int(test_T/test_dt)) np.testing.assert_array_equal(test_pend.t, test_ts) np.testing.assert_array_equal(test_pend.theta1, test_zeros) np.testing.assert_array_equal(test_pend.theta2, test_zeros)
def test_double_pendulum_initial_sol(): double_pendulumtest = DoublePendulum() T = 100 dt = 0.1 eps = 1e-15 t_values = np.linspace(0,T,int(T/dt)) double_pendulumtest.solve((0,0,0,0),T,dt) t = double_pendulumtest.t theta1 = double_pendulumtest.theta1; theta2 = double_pendulumtest.theta2 omega1 = double_pendulumtest.omega1; omega2 = double_pendulumtest.omega2 #Tests: for i in range(len(t)): assert t[i] == t_values[i] for i,j,k,l in zip(theta1,omega1,theta2,omega2): assert abs(i) < eps assert abs(j) < eps assert abs(k) < eps assert abs(l) < eps
def test_dopuble_pendulum_xy_transformation(): """Check if motion is transformed to xy-coordinates.""" test_T = 5 test_dt = 0.1 test_L1 = 2 test_L2 = 5 test_pend = DoublePendulum(L1=test_L1, L2=test_L2) test_pend.solve((pi/2, 0, pi, 0), test_T, test_dt) test_L1_squared = (test_pend.x1)**2 + (test_pend.y1)**2 test_L2_squared = ((test_pend.x2 - test_pend.x1)**2 + (test_pend.y2 - test_pend.y1)**2) ex_L1_quared = test_L1**2 ex_L2_quared = test_L2**2 np.testing.assert_array_almost_equal(test_L1_squared, ex_L1_quared) np.testing.assert_array_almost_equal(test_L2_squared, ex_L2_quared)
def test_double_pendulum_angles(): L = 2.4 theta1 = np.pi/4; theta2 = np.pi omega1 = 0.2; omega2 = 0.01 T = 50 dt = 1e-3 example1 = DoublePendulum(L) example1.solve((theta1,omega1,theta2,omega2),T,dt) theta1 = 45; theta2 = 180 example2 = DoublePendulum(L) example2.solve((theta1,omega1,theta2,omega2),T,dt,angles = 'deg') kinetic1 = example1.kinetic; kinetic2 = example2.kinetic potential1 = example1.potential; potential2 = example2.potential for i,j,k,l in zip(kinetic1,potential1,kinetic2,potential2): assert i == k assert j == l
def test_properties_zeros(): scenario = DoublePendulum(1, 1, 1, 1) t, theta1, omega1, theta2, omega2 = scenario.solve([0, 0, 0, 0], 10, 1e-3) tt = linspace(0, 10, 10004) zeroo = zeros(len(theta1)) assert mean(theta1) == mean( zeroo), "theta1 set to zeros did not yield zeros array" assert mean(theta2) == mean( zeroo), "theta2 set to zeros did not yield zeros array" assert (abs(mean(t) - mean(tt)) < 1e-2), "t was not equal to linspace(0,T,dt)"
def test_radius1(): a = DoublePendulum() a.solve((0, 0.1, 3, 0.5), 10, 101) r2 = a.x1**2 + a.y1**2 assert np.isclose(1**2, np.all(r2))
class Simulation: def __init__(self, res, fps, time, dt, scale, speed, path_depth, ag, mass, length, theta, d_theta): self.running = False # Simulation not started yet at this point # Setting simulation variables self.width, self.height = res self.fps = fps self.time, self.dt = time, dt self.points_count = self.time / self.dt self.scale = scale self.speed = speed self.path_depth = path_depth self.path = [] # Setting variables for solve method. self.time_range = np.arange(0, self.time + self.dt, self.dt) # Range of time points self.ag = ag # Gravitational acceleration # Creating display and pendulum objects; Solving equations self.pendulum = DoublePendulum(mass, length, theta, d_theta) self.pendulum.solve(self.time_range, self.ag) self.display = Display(res) def run(self): """ Simulation loop. """ # Start the simulation self.running = True i = 0 # Iterable for simulation frames di = int((1 / self.fps / self.dt) * self.speed) # Step size based on time density and frame rate # Loop while self.running: # Getting start point and all of the pendulum positions x_start, y_start = (int(self.width / 2), int(self.height / 3)) x_1_scaled, y_1_scaled, x_2_scaled, y_2_scaled = self.pendulum.get_scaled_positions( i, self.scale) start_pos = (x_start, y_start) x_1_pos = (x_start + x_1_scaled, y_start - y_1_scaled) x_2_pos = (x_start + x_2_scaled, y_start - y_2_scaled) # Getting raw positions and velocities to show live info x_1_raw, y_1_raw, x_2_raw, y_2_raw = self.pendulum.get_positions(i) angle_1, angle_2 = self.pendulum.get_angles(i) velocity_1, velocity_2 = self.pendulum.get_angular_velocities(i) # Setting strings ready to be drawn on display info_str = 'Mass {} X: {:05.2f}m, Y: {:05.2f}m, Angle: {:05.1f}deg, Velocity: {:06.1f}deg/s' m_1_info_str = info_str.format(1, x_1_raw, y_1_raw, angle_1 % 360, velocity_1) m_2_info_str = info_str.format(2, x_2_raw, y_2_raw, angle_2 % 360, velocity_2) # Drawing rods self.display.draw_rod(start_pos, x_1_pos) self.display.draw_rod(x_1_pos, x_2_pos) self.display.draw_path(self.path, self.path_depth) # Drawing path # Drawing bodies self.display.draw_body(x_1_pos) self.display.draw_body(x_2_pos) # Drawing live info self.display.draw_info(m_1_info_str, (10, 10)) self.display.draw_info(m_2_info_str, (10, 38)) # Handling events and transition into next iteration self.display.next_frame(int(1000 / self.fps)) self.display.handle_events() # Inserting current second pendulum position into path self.path.append(x_2_pos) # Iterating and stopping the simulation at the end of solved time range i += di if i > self.points_count: self.running = False