#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>
#include <limits> // Для numeric_limits
#ifdef WITH_GNUPLOT
#include "gnuplot-iostream.h"
#endif
using namespace std;
// Структура для хранения состояния ракеты
struct State {
double position; // Высота над поверхностью
double velocity;
double mass; // Текущая масса ракеты
};
// Структура для параметров модели
struct Parameters {
double initialMass; // Начальная масса ракеты
double fuelConsumptionRate; // Скорость сгорания топлива (кг/с)
double exhaustVelocity; // Скорость истечения газов относительно ракеты
double gravitationalAcceleration; // Ускорение свободного падения
double dragCoefficient; // Коэффициент сопротивления воздуха
double area; // Площадь поперечного сечения ракеты
double airDensity; // Плотность воздуха
double finalTime; // Время симуляции
double timeStep; // Шаг времени
};
// Функция для вычисления производных (правая часть дифференциальных уравнений)
vector<double> derivatives(const State& state, const Parameters& params) {
double dragForce = 0.5 * params.airDensity * pow(state.velocity, 2) * params.dragCoefficient * params.area;
double thrust = params.fuelConsumptionRate * params.exhaustVelocity;
double netForce = thrust - dragForce - state.mass * params.gravitationalAcceleration;
double acceleration = netForce / state.mass;
double massRate = -params.fuelConsumptionRate; // Масса уменьшается
return {state.velocity, acceleration, massRate};
}
// Функция для выполнения одного шага метода Рунге-Кутты 4-го порядка
State rk4Step(const State& state, const Parameters& params) {
vector<double> k1 = derivatives(state, params);
State state2 = {state.position + params.timeStep * k1[0] / 2.0,
state.velocity + params.timeStep * k1[1] / 2.0,
state.mass + params.timeStep * k1[2] / 2.0};
vector<double> k2 = derivatives(state2, params);
State state3 = {state.position + params.timeStep * k2[0] / 2.0,
state.velocity + params.timeStep * k2[1] / 2.0,
state.mass + params.timeStep * k2[2] / 2.0};
vector<double> k3 = derivatives(state3, params);
State state4 = {state.position + params.timeStep * k3[0],
state.velocity + params.timeStep * k3[1],
state.mass + params.timeStep * k3[2]};
vector<double> k4 = derivatives(state4, params);
return {state.position + params.timeStep * (k1[0] + 2.0 * k2[0] + 2.0 * k3[0] + k4[0]) / 6.0,
state.velocity + params.timeStep * (k1[1] + 2.0 * k2[1] + 2.0 * k3[1] + k4[1]) / 6.0,
state.mass + params.timeStep * (k1[2] + 2.0 * k2[2] + 2.0 * k3[2] + k4[2]) / 6.0};
}
int main() {
Parameters params;
// Ввод параметров с защитой от "дурака"
cout << "Введите начальную массу ракеты (кг): ";
cin >> params.initialMass;
if (params.initialMass <= 0) {
cout << "Ошибка: Начальная масса должна быть положительной." << endl;
return 1;
}
cout << "Введите скорость сгорания топлива (кг/с): ";
cin >> params.fuelConsumptionRate;
if (params.fuelConsumptionRate < 0) {
cout << "Ошибка: Скорость сгорания топлива не может быть отрицательной." << endl;
return 1;
}
cout << "Введите скорость истечения газов (м/с): ";
cin >> params.exhaustVelocity;
if (params.exhaustVelocity <= 0) {
cout << "Ошибка: Скорость истечения газов должна быть положительной." << endl;
return 1;
}
cout << "Введите ускорение свободного падения (м/с^2): ";
cin >> params.gravitationalAcceleration;
if (params.gravitationalAcceleration < 0) {
cout << "Ошибка: Ускорение свободного падения не может быть отрицательным." << endl;
return 1;
}
cout << "Введите коэффициент сопротивления воздуха: ";
cin >> params.dragCoefficient;
if (params.dragCoefficient < 0) {
cout << "Ошибка: Коэффициент сопротивления не может быть отрицательным." << endl;
return 1;
}
cout << "Введите площадь поперечного сечения ракеты (м^2): ";
cin >> params.area;
if (params.area <= 0) {
cout << "Ошибка: Площадь должна быть положительной." << endl;
return 1;
}
cout << "Введите плотность воздуха (кг/м^3): ";
cin >> params.airDensity;
if (params.airDensity < 0) {
cout << "Ошибка: Плотность воздуха не может быть отрицательной." << endl;
return 1;
}
cout << "Введите время симуляции (с): ";
cin >> params.finalTime;
if (params.finalTime <= 0) {
cout << "Ошибка: Время симуляции должно быть положительным." << endl;
return 1;
}
cout << "Введите шаг времени (с): ";
cin >> params.timeStep;
if (params.timeStep <= 0) {
cout << "Ошибка: Шаг времени должен быть положительным." << endl;
return 1;
}
// Начальное состояние
State currentState = {0.0, 0.0, params.initialMass};
// Векторы для хранения данных для графика
vector<pair<double, double>> positionData;
vector<pair<double, double>> velocityData;
vector<pair<double, double>> massData;
// Основной цикл симуляции
double time = 0.0;
while (time <= params.finalTime) {
// Сохраняем данные для графика
positionData.push_back({time, currentState.position});
velocityData.push_back({time, currentState.velocity});
massData.push_back({time, currentState.mass});
// Выполняем шаг Рунге-Кутты
currentState = rk4Step(currentState, params);
// Проверка на "падение" ракеты (высота стала отрицательной)
if (currentState.position < 0) {
currentState.position = 0;
currentState.velocity = 0; // Останавливаем ракету при касании земли
}
// Обновляем время
time += params.timeStep;
//Проверка на окончание топлива (масса стала меньше, чем масса конструкции ракеты)
if(currentState.mass <= 10)
{
cout<<"Топливо закончилось!"<<endl;
break;
}
}
#ifdef WITH_GNUPLOT
// Рисуем графики с использованием gnuplot-iostream
Gnuplot gp;
gp << "set terminal qt size 600,400\n"; // Настройка размера окна
// График высоты
gp << "set title 'Высота ракеты'\n";
gp << "set xlabel 'Время (с)'\n";
gp << "set ylabel 'Высота (м)'\n";
gp << "plot '-' with lines title 'Высота'\n";
gp.send1d(positionData);
// График скорости
gp << "set title 'Скорость ракеты'\n";
gp << "set xlabel 'Время (с)'\n";
gp << "set ylabel 'Скорость (м/с)'\n";
gp << "plot '-' with lines title 'Скорость'\n";
gp.send1d(velocityData);
// График массы
gp << "set title 'Масса ракеты'\n";
gp << "set xlabel 'Время (с)'\n";
gp << "set ylabel 'Масса (кг)'\n";
gp << "plot '-' with lines title 'Масса'\n";
gp.send1d(massData);
cout << "Графики отображены. Закройте окна графиков для завершения программы." << endl;
cin.get(); // Ждем нажатия Enter, чтобы окна графиков не закрылись сразу
#else
cout << "Для отображения графиков установите библиотеку gnuplot-iostream." << endl;
cout << "Результаты симуляции сохранены в файлы position.dat, velocity.dat и mass.dat." << endl;
// Сохраняем данные в файлы (альтернатива gnuplot)
ofstream positionFile("position.dat");
ofstream velocityFile("velocity.dat");
ofstream massFile("mass.dat");
for (const auto& p : positionData) positionFile << p.first << " " << p.second << endl;
for (const auto& v : velocityData) velocityFile << v.first << " " << v.second << endl;
for (const auto& m : massData) massFile << m.first << " " << m.second << endl;
positionFile.close();
velocityFile.close();
massFile.close();
#endif
return 0;
}