SIMLIB/C++  3.07
delay.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 //! \file delay.cc Delay block implementation (experimental)
3 //
4 // Copyright (c) 1991-2004 Petr Peringer
5 //
6 // This library is licensed under GNU Library GPL. See the file COPYING.
7 //
8 
9 //
10 // This module contains implementation of continuous delay class
11 //
12 // classes:
13 // Delay -- real delay blocks
14 // SIMLIB_Delay -- internal class for registration of delay blocks
15 // SIMLIB_DelayBuffer -- delay memory
16 //
17 // LIMITS:
18 // dt <= MaxStep --- problem with too small delay time
19 // increasing dt --- problem with buffer length
20 //
21 
22 ////////////////////////////////////////////////////////////////////////////
23 // interface
24 //
25 
26 #include "simlib.h"
27 #include "delay.h" // extra header, TODO: move to simlib.h
28 #include "internal.h"
29 
30 #include <deque> // for buffer implementation
31 #include <list> // for registration list of all delay blocks
32 
33 
34 ////////////////////////////////////////////////////////////////////////////
35 // implementation
36 //
37 
38 namespace simlib3 {
39 
41 
42 ////////////////////////////////////////////////////////////////////////////
43 /// continuous delay block
44 class SIMLIB_Delay {
45  static std::list<Delay *> *listptr; //!< list of delay objects -- singleton
46  public:
47  static void Register(Delay *p) { //!< must be called by Delay ctr
48  if( listptr == 0 ) Initialize();
49  listptr->push_back(p);
50  }
51  static void UnRegister(Delay *p) {//!< must be called from Delay destructor
52  listptr->remove(p);
53  if( listptr->empty() ) Destroy();// is really important???
54  }
55  private:
56  static void Initialize() { //!< initialize delay subsystem
57  listptr = new std::list<Delay*>(); // create new list of delays
58  // install 'hooks' into simulation control algorithm:
60  INSTALL_HOOK( DelayInit, SIMLIB_Delay::InitAll );
61  }
62  static void Destroy() { //!< should be called by ExitSimulation()? ###???
63  delete listptr; // remove list
64  listptr = 0;
65  // disable hooks into simulation control algorithm
66  INSTALL_HOOK( Delay, 0 );
67  INSTALL_HOOK( DelayInit, 0 );
68  }
69  /// function to scan inputs of all delay objects
70  static void SampleAll() { // called each continuous step (and more)
71  if( listptr == 0 ) return; // ### should never be reached (2remove)
72  std::list<Delay *>::iterator i;
73  for( i=listptr->begin(); i!=listptr->end(); ++i) // for each delay object
74  (*i)->Sample(); // sample input value
75  }
76  /// function to initialize all delay objects
77  static void InitAll() { // called at Init()
78  if( listptr == 0 ) return; // no delays ###
79  std::list<Delay *>::iterator i;
80  for( i=listptr->begin(); i!=listptr->end(); ++i) // for each delay object
81  (*i)->Init(); // set initial value
82  }
83 };
84 
85 // static member must be initializad
86 std::list<Delay *> *SIMLIB_Delay::listptr = 0;
87 
88 
89 #ifndef SIMLIB_public_Delay_Buffer
90 /// abstract base class for delayed signal samples storage
91 struct Delay::Buffer {
92  virtual void put(double value, double time) = 0; //!< store value
93  virtual double get(double time) = 0; //!< read interpolated value
94  virtual void clear() = 0; //!< initialize buffer
95  virtual ~Buffer() {};
96 };
97 #endif
98 
99 /////////////////////////////////////////////////////////////////////////////
100 /// memory for delayed pairs (Time,value)
101 ///
102 /// This buffer inherits interface from Delay::Buffer (we can use various
103 /// implementations later)
104 /// method get() does linear interpolation ? TODO: should be split
105 ///
106 class SIMLIB_DelayBuffer : public Delay::Buffer { // memory for delayed signal
107  /// pair (t,val) for storing in buffer TODO: use std::tuple
108  struct Pair {
109  double time; //<! sample time
110  double value; //<! sampled value
111  Pair(double t, double v) : time(t), value(v) {}
112  bool operator == (Pair &p) { return p.time==time && p.value==value; }
113  };
114  std::deque<Pair> buf; //!< storage for samples
115  Pair last_insert; //!< last inserted value (for optimization)
116 
117  public:
118 
119  SIMLIB_DelayBuffer(): buf(), last_insert(-2,0) { /*empty*/ }
120 
121  virtual void clear() override {
122  last_insert = Pair(-2,0); // we need it for optimization
123  buf.clear(); // empty buffer
124  }
125 
126  virtual void put(double value, double time) override {
127  Pair p(time,value);
128 #ifndef NO_DELAY_OPTIMIZATION
129  // TODO: can be improved using interpolation
130  if( last_insert == p ) // do not allow duplicate records
131  return;
132  last_insert = p;
133 #endif
134  buf.push_back(p); // add at buffer end
135  }
136 
137  virtual double get(double time) override // get delayed value (with interpolation)
138  {
139  // TODO: this code is EXPERIMENTAL ### (needs optimization)
140  Pair p(-1,0);
141  Pair l(-1,0);
142  std::deque<Pair>::iterator i;
143  int n; // number of records (samples) skipped
144  // ASSERT: there should be at least one record in the buffer
145  for( n=0, i=buf.begin(); i!=buf.end(); ++i ) {
146  l = p;
147  p = *i;
148  n++;
149  if( p.time > time ) break;
150  }
151  // ASSERT: n>0
152  if( n < 2 ) // we want time before first recorded sample
153  return p.value; // use first buffer value as default
154  else { // there are at least two samples recorded
155  if( p.time < time ) { // delay too small ###
156  SIMLIB_error(DelayTimeErr);// TODO: ### do it better
157  }
158  // standard situation
159  const int LIMIT=2; // >=2 --- allows change of delay if bigger
160  // WARNING: slow for bigger LIMIT
161  // remove old items in buffer
162  for(; n>LIMIT; n--)
163  buf.pop_front(); // remove front records
164  // linear interpolation
165  double dt = p.time - l.time;
166  double dy = p.value - l.value;
167  if( dt <= 0.0) { // ASSERT: dt > 0
169  }
170  return l.value + dy*(time-l.time)/dt;
171  }
172  } // get
173 }; // class SIMLIB_DelayBuffer
174 
175 
176 /////////////////////////////////////////////////////////////////////////////
177 /// initialize and register delay block
178 Delay::Delay(Input i, double _dt, double ival) :
179  aContiBlock1( i ), // input block-expression
180  last_time( Time ), // last sample time
181  last_value( ival ), // last sample value
182  buffer( new SIMLIB_DelayBuffer ), // allocate delay buffer
183  dt( _dt ), // Parameter: delay time
184  initval( ival ) // initial value of delay block
185 {
186  Dprintf(("Delay::Delay(in=%p, dt=%g, ival=%g)", &i, _dt, ival));
187  SIMLIB_Delay::Register( this ); // register delay in list of delays
188  Init(); // initialize -- important for dynamically created delays
189 }
190 
191 /////////////////////////////////////////////////////////////////////////////
192 /// remove buffer and delay block from list
194 {
195  Dprintf(("Delay::~Delay()"));
196  delete buffer; // free the delay buffer
197  SIMLIB_Delay::UnRegister(this); // remove from delay list
198 }
199 
200 /////////////////////////////////////////////////////////////////////////////
201 /// initialize delay status
202 ///
203 /// called automatically by Init(....) function
204 /// initialize: buffer and last output value
205 /// WARNING: does not change dt ### (maybe problem for multiple experiments)
206 /// TODO: evaluate input expression of delay block?
207 void Delay::Init() {
208  buffer->clear(); // empty buffer
209  buffer->put( last_value=initval, last_time=Time ); // set initial value
210 }
211 
212 
213 /////////////////////////////////////////////////////////////////////////////
214 /// sample input value
216 {
217  Dprintf(("Delay::Sample()"));
218  buffer->put( InputValue(), Time ); // store into buffer
219 }
220 
221 /////////////////////////////////////////////////////////////////////////////
222 /// get delayed output value
223 double Delay::Value()
224 {
225  Dprintf(("Delay::Value()"));
226  double oldtime = Time - dt; // past time
227  if( last_time != oldtime ) { // is not already computed?
228  last_value = buffer->get( oldtime ); // get delayed value
229  last_time = oldtime;
230  }
231  return last_value;
232 }
233 
234 /////////////////////////////////////////////////////////////////////////////
235 /// change delay time
236 ///
237 /// TODO: EXPERIMENTAL --- this should be used with care
238 ///
239 double Delay::Set(double newdelay)
240 {
241  double last = dt;
242  if( newdelay>=0.0 && newdelay<=Time ) // FIXME: condition is too weak ###
243  dt = newdelay;
244  return last;
245 }
246 
247 } // namespace
248 
abstract base class for delayed signal samples storage
Definition: delay.cc:91
static void UnRegister(Delay *p)
Definition: delay.cc:51
static void InitAll()
function to initialize all delay objects
Definition: delay.cc:77
void Sample()
sample input (called automatically)
Definition: delay.cc:215
void SIMLIB_error(const enum _ErrEnum N)
print error message and abort program
Definition: error.cc:38
Delay(const Delay &)
continuous block connection (transparent reference) wrapper for pointer to objects of aContiBlock der...
Definition: simlib.h:895
double Value() override
output of continuous delay block
Definition: delay.cc:223
virtual void put(double value, double time)=0
store value
static void Initialize()
Definition: delay.cc:56
memory for delayed pairs (Time,value)
Definition: delay.cc:106
void Init()
initialize delay block
Definition: delay.cc:207
Implementation of class CalendarList interface is static - using global functions in SQS namespace...
Definition: algloop.cc:32
~Delay()
remove buffer and delay block from list
Definition: delay.cc:193
virtual double get(double time)=0
read interpolated value
virtual void clear() override
initialize buffer
Definition: delay.cc:121
const double & Time
model time (is NOT the block)
Definition: run.cc:48
static std::list< Delay * > * listptr
list of delay objects – singleton
Definition: delay.cc:45
Test t(F)
virtual ~Buffer()
Definition: delay.cc:95
double dt
Parameter: delay time (should be > MaxStep)
Definition: delay.h:47
double initval
initial value (used at start)
Definition: delay.h:48
bool operator==(const ParameterVector &p1, const ParameterVector &p2)
Definition: opt-param.cc:86
double Set(double newDT)
change delay time (EXPERIMENTAL)
Definition: delay.cc:239
Internal header file for SIMLIB/C++.
static void SampleAll()
function to scan inputs of all delay objects
Definition: delay.cc:70
Simple delay block interface.
continuous delay block
Definition: delay.cc:44
Main SIMLIB/C++ interface.
#define INSTALL_HOOK(name, function)
Definition: internal.h:255
SIMLIB_IMPLEMENTATION
Definition: algloop.cc:34
Buffer * buffer
memory for past values
Definition: delay.h:45
std::deque< Pair > buf
storage for samples
Definition: delay.cc:114
static void Destroy()
Definition: delay.cc:62
double last_time
memory for delayed signal samples
Definition: delay.h:40
static void Register(Delay *p)
Definition: delay.cc:47
double InputValue()
Definition: simlib.h:944
base for continuous blocks with single input and algebraic loop check
Definition: simlib.h:940
continuous signal delay block
Definition: delay.h:26
#define Dprintf(f)
Definition: internal.h:100
Pair last_insert
last inserted value (for optimization)
Definition: delay.cc:115
virtual void put(double value, double time) override
store value
Definition: delay.cc:126
Pair(double t, double v)
Definition: delay.cc:111
pair (t,val) for storing in buffer TODO: use std::tuple
Definition: delay.cc:108
virtual void clear()=0
initialize buffer
double last_value
last output value
Definition: delay.h:44