diff --git a/main_animate.py b/main_animate.py new file mode 100644 index 0000000000000000000000000000000000000000..f5d51fdcb3f6db36f7051ff992582f82ddeaf1af --- /dev/null +++ b/main_animate.py @@ -0,0 +1,174 @@ +import math +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.animation import FuncAnimation + + +ani = None +saved = False + + +def acc_model_simple(v, v1=0.3, a0=0.2, ap=0.1, am=0.2): + """ + naive model of a motor acceleration bound as a function of its current speed + + inputs: position vector v + returns: positive and negative accelerations + """ + n = len(v) + a_minus = np.zeros((n,)) + a_plus = np.zeros((n,)) + alpha1 = np.minimum(v[v > 0] / v1, 1) + alpha2 = np.minimum(-v[v <= 0] / v1, 1) + a_minus[v > 0] = -(alpha1 * am + (1 - alpha1) * a0) + a_plus[v > 0] = alpha1 * ap + (1 - alpha1) * a0 + a_minus[v <= 0] = -(alpha2 * ap + (1 - alpha2) * a0) + a_plus[v <= 0] = alpha2 * am + (1 - alpha2) * a0 + return a_minus, a_plus + + +def constraint_a(x, v, acc_model, jerk_max=0.5): + """ + inputs: position vector x, speed vector v + returns: min. and max. acceleration for each segment + """ + x_delta = x[1:] - x[:-1] + x_mid = (x[:-1] + x[1:]) * 0.5 + v_mid = (v[:-1] + v[1:]) * 0.5 + t_delta = x_delta / v_mid + a = (v[1:] - v[:-1]) / t_delta + t_delta_a = (t_delta[:-1] + t_delta[1:]) * 0.5 + + a_max_next = a[:-1] + jerk_max * t_delta_a + a_min_next = a[:-1] - jerk_max * t_delta_a + a_max_prev = a[1:] + jerk_max * t_delta_a + a_min_prev = a[1:] - jerk_max * t_delta_a + a_min = np.zeros_like(a) + a_max = np.zeros_like(a) + a_min[0] = a_min_prev[0] + a_min[-1] = a_min_next[-1] + a_max[0] = a_max_prev[0] + a_max[-1] = a_max_next[-1] + a_min[1:-1] = np.maximum(a_min_next[:-1], a_min_prev[1:]) + a_max[1:-1] = np.minimum(a_max_next[:-1], a_max_prev[1:]) + + a_neg_bound, a_pos_bound = acc_model(v_mid) + a_min = np.maximum(a_min, a_neg_bound) + a_max = np.minimum(a_max, a_pos_bound) + a_min = np.minimum(a_min, a) + a_max = np.maximum(a_max, a) + + return a_min, a_max + + +def constraint_v(x, v, a_min, a_max, v_abs_max=0.3): + """ + inputs: position vector x, speed vector v + returns: min. and max. speed for each segment + """ + dx = x[1:] - x[:-1] + v_max_next = np.sqrt(np.maximum(v[:-1] * v[:-1] + 2 * a_max * dx, 0)) + v_min_next = np.sqrt(np.maximum(v[:-1] * v[:-1] + 2 * a_min * dx, 0)) + v_min_prev = np.sqrt(np.maximum(v[1:] * v[1:] - 2 * a_max * dx, 0)) + v_max_prev = np.sqrt(np.maximum(v[1:] * v[1:] - 2 * a_min * dx, 0)) + v_min = np.zeros_like(v) + v_max = np.zeros_like(v) + v_min[0] = v_min_prev[0] + v_min[-1] = v_min_next[-1] + v_max[0] = v_max_prev[0] + v_max[-1] = v_max_next[-1] + v_min[1:-1] = np.maximum(v_min_next[:-1], v_min_prev[1:]) + v_max[1:-1] = np.minimum(v_max_next[:-1], v_max_prev[1:]) + v_min = np.maximum(v_min, -v_abs_max) + v_max = np.minimum(v_max, v_abs_max) + + return v_min, v_max + + +def update(frame, lines, x, v): + global ani, saved + # acceleration horizon + a_min, a_max = constraint_a(x, v, acc_model_simple) + # speed horizon + v_min, v_max = constraint_v(x, v, a_min, a_max) + # update speed (could go unstable) + lambd = 0.1 + v[1:-1] = v_max[1:-1] * lambd + v[1:-1] * (1 - lambd) + + # stop criterion + mse_diff = np.mean(np.square(v_max[1:-1] - v[1:-1])) + if mse_diff < 1e-10: + if not saved: + np.save("x.npy", x) + np.save("v.npy", v) + print("Solution saved!") + saved = True + + lines[0].set_xdata(x) + lines[0].set_ydata(v) + lines[1].set_xdata(x) + lines[1].set_ydata(v_min) + lines[2].set_xdata(x) + lines[2].set_ydata(v_max) + + # compute acceleration for display + x_mid = (x[1:] + x[:-1])*0.5 + x_delta = x[1:] - x[:-1] + v_mid = (v[:-1] + v[1:]) * 0.5 + t_delta = x_delta / v_mid + a = (v[1:] - v[:-1]) / t_delta + + lines[3].set_xdata(x_mid) + lines[3].set_ydata(a) + lines[4].set_xdata(x_mid) + lines[4].set_ydata(a_min) + lines[5].set_xdata(x_mid) + lines[5].set_ydata(a_max) + + return lines + + +def main_func(): + global ani + + fig, axes = plt.subplots(1, 2) + ax = axes[0] + ax2 = axes[1] + ln1, = ax.plot([], [], 'k') + ln2, = ax.plot([], [], 'b') + ln3, = ax.plot([], [], 'r') + ax.set_xlim([0, 4]) + ax.set_ylim([0, 0.4]) + ax.set_xlabel("x") + ax.set_ylabel("v") + ax.set_title("Speed") + ax.legend(["speed", "min", "max"]) + + ln4, = ax2.plot([], [], 'k') + ln5, = ax2.plot([], [], 'b') + ln6, = ax2.plot([], [], 'r') + ax2.set_xlim([0, 4]) + ax2.set_ylim([-0.4, 0.4]) + ax2.set_xlabel("x") + ax2.set_ylabel("a") + ax2.set_title("Acceleration") + ax2.legend(["acc.", "min", "max"]) + + lines = [ln1, ln2, ln3, ln4, ln5, ln6] + plt.tight_layout() + + # position axis + n_points = 256 + x = np.linspace(0, 4, n_points) + v = np.zeros((n_points, )) + v[1:-1] = 1e-4 + + def init(): + return lines + + ani = FuncAnimation(fig, update, init_func=init, fargs=(lines, x, v), blit=True, interval=2) + plt.show() + + +if __name__ == "__main__": + main_func()