Nebula
Loading...
Searching...
No Matches
extrapolator.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
34#include "timing/time.h"
35
36namespace Math
37{
38template<class TYPE> class Extrapolator
39{
40public:
44 ~Extrapolator() = default;
46 bool AddSample(Timing::Time packetTime, Timing::Time curTime, const TYPE& pos);
48 bool AddSample(Timing::Time packetTime, Timing::Time curTime, const TYPE& pos, const TYPE& vel);
50 void Reset(Timing::Time packetTime, Timing::Time curTime, const TYPE& pos);
52 void Reset(Timing::Time packetTime, Timing::Time curTime, const TYPE& pos, const TYPE& vel);
56 bool ReadValue(Timing::Time forTime, TYPE& oPos) const;
60 bool ReadValue(Timing::Time forTime, TYPE& oPos, TYPE& oVel) const;
65
67 bool Estimates(Timing::Time packetTime, Timing::Time curTime);
68
69 TYPE snapPos;
70 TYPE snapVel;
71 TYPE aimPos;
72 TYPE lastPacketPos; // only used when re-constituting velocity
73 Timing::Time snapTime; // related to this->snapPos
74 Timing::Time aimTime; // related to this->aimPos
75 Timing::Time lastPacketTime; // related to this->lastPacketPos
78};
79
80//------------------------------------------------------------------------------
83template<class TYPE>
85{
86 this->Reset(0, 0, TYPE());
87}
88
89//------------------------------------------------------------------------------
104template<class TYPE> bool
105Extrapolator<TYPE>::AddSample(Timing::Time packetTime, Timing::Time curTime, const TYPE& pos)
106{
107 // The best guess I can make for velocity is the difference between
108 // this sample and the last registered sample.
109 // if you use this function, TYPE must implement zero assignment
110 TYPE vel(0);
111 if (Math::abs(packetTime - this->lastPacketTime) > N_TINY) // 1e-4
112 {
113 float dt = (float)(1.0 / (packetTime - this->lastPacketTime));
114 vel = (pos - this->lastPacketPos) * dt;
115 }
116 return this->AddSample(packetTime, curTime, pos, vel);
117}
118
119//------------------------------------------------------------------------------
140template<class TYPE> bool
141Extrapolator<TYPE>::AddSample(Timing::Time packetTime, Timing::Time curTime, const TYPE& pos, const TYPE& vel)
142{
143 if (!Estimates(packetTime, curTime)) {
144 return false;
145 }
146 this->lastPacketPos = pos;
147 this->lastPacketTime = packetTime;
148 this->ReadValue(curTime, this->snapPos);
149 this->aimTime = curTime + this->updateTime;
150 float dt = (float)(this->aimTime - packetTime);
151 this->snapTime = curTime;
152 this->aimPos = pos + vel * dt;
153
154 // I now have two positions and two times:
155 // this->aimPos / this->aimTime
156 // this->snapPos / this->snapTime
157 // I must generate the interpolation velocity based on these two samples.
158 // However, if this->aimTime is the same as this->snapTime, I'm in trouble. In that
159 // case, use the supplied velocity.
160 if (Math::abs(this->aimTime - this->snapTime) < N_TINY)
161 {
162 this->snapVel = vel;
163 }
164 else
165 {
166 float dt = (float)(1.0 / (this->aimTime - this->snapTime));
167 this->snapVel = (this->aimPos - this->snapPos) * dt;
168 }
169 return true;
170}
171
172//------------------------------------------------------------------------------
180template<class TYPE> void
181Extrapolator<TYPE>::Reset(Timing::Time packetTime, Timing::Time curTime, const TYPE& pos)
182{
183 TYPE vel(0);
184 this->Reset(packetTime, curTime, pos, vel);
185}
186
187//------------------------------------------------------------------------------
195template<class TYPE> void
196Extrapolator<TYPE>::Reset(Timing::Time packetTime, Timing::Time curTime, const TYPE& pos, const TYPE& vel)
197{
198 n_assert(packetTime <= curTime);
199 this->lastPacketTime = packetTime;
200 this->lastPacketPos = pos;
201 this->snapTime = curTime;
202 this->snapPos = pos;
203 this->updateTime = curTime - packetTime;
204 this->latency = this->updateTime;
205 this->aimTime = curTime + this->updateTime;
206 this->snapVel = vel;
207 this->aimPos = this->snapPos + this->snapVel * (float)this->updateTime;
208}
209
210//------------------------------------------------------------------------------
223template<class TYPE> bool
225{
226 TYPE vel;
227 return this->ReadValue(forTime, oPos, vel);
228}
229
230//------------------------------------------------------------------------------
244template<class TYPE> bool
245Extrapolator<TYPE>::ReadValue(Timing::Time forTime, TYPE& oPos, TYPE& oVel) const
246{
247 bool ok = true;
248
249 // asking for something before the allowable time?
250 if (forTime < this->snapTime)
251 {
252 forTime = this->snapTime;
253 ok = false;
254 }
255
256 // asking for something very far in the future?
257 Timing::Time maxRange = this->aimTime + this->updateTime;
258 if (forTime > maxRange)
259 {
260 forTime = maxRange;
261 ok = false;
262 }
263
264 // calculate the interpolated position
265 oVel = this->snapVel;
266 oPos = this->snapPos + oVel * (float)(forTime - this->snapTime);
267
268 return ok;
269}
270
271//------------------------------------------------------------------------------
277template<class TYPE> Timing::Time
279{
280 return this->latency;
281}
282
283//------------------------------------------------------------------------------
288template<class TYPE> Timing::Time
290{
291 return this->updateTime;
292}
293
294//------------------------------------------------------------------------------
297template<class TYPE> bool
299{
300 if (packet <= this->lastPacketTime)
301 {
302 return false;
303 }
304
305 // The theory is that, if latency increases, quickly
306 // compensate for it, but if latency decreases, be a
307 // little more resilient; this is intended to compensate
308 // for jittery delivery.
309 Timing::Time lat = cur - packet;
310 if (lat < 0) lat = 0;
311 if (lat > this->latency)
312 {
313 this->latency = (this->latency + lat) * 0.5;
314 }
315 else
316 {
317 this->latency = (this->latency * 7 + lat) * 0.125;
318 }
319
320 // Do the same running average for update time.
321 // Again, the theory is that a lossy connection wants
322 // an average of a higher update time.
323 Timing::Time tick = packet - this->lastPacketTime;
324 if (tick > this->updateTime)
325 {
326 this->updateTime = (this->updateTime + tick) * 0.5;
327 }
328 else
329 {
330 this->updateTime = (this->updateTime * 7.0 + tick) * 0.125;
331 }
332
333 return true;
334}
335
336}
Timing::Time latency
Definition extrapolator.h:76
Timing::Time lastPacketTime
Definition extrapolator.h:75
Timing::Time EstimateUpdateTime() const
Definition extrapolator.h:289
TYPE lastPacketPos
Definition extrapolator.h:72
Timing::Time aimTime
Definition extrapolator.h:74
bool ReadValue(Timing::Time forTime, TYPE &oPos) const
Return an estimate of the interpolated position at a given global time (which typically will be great...
Definition extrapolator.h:224
~Extrapolator()=default
destructor
Timing::Time EstimateLatency() const
Definition extrapolator.h:278
Extrapolator()
constructor
Definition extrapolator.h:84
void Reset(Timing::Time packetTime, Timing::Time curTime, const TYPE &pos)
Re-set the Extrapolator's idea of time, velocity and position.
Definition extrapolator.h:181
bool AddSample(Timing::Time packetTime, Timing::Time curTime, const TYPE &pos)
add sample without velocity, velocity is compute from positions
Definition extrapolator.h:105
TYPE snapVel
Definition extrapolator.h:70
Timing::Time updateTime
Definition extrapolator.h:77
bool Estimates(Timing::Time packetTime, Timing::Time curTime)
is this packet newer than already received
Definition extrapolator.h:298
TYPE snapPos
Definition extrapolator.h:69
Timing::Time snapTime
Definition extrapolator.h:73
TYPE aimPos
Definition extrapolator.h:71
#define n_assert(exp)
Definition debug.h:50
Different curves.
Definition angularpfeedbackloop.h:17
__forceinline scalar abs(scalar a)
Definition scalar.h:441
double Time
the time datatype
Definition time.h:18
#define N_TINY
Definition scalar.h:43
Typedefs for the Timing subsystem.