Маневр перехода с плоским вращением: почему угловой момент непостоянен?

В статье Рана и Барбы, в которой исследуется переходный маневр с плоским вращением, представлен следующий рисунок:

введите описание изображения здесь

Я пытаюсь воспроизвести эту фигуру, интегрируя следующие связанные уравнения движения, изложенные в статье:

введите описание изображения здесь

Используя следующие параметры моделирования:

введите описание изображения здесь

Угловой момент рассчитывается по формуле:

введите описание изображения здесь

Результаты:

введите описание изображения здесь

Создано следующим кодом MATLAB:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% Example Rahn & Barba (1991) %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Principal moments of inertia of spacecraft including slug
Ix = 2000;
Iy = 1500;
Iz = 1000;
I = [Ix Iy Iz];

% Principal moments of inertia of spherical propellant slug
J = 18;

% Spacecraft body rates
omega_x = 0.1224;
omega_y = 0;
omega_z = 2.99;
omega_0 = [omega_x omega_y omega_z];

% Relative rates between spacecraft body and propellant slug
sigma_x = 0;
sigma_y = 0;
sigma_z = 0;
sigma_0 = [sigma_x sigma_y sigma_z];

% Viscous damping coefficient
mu_x = 30;
mu_y = 30;
mu_z = 30;
mu = [mu_x mu_y mu_z];

% Torques about principal axes
Tx = 0;
Ty = 0;
Tz = 0;
T = [Tx Ty Tz];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Integrate system of differential equations
options = [];
[t1, x1] = ode45( @omega_dynamics, [0 1000], [omega_0 sigma_0], options, I, mu, T, J );

% Calculate angular momentum
h = ((Ix * x1(:,1) + J * x1(:,4)).^2 + (Iy * x1(:,2) + J * x1(:,5)).^2 + (Iz * x1(:,3) + J * x1(:,6)).^2).^(1/2);

figure(1)
% Plot minor-axis spin rate
subplot(2,2,1);
plot(t1,x1(:,3))
axis([0 1000 -2 3])
title('Minor Axis Spin Rate')
xlabel('Time - seconds')
ylabel('rad/s')
% Plot intermediate-axis spin rate
subplot(2,2,2);
plot(t1,x1(:,2))
title('Intermediate Axis Spin Rate')
xlabel('Time - seconds')
ylabel('rad/s')
% Plot major-axis spin rate
subplot(2,2,3);
plot(t1,x1(:,1))
title('Major Axis Spin Rate')
xlabel('Time - seconds')
ylabel('rad/s')
% Plot angular momentum
subplot(2,2,4);
plot(t1,h)
title('Angular Momentum')
xlabel('Time - seconds')
ylabel('Nms')

function dx = omega_dynamics(~, x_0, I, mu, T, J)

    % Initial state vector
    omega_x = x_0(1);
    omega_y = x_0(2);
    omega_z = x_0(3);
    sigma_x = x_0(4);
    sigma_y = x_0(5);
    sigma_z = x_0(6);

    % Constants
    mu_x = mu(1);
    mu_y = mu(2);
    mu_z = mu(3);
    Ix = I(1);
    Iy = I(2);
    Iz = I(3);
    Tx = T(1);
    Ty = T(2);
    Tz = T(3);

    % Differential equations
    omega_dot_x = ((Iy - Iz)*omega_y*omega_z + mu_x*sigma_x + Tx)/(Ix - J);
    omega_dot_y = ((Iz - Ix)*omega_z*omega_x + mu_y*sigma_y + Ty)/(Iy - J);
    omega_dot_z = ((Ix - Iy)*omega_x*omega_y + mu_z*sigma_z + Tz)/(Iz - J);
    sigma_dot_x = -omega_dot_x - mu_x*sigma_x/J - omega_y*sigma_z + omega_z*sigma_y;
    sigma_dot_y = -omega_dot_y - mu_y*sigma_y/J - omega_z*sigma_x + omega_x*sigma_z;
    sigma_dot_z = -omega_dot_z - mu_z*sigma_z/J - omega_x*sigma_y + omega_y*sigma_x;

    % Return vector
    dx = [omega_dot_x; omega_dot_y; omega_dot_z; sigma_dot_x; sigma_dot_y; sigma_dot_z];

end

Как видно из результатов, угловой момент, который должен быть постоянным, не является постоянным, а даже увеличивается при переходном маневре. Я проверил свой код вдоль и поперек, но не смог найти никаких ошибок. Я предполагаю, что это как-то связано с ode45функцией, но я не уверен. Кто-нибудь здесь имеет представление о том, что происходит?

