SIMLIB/C++ 3.09
Loading...
Searching...
No Matches
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
38namespace simlib3 {
39
41
42////////////////////////////////////////////////////////////////////////////
43/// continuous delay block
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:
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
86std::list<Delay *> *SIMLIB_Delay::listptr = 0;
87
88
89#ifndef SIMLIB_public_Delay_Buffer
90/// abstract base class for delayed signal samples storage
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///
106class 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
178Delay::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?
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
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///
239double 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
Test t(F)
continuous signal delay block
Definition: delay.h:26
Delay(const Delay &)
double Value() override
output of continuous delay block
Definition: delay.cc:223
double last_time
memory for delayed signal samples
Definition: delay.h:43
void Init()
initialize delay block
Definition: delay.cc:207
double Set(double newDT)
change delay time (EXPERIMENTAL)
Definition: delay.cc:239
double last_value
last output value
Definition: delay.h:44
void Sample()
sample input (called automatically)
Definition: delay.cc:215
double initval
initial value (used at start)
Definition: delay.h:48
double dt
Parameter: delay time (should be > MaxStep)
Definition: delay.h:47
~Delay()
remove buffer and delay block from list
Definition: delay.cc:193
Buffer * buffer
memory for past values
Definition: delay.h:45
continuous block connection (transparent reference) wrapper for pointer to objects of aContiBlock der...
Definition: simlib.h:895
memory for delayed pairs (Time,value)
Definition: delay.cc:106
Pair last_insert
last inserted value (for optimization)
Definition: delay.cc:115
virtual void clear() override
initialize buffer
Definition: delay.cc:121
virtual double get(double time) override
read interpolated value
Definition: delay.cc:137
std::deque< Pair > buf
storage for samples
Definition: delay.cc:114
virtual void put(double value, double time) override
store value
Definition: delay.cc:126
continuous delay block
Definition: delay.cc:44
static void Destroy()
Definition: delay.cc:62
static std::list< Delay * > * listptr
list of delay objects – singleton
Definition: delay.cc:45
static void InitAll()
function to initialize all delay objects
Definition: delay.cc:77
static void SampleAll()
function to scan inputs of all delay objects
Definition: delay.cc:70
static void Initialize()
Definition: delay.cc:56
static void Register(Delay *p)
Definition: delay.cc:47
static void UnRegister(Delay *p)
Definition: delay.cc:51
base for continuous blocks with single input and algebraic loop check
Definition: simlib.h:940
double InputValue()
Definition: simlib.h:944
Simple delay block interface.
@ DelayTimeErr
Definition: errors.h:88
Internal header file for SIMLIB/C++.
#define Dprintf(f)
Definition: internal.h:100
#define INSTALL_HOOK(name, function)
Definition: internal.h:255
Implementation of class CalendarList interface is static - using global functions in SQS namespace.
Definition: algloop.cc:32
const double & Time
model time (is NOT the block)
Definition: run.cc:48
void SIMLIB_error(const enum _ErrEnum N)
print error message and abort program
Definition: error.cc:38
SIMLIB_IMPLEMENTATION
Definition: algloop.cc:34
Main SIMLIB/C++ interface.
abstract base class for delayed signal samples storage
Definition: delay.cc:91
virtual void put(double value, double time)=0
store value
virtual void clear()=0
initialize buffer
virtual double get(double time)=0
read interpolated value
virtual ~Buffer()
Definition: delay.cc:95
pair (t,val) for storing in buffer TODO: use std::tuple
Definition: delay.cc:108
Pair(double t, double v)
Definition: delay.cc:111