-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathevtol.h
373 lines (316 loc) · 11.2 KB
/
evtol.h
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#ifndef EVTOL
#define EVTOL
#include <iostream>
#include <string>
#include <stdexcept>
#include <random>
#include <chrono>
#include "sim_types.h"
#include "charge_station.h"
// Describes the configuration of an eVTOL
// Validates all of the entries.
// Provides some simple calculations for compound properties.
// Provides following configuration values:
// company_name
// cruise_speed in mph
// battery_capacity in kWh
// time_to_charge in hours
// energy_use_at_cruise in kWh/mile
// passenger_count
// prob_fault_per_hour
//
// Usage:
// eVTOLConfiguration vtol_config("Alpha", 120, 320, 0.6, 1.6, 4, 0.25);
// int num_passengers = vtol_config.passenger_count();
// double charge_rate = vtol_config.chargeRate();
struct eVTOLConfiguration
{
eVTOLConfiguration() {
company_name_ = "unknonw";
cruise_speed_ = 1;
battery_capacity_ = 1;
time_to_charge_ = 1;
energy_use_at_cruise_ = 1;
passenger_count_ = 1;
battery_capacity_ = 1;
prob_fault_per_hour_ = 1.0;
}
eVTOLConfiguration(std::string company_name, double cruise_speed, double battery_capacity,
double time_to_charge, double energy_use_at_cruise, size_t passenger_count,
double prob_fault_per_hour = 0.25)
{
if (company_name == "") throw std::invalid_argument("company_name cannot be blank.");
if (cruise_speed <= 0.0) throw std::invalid_argument("cruise_speed must be a positive number.");
if (battery_capacity <= 0.0) throw std::invalid_argument("battery_capacity must be a positive number.");
if (time_to_charge <= 0.0) throw std::invalid_argument("time_to_charge must be a positive number.");
if (energy_use_at_cruise <= 0.0) throw std::invalid_argument("energy_use_at_cruise must be a positive number.");
if (passenger_count <= 0) throw std::invalid_argument("passenger_count must be a positive number.");
if (prob_fault_per_hour < 0.0 || prob_fault_per_hour > 1.0) throw std::invalid_argument("prob_fault_per_hour must be in [0.0, 1.0].");
company_name_ = company_name;
cruise_speed_ = cruise_speed;
battery_capacity_ = battery_capacity;
time_to_charge_ = time_to_charge;
energy_use_at_cruise_ = energy_use_at_cruise;
passenger_count_ = passenger_count;
battery_capacity_ = battery_capacity;
prob_fault_per_hour_ = prob_fault_per_hour;
}
std::string company_name() { return company_name_; }
double cruise_speed() { return cruise_speed_; }
double battery_capacity() { return battery_capacity_; }
double time_to_charge() { return time_to_charge_; }
double energy_use_at_cruise() { return energy_use_at_cruise_; }
size_t passenger_count() { return passenger_count_; }
double prob_fault_per_hour() { return prob_fault_per_hour_; }
// returns rate of charge for the batteries in kWh / ms
double chargeRate()
{
return battery_capacity_ / (time_to_charge_ * 60.0 * 60.0 * 1000.0); // converting hours to milliseconds
}
// returns rate of energy consumption in kWh per millisecond when flying at cruise speed
double energyUsePerMillisecond()
{
return energy_use_at_cruise_ * cruise_speed_ / (60.0 * 60.0 * 1000.0);
}
private:
std::string company_name_;
double cruise_speed_; // in mph
double battery_capacity_; // in kWh
double time_to_charge_; // in hours
double energy_use_at_cruise_; // in kWh/mile
size_t passenger_count_;
double prob_fault_per_hour_;
};
// describes possible states of an eVTOL
enum class eVTOLState
{
UNKNOWN,
FLYING,
CHARGING,
WAITING
};
// Simulates an eVTOL.
// An eVTOLConfiguration describes the eVTOL.
// Is a ChargeableDevice and can get its batteries recharged in a ChargingStation.
// The ChargingStation is shared among all eVTOLs.
// Is a SimulationAgent and receives timestep updates to update its internal state.
// Can be in one of 3 states, FLYING, CHARGING, or WAITING.
// Keeps track of total time spent in each of these states.
// Additionally keeps track of total number of faults that occur while flying.
// An eVTOL starts out with a full charge and in FLYING mode.
// As it flies, it drains its battery. Once it gets close to zero charge,
// It enters the charging station. If a charging bay is open, the eVTOL goes
// into charging state, if all bays are occupied, it goes int WAITING mode.
// Once fully charged, it goes back into FLYING mode.
// The simulation is conducted in time units of milliseconds.
// These values are converted to seconds, minutes, hours as needed.
class eVTOL : public SimulationAgent, public ChargeableDevice
{
public:
eVTOL(const eVTOLConfiguration& config, ChargingStation* charging_station)
{
configuration_ = config;
this->charging_station_ = charging_station;
total_flight_time_ = 0.0;
total_charge_time_ = 0.0;
total_wait_time_ = 0.0;
number_of_faults_ = 0;
current_charge_ = configuration_.battery_capacity();
state_ = eVTOLState::UNKNOWN;
unsigned seed = std::chrono::steady_clock::now().time_since_epoch().count();
random_engine_ = std::default_random_engine(seed);
}
eVTOL(const eVTOL& source_evtol)
{
configuration_ = source_evtol.configuration_;
charging_station_ = source_evtol.charging_station_;
total_flight_time_ = source_evtol.total_flight_time_;
total_charge_time_ = source_evtol.total_charge_time_;
total_wait_time_ = source_evtol.total_wait_time_;
current_charge_ = source_evtol.current_charge_;
number_of_faults_ = source_evtol.number_of_faults_;
state_ = source_evtol.state_;
// don't copy the random engine, just create a new one
unsigned seed = std::chrono::steady_clock::now().time_since_epoch().count();
random_engine_ = std::default_random_engine(seed);
}
void begin() override
{
state_ = eVTOLState::FLYING;
}
void timestepUpdate(size_t prev_time, size_t cur_time) override
{
if (state_ == eVTOLState::FLYING)
{
total_flight_time_ += (cur_time - prev_time);
current_charge_ -= energyUsePerMillisecond() * (cur_time - prev_time);
number_of_faults_ += didFaultOccur(cur_time - prev_time);
// if low on battery charge, plug into charging station
if (percentChargeRemaining() < 0.5)
{
state_ = eVTOLState::WAITING;
if (charging_station_)
{
charging_station_->addDevice(this);
}
}
}
else if (state_ == eVTOLState::WAITING)
{
total_wait_time_ += (cur_time - prev_time);
}
else if (state_ == eVTOLState::CHARGING)
{
total_charge_time_ += (cur_time - prev_time);
if (hasFullCharge())
{
state_ = eVTOLState::FLYING;
}
}
else
{
// oops, something went wrong
throw std::logic_error("VTOL in a bad state.");
}
}
// returns true if a fault occured during the time interval specified
bool didFaultOccur(size_t interval_milliseconds)
{
double prob_fault_per_millisecond = configuration_.prob_fault_per_hour() / (60.0 * 60.0 * 1000.0);
double prob_fault_during_interval = prob_fault_per_millisecond * interval_milliseconds;
std::uniform_real_distribution<double> dist(0.0, 1.0);
double observation = dist(random_engine_);
bool fault_occured = observation < prob_fault_during_interval;
return fault_occured;
}
// charge is in kWh
void addCharge(double charge) override
{
current_charge_ += charge;
current_charge_ = std::min(current_charge_, configuration_.battery_capacity());
if (hasFullCharge())
{
state_ = eVTOLState::FLYING;
}
else
{
state_ = eVTOLState::CHARGING;
}
}
bool hasFullCharge() override
{
return current_charge_ == configuration_.battery_capacity();
}
// returns the name of the state
std::string stateName()
{
if (state_ == eVTOLState::FLYING)
{
return "FLYING";
}
else if (state_ == eVTOLState::CHARGING)
{
return "CHARGING";
}
else if (state_ == eVTOLState::WAITING)
{
return "WAITING";
}
else
{
return "UNKNOWN";
}
}
// return amount of charge remaining as a percent of max charge
double percentChargeRemaining()
{
return current_charge_ / configuration_.battery_capacity() * 100.0;
}
// returns the charge rate in kWh / milliseconds
double chargeRate() override
{
return configuration_.chargeRate();
}
// returns the cruising speed energy used in kWh / milliseconds
double energyUsePerMillisecond()
{
return configuration_.energyUsePerMillisecond();
}
std::string company_name()
{
return configuration_.company_name();
}
size_t passenger_count()
{
return configuration_.passenger_count();
}
size_t cruise_speed()
{
return configuration_.cruise_speed();
}
eVTOLState state() { return state_; }
size_t total_flight_time() { return total_flight_time_; }
size_t total_charge_time() { return total_charge_time_; }
size_t total_wait_time() { return total_wait_time_; }
double current_charge() { return current_charge_; }
size_t number_of_faults() { return number_of_faults_; }
eVTOLConfiguration configuration() { return configuration_; }
private:
eVTOLConfiguration configuration_;
size_t total_flight_time_; // in milliseconds
size_t total_charge_time_; // in milliseconds
size_t total_wait_time_; // in milliseconds
double current_charge_; // in kWh
size_t number_of_faults_;
eVTOLState state_;
ChargingStation* charging_station_; // where eVTOLs get their batteries recharged
std::default_random_engine random_engine_;
};
void test_eVTOLConfiguration()
{
using namespace std;
try { eVTOLConfiguration vtol_config("", 120, 320, 0.6, 1.6, 4, 0.25); }
catch (const std::invalid_argument& ia) { cout << ia.what() << endl; }
try { eVTOLConfiguration vtol_config("Alpha", 0, 320, 0.6, 1.6, 4, 0.25); }
catch (const std::invalid_argument& ia) { cout << ia.what() << endl; }
try { eVTOLConfiguration vtol_config("Alpha", 120, -10, 0.6, 1.6, 4, 0.25); }
catch (const std::invalid_argument& ia) { cout << ia.what() << endl; }
try { eVTOLConfiguration vtol_config("Alpha", 120, 320, 0, 1.6, 4, 0.25); }
catch (const std::invalid_argument& ia) { cout << ia.what() << endl; }
try { eVTOLConfiguration vtol_config("Alpha", 120, 320, 0.6, -1.6, 4, 0.25); }
catch (const std::invalid_argument& ia) { cout << ia.what() << endl; }
try { eVTOLConfiguration vtol_config("Alpha", 120, 320, 0.6, 1.6, 0, 0.25); }
catch (const std::invalid_argument& ia) { cout << ia.what() << endl; }
eVTOLConfiguration vtol_config("Alpha", 120, 320, 0.6, 1.6, 4, 0.25);
cout << vtol_config.company_name() << " ";
cout << vtol_config.cruise_speed() << " ";
cout << vtol_config.battery_capacity() << " ";
cout << vtol_config.time_to_charge() << " ";
cout << vtol_config.energy_use_at_cruise() << " ";
cout << vtol_config.passenger_count() << " ";
cout << vtol_config.prob_fault_per_hour() << " ";
cout << vtol_config.chargeRate();
}
void test_eVTOL()
{
using namespace std;
eVTOLConfiguration vtol_config("Alpha", 120, 320, 0.6, 1.6, 4, 0.25);
eVTOL vtol(vtol_config, nullptr);
cout << vtol.company_name() << endl;
cout << (vtol.state() == eVTOLState::UNKNOWN) << endl;
cout << vtol.percentChargeRemaining() << endl;
cout << vtol.chargeRate() << endl;
cout << vtol.energyUsePerMillisecond() << endl;
vtol.begin();
cout << (vtol.state() == eVTOLState::FLYING) << endl;
vtol.timestepUpdate(0, 1000);
vtol.timestepUpdate(1000, 2000);
vtol.timestepUpdate(2000, 3000);
cout << (vtol.state() == eVTOLState::FLYING) << endl;
cout << vtol.percentChargeRemaining() << endl;
vtol.timestepUpdate(3000, 30000);
cout << vtol.percentChargeRemaining() << endl;
vtol.timestepUpdate(30000, 100000);
cout << vtol.percentChargeRemaining() << endl;
}
#endif // EVTOL