2‰ дрейфуют по моделированию, при начальных условиях, заданных четырьмя значащими цифрами, вероятно, из-за ошибок округления.
Я бы сказал, что независимо от начальных условий угловой момент должен оставаться постоянным. Значит, в ode45алгоритме должно быть что-то, вызывающее этот дрейф.
Интересный вопрос!
«ode45 — это универсальный решатель ОДУ, и это первый решатель, который вы должны попробовать для большинства задач. Однако, если проблема сложная или требует высокой точности, то есть другие решатели ОДУ, которые могут лучше подойти для этой проблемы».
Я согласен, начальные условия не должны влиять на ожидаемую нулевую сумму, но прогрессивные приближения (операции с плавающей запятой) могут накапливать ошибки.
Из всех решателей, предлагаемых MATLAB, результаты, которые дает ode113и ode23s, наиболее близки к оригиналу. И все же они неудовлетворительны. Но на самом деле, это, кажется, вещь решателя.
Вы пытались установить параметры допуска ошибок ( mathworks.com/help/matlab/math/summary-of-ode-options.html )?
@uhoh Я не думаю, что внутренняя работа алгоритма ode45, встроенного в Matlab для численного решения дифференциальных уравнений, отдаленно является темой исследования космоса. Поэтому я не удивлюсь, если ваш вопрос получит несколько голосов не по теме.
@user2705196 user2705196 взгляните на этот ответ , который показывает RK4 (следующим я бы добавил RK45 и переменный размер шага, если бы пользователь был заинтересован) и этот вопрос . Расчет орбитальных траекторий и углового движения космического корабля занимает центральное место в исследовании космоса и прямо и четко относится к теме этого сайта. Также см. Помощь с моим натяжением тензора; как получить и рассчитать этот крутящий момент градиента гравитации твердого тела? Кстати, это не мой вопрос, я просто отредактировал...
@uhoh Я просто объясняю, почему люди могут голосовать за закрытие этого вопроса по причинам, которые не имеют ничего общего с тем, что они не знают ответа. И меня не убеждают ваши рассуждения. Это немного похоже на высказывание «цифровые камеры важны для освоения космоса, поэтому вопрос о том, как работает ПЗС, прямо в тему».

Ответы (2)

Краткий ответ: это проблема решателя ODE.

При настройке допусков относительной и абсолютной погрешности достигаются лучшие результаты. Например, optionsпеременная в коде MATLAB может быть определена следующим образом:

options = odeset('RelTol',1e-10,'AbsTol',1e-10);

Кроме того, чтобы начальный угловой момент был 3000вместо 3000.0045(как было указано в этом ответе ), уравнение для расчета углового момента можно решить для начальной скорости вращения малой оси следующим образом:

omega_z = ( ( 3000^2 - ( Ix * omega_x )^2 ) / ( Iz^2 ) )^( 1/2 );

Наконец, чтобы настроить оси графика углового момента, добавьте:

axis([0 1000 2999 3001])

Получается следующая фигура:

введите описание изображения здесь

Очень хороший ответ и отличные новости! Я бы остановился rtolтолько на уточнении. Абсолютный допуск или atolнеудобно использовать, когда у вас есть числа с физическими единицами. rtolэто все, что тебе нужно. Кроме того, посмотрите, можете ли вы найти способ разрешить вертикальную ось автомасштабирования, angular momentumчтобы вы всегда могли видеть, насколько велико отклонение. Зафиксировав его на [2999 to 3001], вы не сможете видеть, что происходит.
@uhoh Оказывается, когда я указываю RelTolтолько, точность снижается только до 10^(-2). Указание AbsTolтакже дает 10^(-6)точность. Вы правы насчет масштабирования, чтобы показать отклонение, но целью было воспроизвести цифру в статье. Поэтому достаточно зафиксировать ось.
Попробуйте изучить конкретные значения, которые вы используете. Эффект от них будет разным, потому что один нормализован, а другой нет. Недостаточно сказать, что вы использовали или не использовали параметр, вам нужно оптимизировать значение параметра. Они оба будут иметь влияние, и если вы просто установите их равными, одно из них может иметь значение, отличное от другого, но нет причин устанавливать для них одно и то же значение. Удачи, раз и навсегда!
О, за исключением того, что вы можете принять свой собственный ответ! Это лучше всего описывает решение вашего вопроса.

Я переписал ваш матлаб на Python (что действительно легко сделать, и это не совпадение!) И использовал интегратор SciPy ODE по умолчанию. Проверяя, info['mused']я вижу, что он всегда использовал алгоритм Адамса (нежесткий), поэтому проблема не в жесткости.

Почему бы просто не сбросить «старый и сломанный» Matlab и не принять «новый» Python? ( ссылка на MIB )

Я предполагаю, что вам следует начать читать документацию по Matlab ode45и снизить допуск к ошибкам. Я предполагаю, что это ode45то, что я бы назвал RK45, и это переменный размер шага 4/5 порядка Рунге-Кутта. Это должно быть хорошо, но если вы не укажете допуск, он выберет его для вас.

