-
Notifications
You must be signed in to change notification settings - Fork 0
/
spacecraft.cpp
225 lines (196 loc) · 11.5 KB
/
spacecraft.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#include <iostream>
#include <math.h>
//g++ -c -fPIC spacecraft.cpp -o spacecraft.o
//g++ -shared -Wl,-soname,libspacecraft.so -o libspacecraft.so spacecraft.o
using namespace std;
//общие константы:
const double G = 6.67e-11;//гравитационная постоянная
const double IG = 4600;//среднее значение удельной тяги ЖРД - отношение тяги к расходу топлива
//константы, которые я выбираю для данной конкретной задачи
const double H_START_KM = 10;//высота над поверхностью планеты в начальный момент времени
const double SPACECRAFT_MASS_KG_MIN = 5000;//масса аппарата - да, она должна быть переменной из-за расхода топлива, но нет
const double SPACECRAFT_MASS_KG_MAX = 7000;
const double PLANET_GRAV_ACCEL_MS2 = 1.6;//пусть пока как на Луне
const double LIMIT_VERTICAL_V_MSEC = 2;//лимит на вертикальную скорость при посадке, м/с
const double LIMIT_FUEL_KG = 450;//лимит на количество потраченного топлива, кг
const double ENGINE_FORCE_NEWTONS_MIN = 1 * PLANET_GRAV_ACCEL_MS2 * SPACECRAFT_MASS_KG_MIN;
const double ENGINE_FORCE_NEWTONS_MAX = 2 * PLANET_GRAV_ACCEL_MS2 * SPACECRAFT_MASS_KG_MAX;
//делаем массу переменной в зависимости от мощности двигателя
double CalcSpacecraftMassByEngine(
double engineForceNewtons )
{
double coeff = ( engineForceNewtons - ENGINE_FORCE_NEWTONS_MIN ) / (double)( ENGINE_FORCE_NEWTONS_MAX - ENGINE_FORCE_NEWTONS_MIN );
double mass = SPACECRAFT_MASS_KG_MIN + coeff * ( SPACECRAFT_MASS_KG_MAX - SPACECRAFT_MASS_KG_MIN );
return mass;
}
//расчет интервала времени свободного падения
// - от начального момента до включения тормозного посадочного двигателя
void CalcIntervalFreeFalling(
double hStartKm,//высота над поверхностью планеты в начальный момент времени
double hTurnOnEngineKm,//высота над поверхностью планеты в момент, когда включается движок
double planetGravAccelMS2,//ускорение свободного падения планеты - считаем постоянным
double* ptr_deltaT1Sec,//возвращаемое значение - продолжительность интервала в секундах
double* ptr_V1MSec )//возвращаемое значение - вертикальная скорость снижения в момент включения движка, м/с
{
double deltaT1Sec = sqrt( 2 * ( hStartKm - hTurnOnEngineKm ) * 1000 / planetGravAccelMS2 );
*ptr_deltaT1Sec = deltaT1Sec;
*ptr_V1MSec = deltaT1Sec * planetGravAccelMS2;
}
//расчет интервала работы двигателя
// - от включения тормозного двигателя до поверхности, если долетим - возвращаем true
// можем же и вверх полететь - тогда возвращаем false
bool CalcIntervalEngineWorking(
double V1MSec,//вертикальная скорость снижения в момент включения движка, м/с
double hTurnOnEngineKm,//высота над поверхностью планеты в момент, когда включается движок
double engineAccelMS2,//ускорение от тяги двигателя
double planetGravAccelMS2,//ускорение свободного падения планеты - считаем постоянным
double *ptr_deltaT2Sec,//возвращаемое значение - продолжительность интервала работы двигателя в секундах
double *ptr_V2MSec )//возвращаемое значение - вертикальная скорость снижения в момент касания поверхности, м/с
{
//особый случай - если ускорение от двигателя компенсирует ускорение свободного падения,
//то получается падение с постоянной скоростью
if ( planetGravAccelMS2 == engineAccelMS2 )
{
double deltaT2Sec = hTurnOnEngineKm / V1MSec;
double V2MSec = V1MSec;
//cout << "Equal accelerations, one root\n";
*ptr_deltaT2Sec = deltaT2Sec;
*ptr_V2MSec = V2MSec;
}
else
{
//нужно решить квадратное уравнение - считаем дискриминант
double D = V1MSec * V1MSec + 2 * ( planetGravAccelMS2 - engineAccelMS2 ) * hTurnOnEngineKm * 1000;
if( D < 0 )
return false;//не долетели - тяга движка слишком велика, затормозились и полетели обратно вверх
//иначе считаем дальше - сколько времени ушло и какая скорость получилась у Земли
double deltaT2Sec_1 = ( - V1MSec + sqrt( D ) ) / (double)( planetGravAccelMS2 - engineAccelMS2 );
double deltaT2Sec_2 = ( - V1MSec - sqrt( D ) ) / (double)( planetGravAccelMS2 - engineAccelMS2 );
//cout << "Roots: " << deltaT2Sec_1 << " " << deltaT2Sec_2 << "\n";
double deltaT2Sec = deltaT2Sec_1;
double V2MSec = V1MSec + deltaT2Sec * ( planetGravAccelMS2 - engineAccelMS2 );
//вертикальная скорость снижения в момент касания поверхности планеты, м/с
*ptr_deltaT2Sec = deltaT2Sec;
*ptr_V2MSec = V2MSec;
}
return true;
}
//расчет затрат топлива, кг
extern "C" {
double CalcFuelCostKg(double, double);
}
double CalcFuelCostKg(
double deltaTEngineSec,//продолжительность работы двигателя, сек
double engineForceNewtons )//величина тяги двигателя, Н
{
double fuelCostPerSecond = engineForceNewtons / IG;
return ( fuelCostPerSecond * deltaTEngineSec );
}
/*"H = " << hTurnOnEngineKm << " km, F = "
<< engineForceNewtons << " N, mass = "
<< spacecraftMass << " kg: ";
cout << "deltaT2Sec = " << deltaT2Sec
<< " sec, V2MSec = " << V2MSec
<< " m/s, fuel = " << fuelCostKg << " kg\n";*/
//основная функция расчета - на вход получает данные от пользователя
typedef struct
{
bool resultSecondStep;
bool isSolution;
double hTurnOnEngineKm;
double engineForceNewtons;
double spacecraftMass;
double deltaT2Sec;
double V2MSec;
double fuelCostKg;
} commonSolution;
extern "C" {
commonSolution CommonCalculations(double, double);
}
commonSolution CommonCalculations(
double hTurnOnEngineKm,//высота над поверхностью планеты в момент, когда включается движок
double engineForceNewtons )//величина тяги двигателя, Н
{
//сразу договоримся, что 0 <= hTurnOnEngineKm <= H_START_KM - ограничение "ползунка"
// и надо выбрать ограничения для engineForceNewtons
//обсчет участка свободного падения до включения двигателя
commonSolution result;
double deltaT1Sec;
double V1MSec;
CalcIntervalFreeFalling(
H_START_KM,//высота над поверхностью планеты в начальный момент времени
hTurnOnEngineKm,//высота над поверхностью планеты в момент, когда включается движок
PLANET_GRAV_ACCEL_MS2,//ускорение свободного падения планеты - считаем постоянным
&deltaT1Sec,//возвращаемое значение - продолжительность интервала в секундах
&V1MSec );//возвращаемое значение - вертикальная скорость снижения в момент включения движка, м/с
// cout << "deltaT1Sec = " << deltaT1Sec
// << " sec, V1MSec = " << V1MSec
// << " m/s\n";
//обсчет участка снижения с работающим двигателем
double spacecraftMass = CalcSpacecraftMassByEngine( engineForceNewtons );
double deltaT2Sec;
double V2MSec;
bool resultSecondStep = CalcIntervalEngineWorking(
V1MSec,//вертикальная скорость снижения в момент включения движка, м/с
hTurnOnEngineKm,//высота над поверхностью планеты в момент, когда включается движок
engineForceNewtons / spacecraftMass,//ускорение от тяги двигателя
PLANET_GRAV_ACCEL_MS2,//ускорение свободного падения планеты - считаем постоянным
&deltaT2Sec,//возвращаемое значение - продолжительность интервала работы двигателя в секундах
&V2MSec );//возвращаемое значение - вертикальная скорость снижения в момент касания поверхности, м/с
// cout << "H = " << hTurnOnEngineKm << " km, F = "
// << engineForceNewtons << " N, mass = "
// << spacecraftMass << " kg: ";
if( resultSecondStep == false )
{
result =
{
resultSecondStep,
false,
hTurnOnEngineKm,
engineForceNewtons,
spacecraftMass,
deltaT2Sec,
V2MSec,
0.0
};
return(result);
// cout << "Surface not achieved - flying up\n";//сообщение, что взлетаем, не достигнув поверхности планеты
}
else
{
double fuelCostKg = CalcFuelCostKg(
deltaT2Sec,//продолжительность работы двигателя, сек
engineForceNewtons );//величина тяги двигателя, Н
if( ( V2MSec < LIMIT_VERTICAL_V_MSEC )&&( fuelCostKg < LIMIT_FUEL_KG ) )
{
result =
{
resultSecondStep,
true,
hTurnOnEngineKm,
engineForceNewtons,
spacecraftMass,
deltaT2Sec,
V2MSec,
fuelCostKg
};
return(result);
}
else
{
result =
{
resultSecondStep,
false,
hTurnOnEngineKm,
engineForceNewtons,
spacecraftMass,
deltaT2Sec,
V2MSec,
fuelCostKg
};
return(result);
/* cout << "V2Msec greater than LIMIT or fuelCostKg too large \n";*/
}
}
}