openETCS
case study for the European Train Control System developed for the authors dissertation
Simulation.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010-2012
3  Johannes Feuser <feuser@uni-bremen.de>
4  This file is part of the openETCS library.
5 
6  The openETCS library is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  any later version.
10 
11  The openETCS library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with the openETCS library. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /*!
21  * \author Johannes Feuser <feuser@uni-bremen.de>
22  * \brief classes for simulative usage
23  */
24 
25 #include "Simulation.h"
26 
27 
28 
29 
30 namespace oETCS {
31 
32 namespace DF {
33 
34 namespace PS {
35 
36 namespace SIM {
37 
38 
39 COdometer::COdometer(const double& dInitialPosition, const double& dInitialVelocity) throw()
41  m_dVelocity(dInitialVelocity),
42  m_dPosition(dInitialPosition)
43 {
44  // Bouml preserved body begin 000D6482
45  // set last calculation time point as now
46  //m_LastCalculation = ::std::chrono::high_resolution_clock::now();
47  // Bouml preserved body end 000D6482
48 
49 } // COdometer::COdometer() throw()
50 
51 
52 
53 
55 {
56  // Bouml preserved body begin 000D6502
57  // empty destructor
58  // Bouml preserved body end 000D6502
59 
60 } // COdometer::~COdometer() throw()
61 
62 
63 
64 
66 {
67  // Bouml preserved body begin 000D6582
68  ::std::chrono::duration< long long, ::std::chrono::system_clock::duration::period > Duration;
69 
70 
71 
72 
73  // lock mutex
74  m_Mutex.lock();
75 
76  // calculate duration with current velocity
77  Duration = ::std::chrono::system_clock::now() - m_LastCalculation;
78 
79  // calculate new position by integration (simplified by multiplication)
80  m_dPosition += m_dVelocity / 3.6 * double(Duration.count()) * (double(::std::chrono::system_clock::duration::period::num) / double(::std::chrono::system_clock::duration::period::den));
81 
82  // set last calculation to now
83  m_LastCalculation = ::std::chrono::system_clock::now();
84 
85  // unlock mutex
86  m_Mutex.unlock();
87 
88  // return new position
89  return (m_dPosition);
90  // Bouml preserved body end 000D6582
91 
92 } // double COdometer::GetAbsolutePosition()
93 
94 
95 
96 
98 {
99  // Bouml preserved body begin 000D6602
100  double dVelocity(0.0);
101 
102 
103 
104  // lock mutex
105  m_Mutex.lock();
106 
107  // get velocity from member
108  dVelocity = m_dVelocity;
109 
110  // unlock mutex
111  m_Mutex.unlock();
112 
113  // return current velocity
114  return (dVelocity);
115  // Bouml preserved body end 000D6602
116 
117 } // double COdometer::GetVelocity()
118 
119 
120 
121 
122 void COdometer::SetVelocity(const double& dVelocity) throw()
123 {
124  // Bouml preserved body begin 000D8202
125  ::std::chrono::duration< long long, ::std::chrono::system_clock::duration::period > Duration;
126 
127 
128 
129 
130  // lock mutex
131  m_Mutex.lock();
132 
133  // calculate duration with old velocity
134  Duration = ::std::chrono::system_clock::now() - m_LastCalculation;
135 
136  // calculate new position by integration (simplified by multiplication)
137  m_dPosition += m_dVelocity / 3.6 * double(Duration.count()) * (double(::std::chrono::system_clock::duration::period::num) / double(::std::chrono::system_clock::duration::period::den));
138 
139  // set new velocity in member
140  m_dVelocity = dVelocity;
141 
142  // set last calculation to now
143  m_LastCalculation = ::std::chrono::system_clock::now();
144 
145  // unlock mutex
146  m_Mutex.unlock();
147  // Bouml preserved body end 000D8202
148 
149 } // void COdometer::SetVelocity() throw()
150 
151 
152 
153 
154 void COdometer::ResetPosition(const double& dPosition) throw()
155 {
156  // Bouml preserved body begin 000D8282
157  // lock mutex
158  m_Mutex.lock();
159 
160  // set new position from parameter
161  m_dPosition = dPosition;
162 
163  // set last calculation to now
164  m_LastCalculation = ::std::chrono::system_clock::now();
165 
166  // unlock mutex
167  m_Mutex.unlock();
168  // Bouml preserved body end 000D8282
169 
170 } // void COdometer::ResetPosition() throw()
171 
172 
173 
174 
175 CServiceBrake::CServiceBrake(::oETCS::DF::PS::SIM::COdometer * const pOdometer, ::oETCS::DF::PS::SIM::CEmergencyBrake * const pEmergencyBrake, const double & dIntensity, const double & dMass, const double & dAdhesion) throw()
177  m_bCalculate(false),
178  m_dIntensity(dIntensity),
179  m_dMass(dMass),
180  m_dAdhesion(dAdhesion),
181  m_pOdometer(pOdometer),
182  m_pEmergencyBrake(pEmergencyBrake),
183  m_pPhysicalCalculation(nullptr)
184 {
185  // Bouml preserved body begin 000D8302
186  // check, if pointer to odometer is valid
187  if (m_pOdometer != nullptr)
188  {
189  try
190  {
191  // set calculate flag for thread to true
192  m_bCalculate = true;
193 
194  // try to create new thread object with thread method
195  m_pPhysicalCalculation = new ::std::thread(&::oETCS::DF::PS::SIM::CServiceBrake::OdometerThread, this);
196 
197  } // try
198  catch (const ::std::bad_alloc& Exception)
199  {
200  // print error message to stderr
201  ::std::cerr << "In file " << __FILE__ << " at line " << __LINE__ << ": creation of thread for physical calculation failed" << ::std::endl;
202 
203  // reset calculation flag
204  m_bCalculate = false;
205 
206  } // catch (const ::std::bad_alloc& Exception)
207 
208  } // if (m_pOdometer != nullptr)
209  // Bouml preserved body end 000D8302
210 
211 } // CServiceBrake::CServiceBrake() throw()
212 
213 
214 
215 
217 {
218  // Bouml preserved body begin 000D8382
219  // check, if calculation thread is executed
220  if (m_bCalculate)
221  {
222  // set calculation flag to false to notify thread
223  m_bCalculate = false;
224 
225  // check, if thread is joinable
226  if (m_pPhysicalCalculation->joinable())
227  {
228  // wait for thread to terminate
229  m_pPhysicalCalculation->join();
230 
231  } // if (m_pPhysicalCalculation->joinable())
232 
233  } // if (m_bCalculate)
234  // Bouml preserved body end 000D8382
235 
236 } // CServiceBrake::~CServiceBrake() throw()
237 
238 
239 
240 
242 {
243  // Bouml preserved body begin 000D8482
244  double dIntensity(0.0);
245 
246 
247 
248  // lock mutex
249  m_Mutex.lock();
250 
251  // copy value from member
252  dIntensity = m_dIntensity;
253 
254  // unlock mutex
255  m_Mutex.unlock();
256 
257  // return flag
258  return (dIntensity);
259  // Bouml preserved body end 000D8482
260 
261 } // double CServiceBrake::GetIntensity()
262 
263 
264 
265 
266 void CServiceBrake::SetIntensity(const double& dIntensity)
267 {
268  // Bouml preserved body begin 000D8402
269  // lock mutex
270  m_Mutex.lock();
271 
272  // check, if value is in accepted range (0 - 100)
273  if (dIntensity < 0.0)
274  {
275  // set local intensity to 0.0
276  m_dIntensity = 0.0;
277 
278  } // if (dIntensity < 0.0)
279  else if (dIntensity > 100.0)
280  {
281  // set local intensity to 100.0
282  m_dIntensity = 100.0;
283 
284  } // else if (dIntensity > 100.0)
285  else
286  {
287  // copy value from parameter to member
288  m_dIntensity = dIntensity;
289 
290  } // else
291 
292  // unlock mutex
293  m_Mutex.unlock();
294  // Bouml preserved body end 000D8402
295 
296 } // void CServiceBrake::SetIntensity()
297 
298 
299 
300 
301 void CServiceBrake::SetMass(const double& dMass) throw()
302 {
303  // Bouml preserved body begin 000D8602
304  // lock mutex
305  m_Mutex.lock();
306 
307  // check, if value is in accepted range (> 0)
308  if (dMass < 0.0)
309  {
310  // set local value to 0.0
311  m_dMass = 0.0;
312 
313  } // if (dMass < 0.0)
314  else
315  {
316  // copy value from parameter to member
317  m_dMass = dMass;
318 
319  } // else
320 
321  // unlock mutex
322  m_Mutex.unlock();
323  // Bouml preserved body end 000D8602
324 
325 } // void CServiceBrake::SetMass() throw()
326 
327 
328 
329 
330 void CServiceBrake::SetAdhesion(const double& dAdhesion) throw()
331 {
332  // Bouml preserved body begin 000D8682
333  // lock mutex
334  m_Mutex.lock();
335 
336  // check, if value is in accepted range (0...1)
337  if (dAdhesion < 0.0)
338  {
339  // set local value to 0.0
340  m_dAdhesion = 0.0;
341 
342  } // if (dAdhesion < 0.0)
343  else if (dAdhesion > 1.0)
344  {
345  // set local value to 1.0
346  m_dAdhesion = 1.0;
347 
348  } // else if (dAdhesion > 1.0)
349  else
350  {
351  // copy value from parameter to member
352  m_dAdhesion = dAdhesion;
353 
354  } // else
355 
356  // unlock mutex
357  m_Mutex.unlock();
358  // Bouml preserved body end 000D8682
359 
360 } // void CServiceBrake::SetAdhesion() throw()
361 
362 
363 
364 
366 {
367  // Bouml preserved body begin 000D8502
368  long double dIntensity(0.0);
369  long double dAccelration(0.0);
370  long double dCurrentVelocity(0.0);
371  long double dNewVelocity(0.0);
372  const long double FRICTION_COEFICIENT(0.25);
373  const long double GRAVITATION_ACCELERATION(9.81);
374  ::std::chrono::high_resolution_clock::time_point StartTime;
375  ::std::chrono::high_resolution_clock::duration SleepTime;
376  const ::std::chrono::high_resolution_clock::duration SAMPLE_TIME(::std::chrono::microseconds(__DATA_FLOW_SAMPLE_TIME__));
377 
378 
379 
380 
381  // measure start time once
382  StartTime = ::std::chrono::high_resolution_clock::now();
383 
384  // execute thread while flag is true
385  while (m_bCalculate)
386  {
387  // get current velocity from odometer
388  dCurrentVelocity = m_pOdometer->GetVelocity();
389 
390  // lock mutex
391  m_Mutex.lock();
392 
393  // set intensity (take emergency brake into account, if available)
394  dIntensity = (m_pEmergencyBrake != nullptr && m_pEmergencyBrake->GetActivation()) ? 120.0 : m_dIntensity;
395 
396  // calculate negative acceleration in [km/h²] (with linear adaptation for mass)
397  dAccelration = ((dIntensity == 0.0 || dCurrentVelocity == 0.0) ? 0.0 : FRICTION_COEFICIENT * GRAVITATION_ACCELERATION * dIntensity / 100.0 * m_dAdhesion * (m_dMass / 10000.0 ) * 12960.0);
398 
399  // calculate sign of acceleration
400  dAccelration = dCurrentVelocity > 0 ? dAccelration : dAccelration * -1.0;
401 
402  // unlock mutex
403  m_Mutex.unlock();
404 
405  // calculate new velocity with negative acceleration and sample time
406  dNewVelocity = (dAccelration == 0.0 ? dCurrentVelocity : dCurrentVelocity - dAccelration * (__DATA_FLOW_SAMPLE_TIME__ * 1e-6) / 3600.0 );
407 
408  // DEBUG
409  //::std::cout << "CServiceBrake::OdometerThread(): deaccelration: " << dAccelration << " intensity: " << dIntensity << " current v:" << dCurrentVelocity << " new v:" << dNewVelocity << ::std::endl;
410 
411  // check, if new velocity has changed sign
412  if ((dNewVelocity < 0.0L && dCurrentVelocity >= 0.0L) || (dNewVelocity > 0.0L && dCurrentVelocity <= 0.0L))
413  {
414  // set velocity to 0.0 (train stopped)
415  dNewVelocity = 0.0L;
416 
417  } // if ((dNewVelocity < 0.0L && dCurrentVelocity >= 0.0L) || (dNewVelocity > 0.0L && dCurrentVelocity <= 0.0L))
418 
419  // set new velocity in odometer
420  m_pOdometer->SetVelocity(dNewVelocity);
421 
422  // compute sleep time by execution time until now
423  SleepTime = SAMPLE_TIME - (::std::chrono::high_resolution_clock::now() - StartTime);
424 
425  // check, if sample time was no exceeded
426  if (SleepTime.count() >= 0 )
427  {
428  // put thread to sleep
429  ::std::this_thread::sleep_for(SleepTime);
430 
431  } // if (SleepTime.count() >= 0 )
432  else
433  {
434  // print warning to stderr
435  ::std::cerr << "In file " << __FILE__ << " in line " << __LINE__ << ": sample time exceeded in thread" << std::endl;
436 
437  } // else
438 
439  // calculate next start time point to avoid global drifts
440  StartTime += SAMPLE_TIME;
441 
442  } // while (m_bCalculate)
443  // Bouml preserved body end 000D8502
444 
445 } // void CServiceBrake::OdometerThread() throw()
446 
447 
448 
449 
450 CEmergencyBrake::CEmergencyBrake(const bool & bActive) throw()
452  m_bActive(bActive)
453 {
454  // Bouml preserved body begin 000DA582
455  // empty constructor
456  // Bouml preserved body end 000DA582
457 
458 } // CEmergencyBrake::CEmergencyBrake() throw()
459 
460 
461 
462 
464 {
465  // Bouml preserved body begin 000DA602
466  // empty destructor
467  // Bouml preserved body end 000DA602
468 
469 } // CEmergencyBrake::~CEmergencyBrake() throw()
470 
471 
472 
473 
475 {
476  // Bouml preserved body begin 000DA702
477  bool bActive(false);
478 
479 
480 
481  // lock mutex
482  m_Mutex.lock();
483 
484  // get value from member
485  bActive = m_bActive;
486 
487  // unlock mutex
488  m_Mutex.unlock();
489 
490  // return flag
491  return (bActive);
492  // Bouml preserved body end 000DA702
493 
494 } // bool CEmergencyBrake::GetActivation()
495 
496 
497 
498 
499 void CEmergencyBrake::SetActivation(bool bActivated)
500 {
501  // Bouml preserved body begin 000DA802
502  #ifdef __OETCS_DF_SIM_DEBUG_OUTPUT__
503  // DEBUG
504  ::std::cout << "DEBUG: started CEmergencyBrake::SetActivation("<< bActivated << ")..." << ::std::flush;
505  #endif
506 
507  // lock mutex
508  m_Mutex.lock();
509 
510  #ifdef __OETCS_DF_SIM_DEBUG_OUTPUT__
511  // DEBUG
512  ::std::cout << "locked..." << ::std::flush;
513  #endif
514 
515  // set value of member from parameter
516  m_bActive = bActivated;
517 
518  // unlock mutex
519  m_Mutex.unlock();
520 
521  #ifdef __OETCS_DF_SIM_DEBUG_OUTPUT__
522  // DEBUG
523  ::std::cout << "done" << ::std::endl;
524  #endif
525  // Bouml preserved body end 000DA802
526 
527 } // void CEmergencyBrake::SetActivation()
528 
529 
530 
531 
533 : ::oETCS::DF::PS::CBaliseDeviceOut(nullptr)
534 {
535  // Bouml preserved body begin 000D8982
536  // empty constructor
537  // Bouml preserved body end 000D8982
538 
539 } // CBaliseDeviceOut::CBaliseDeviceOut() throw()
540 
541 
542 
543 
545 {
546  // Bouml preserved body begin 000D8A02
547  // empty destructor
548  // Bouml preserved body end 000D8A02
549 
550 } // CBaliseDeviceOut::~CBaliseDeviceOut() throw()
551 
552 
553 
554 
555 void CBaliseDeviceOut::SendTelegram(const ::QBitArray& Bits)
556 {
557  // Bouml preserved body begin 000D8A82
558  unsigned int x(0);
559  const unsigned int SIZE(Bits.size());
560 
561 
562 
563  // print prefix to stdout
564  ::std::cout << "Telegram sent: ";
565 
566  // print telegram bit-wise from MSB to LSB
567  for (x = SIZE - 1; x >= 0; x--)
568  {
569  // print current bit
570  ::std::cout << (Bits[x] ? "1" : "0");
571 
572  } // for (x = SIZE - 1; x >= 0; x--)
573 
574  // new line after each telegram
575  ::std::cout << ::std::endl;
576  // Bouml preserved body end 000D8A82
577 
578 } // void CBaliseDeviceOut::SendTelegram()
579 
580 
581 
582 
584 : ::oETCS::DF::PS::CBaliseDeviceIn(nullptr)
585 {
586  // Bouml preserved body begin 000DC182
587  // empty constructor
588  // Bouml preserved body end 000DC182
589 
590 } // CBaliseDeviceIn::CBaliseDeviceIn() throw()
591 
592 
593 
594 
596 {
597  // Bouml preserved body begin 000DC202
598  // empty destructor
599  // Bouml preserved body end 000DC202
600 
601 } // CBaliseDeviceIn::~CBaliseDeviceIn() throw()
602 
603 
604 
605 
606 void CBaliseDeviceIn::SetNewInputTelegram(const ::QBitArray& Bits) throw()
607 {
608  // Bouml preserved body begin 000DC302
609  ::QByteArray Bytes;
610  int by(0);
611  int bi(0);
612  const int BITS(Bits.size());
613  const int BYTES(BITS / 8 + (BITS % 8 == 0 ? 0 : 1));
614  char cByte(0);
615 
616 
617 
618  // resize byte array
619  Bytes.resize(BYTES);
620 
621  // process all bits byte-wise
622  for (by = 0; by < BYTES; by++)
623  {
624  // reset current byte
625  cByte = 0;
626 
627  // compose current byte bit-wise
628  for (bi = 0; bi < 8 && (bi + by * 8) < BITS; bi++)
629  {
630  // add current bit to current byte
631  cByte |= Bits[bi + by * 8] ? (1 << bi) : 0;
632 
633  } // for (bi = 0; bi < 8 && (bi + by * 8) < BITS; bi++)
634 
635  // add current byte to byte array
636  Bytes[by] = cByte;
637 
638  } // for (by = 0; by < BYTES; by++)
639 
640 
641  // emit signal with new telegram
642  Q_EMIT this->NewTelegram(Bytes, BITS);
643  // Bouml preserved body end 000DC302
644 
645 } // void CBaliseDeviceIn::SetNewInputTelegram() throw()
646 
647 
648 
649 
650 
651 
652 } // namespace oETCS::DF::PS::SIM
653 
654 } // namespace oETCS::DF::PS
655 
656 } // namespace oETCS::DF
657 
658 } // namespace oETCS

Copyright (C) 2010-2012 Johannes Feuser (feuser@uni-bremen.de)
The openETCS library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
The openETCS library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with the openETCS library. If not, see "http://www.gnu.org/licenses/.