Возможно, между тем, когда ваша ссылка была опубликована, и тем, когда вы запустили свой пример, Matlab изменил некоторые значения по умолчанию, или автор мог использовать некоторые из них и забыл сообщить вам, или вы не заметили, что они упоминались ранее в том, что вы читали. .

Короче говоря, у меня он работает просто отлично.

Начальный угловой момент не равен 3000 с использованием значений инициализации, но на самом деле это 3000.0045то место, где начинается симуляция. Он дрейфует 3000.001через 1000 секунд. Это изменение 0,003. На графике показано отклонение от четных 3000 (или 3e3).

Я могу немного улучшить это, чтобы общий дрейф составлял всего около 0,001, вставив rtol=1E-10или rtol=1E-11в вызове ODEint.

введите описание изображения здесь

def omega_dynamics(x_0, t, I, mu, T, J):

    # % Initial state vector
    omega_x, omega_y, omega_z, sigma_x, sigma_y, sigma_z = x_0[:6]

    # % Constants
    mu_x, mu_y, mu_z = mu[:3]
    Ix, Iy, Iz = I[:3]
    Tx, Ty, Tz = T[:3]

    # % Differential equations
    omega_dot_x = ((Iy - Iz)*omega_y*omega_z + mu_x*sigma_x + Tx)/(Ix - J)
    omega_dot_y = ((Iz - Ix)*omega_z*omega_x + mu_y*sigma_y + Ty)/(Iy - J)
    omega_dot_z = ((Ix - Iy)*omega_x*omega_y + mu_z*sigma_z + Tz)/(Iz - J)
    sigma_dot_x = -omega_dot_x - mu_x*sigma_x/J - omega_y*sigma_z + omega_z*sigma_y
    sigma_dot_y = -omega_dot_y - mu_y*sigma_y/J - omega_z*sigma_x + omega_x*sigma_z
    sigma_dot_z = -omega_dot_z - mu_z*sigma_z/J - omega_x*sigma_y + omega_y*sigma_x

    # % Return vector
    dx = np.array([omega_dot_x, omega_dot_y, omega_dot_z, sigma_dot_x, sigma_dot_y, sigma_dot_z])

    return dx

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# %%%%% Example Rahn & Barba (1991) %%%%%
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint as ODEint

J        = 18.0;                                             # Principal moments of inertia of spherical propellant slug
I        = np.array([2000,   1500,   1000], dtype=float)   # Principal moments of inertia of spacecraft including slug
omega_0  = np.array([0.1224, 0,      2.99], dtype=float)   # Spacecraft body rates
sigma_0  = np.array([0,      0,      0   ], dtype=float)   # Relative rates between spacecraft body and propellant slug
mu       = np.array([30,     30,     30  ], dtype=float)   # Viscous damping coefficient
T        = np.array([0,      0,      0   ], dtype=float)   # Torques about principal axes

h_init   = np.sqrt(((I * omega_0 + J * sigma_0)**2).sum())  # % Calculate angular momentum

print "h_init: ", h_init

times        = np.linspace(0, 1000, 10001)
X0           = np.hstack((omega_0, sigma_0))

x1, info = ODEint(omega_dynamics, X0, times, args=(I, mu, T, J), full_output=True)
print x1.shape

h          = np.sqrt(((I * x1[:, :3] + J * x1[:,3:])**2).sum(axis=1))  # % Calculate angular momentum

if True:
    plt.figure()

    plt.subplot(2, 2, 1)
    plt.plot(times, x1[:, 2])
    plt.ylim(-2, 3)
    plt.title('Minor Axis Spin Rate')
    plt.xlabel('Time - seconds')
    plt.ylabel('rad/s')

    plt.subplot(2, 2, 2)
    plt.plot(times, x1[:, 1])
    plt.title('Intermediate Axis Spin Rate')
    plt.xlabel('Time - seconds')
    plt.ylabel('rad/s')

    plt.subplot(2, 2, 3)
    plt.plot(times, x1[:, 0])
    plt.title('Major Axis Spin Rate')
    plt.xlabel('Time - seconds')
    plt.ylabel('rad/s')

    plt.subplot(2, 2, 4)
    plt.plot(times, h)
    plt.title('Angular Momentum')
    plt.xlabel('Time - seconds')
    plt.ylabel('Nms')

    plt.show()
Спасибо @uhoh, это подтверждает то, что я подозревал. Приятно знать, что с кодом все в порядке. Все для Python, когда я не работаю с Simulink :)
@woeterb да! Если вы найдете способ уговорить ode45дать вам то, что вам нужно, опубликуйте здесь еще один ответ. Если это действительно решает вашу проблему, вы также можете принять это. Цель состоит в том, чтобы предоставить наилучшую информацию будущим пользователям. Веселиться!
Я опубликовал новый ответ, который дает фактическое решение для примера MATLAB. Это действительно действительно решает вопрос. Спасибо за ваши старания.