EMANE  1.2.1
noiserecorder.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2014 - Adjacent Link LLC, Bridgewater, New Jersey
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * * Neither the name of Adjacent Link LLC nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "noiserecorder.h"
35 
37  const Microseconds & maxOffset,
38  const Microseconds & maxPropagation,
39  const Microseconds & maxDuration,
40  double dRxSensitivityMilliWatt):
41  totalWindowBins_{maxDuration/bin},
42  totalWheelBins_{(maxOffset + maxPropagation + 2 * maxDuration)/bin},
43  binSizeMicroseconds_{bin.count()},
44  wheel_{static_cast<std::size_t>(totalWheelBins_)},
45  dRxSensitivityMilliWatt_{dRxSensitivityMilliWatt},
46  maxEndOfReceptionBin_{},
47  minStartOfReceptionBin_{}
48 {}
49 
50 std::pair<EMANE::TimePoint,EMANE::TimePoint>
52  const TimePoint & txTime,
53  const Microseconds & offset,
54  const Microseconds & propagation,
55  const Microseconds & duration,
56  double dRxPower,
57  const std::vector<NEMId> & transmitters)
58 {
59  auto startOfReception = txTime + offset + propagation;
60 
61  auto endOfReception = startOfReception + duration;
62 
63  auto reportedStartOfReceptionBin = timepointToBin(startOfReception);
64 
65  auto endOfReceptionBin = timepointToBin(endOfReception,true);
66 
67  Microseconds::rep startOfReceptionBin{reportedStartOfReceptionBin};
68 
69  Microseconds::rep maxEoRBin{};
70 
71  // Determine the last EoR bin for the transmitter - we only
72  // allow one bin noise entry per transmitter. For multiple
73  // transmitters use the max EoR
74  for(const auto & transmitter : transmitters)
75  {
76  const auto iter = nemEoRBinMap_.find(transmitter);
77 
78  if(iter != nemEoRBinMap_.end())
79  {
80  maxEoRBin = std::max(iter->second,maxEoRBin);
81  }
82  }
83 
84  // adjust the SoR bin to be the next past max EoR bin
85  // if necessary
86  if(maxEoRBin >= reportedStartOfReceptionBin)
87  {
88  startOfReceptionBin = maxEoRBin + 1;
89  }
90 
91  // sanity check after any possible adjustments
92  if(startOfReceptionBin <= endOfReceptionBin)
93  {
94  auto nowBin = timepointToBin(now);
95 
96  auto durationBinCount = endOfReceptionBin - startOfReceptionBin + 1;
97 
98  auto startIndex = startOfReceptionBin % totalWheelBins_;
99 
100  if(nowBin - maxEndOfReceptionBin_ > totalWheelBins_)
101  {
102  // reset the max end of reception bin
103  // the last bin we received on
104  maxEndOfReceptionBin_ = 0;
105 
106 
107  // reset the min start of reception bin
108  // the first bin we received on
109  minStartOfReceptionBin_ = 0;
110  }
111 
112  if(!maxEndOfReceptionBin_ && !minStartOfReceptionBin_)
113  {
114  // we can fill the entire duration
115  wheel_.set(startIndex,durationBinCount,dRxPower);
116 
117  minStartOfReceptionBin_ = startOfReceptionBin;
118 
119  maxEndOfReceptionBin_ = endOfReceptionBin;
120  }
121  else
122  {
123  Microseconds::rep beforeDurationCount{};
124  Microseconds::rep afterDurationCount{};
125 
126  // set any values before the minStartOfReceptionBin
127  if(startOfReceptionBin < minStartOfReceptionBin_)
128  {
129  beforeDurationCount =
130  std::min(minStartOfReceptionBin_ - startOfReceptionBin,durationBinCount);
131 
132  wheel_.set(startIndex,beforeDurationCount,dRxPower);
133  }
134 
135  // set any values after the maxEndOfReceptionBin
136  if(endOfReceptionBin > maxEndOfReceptionBin_)
137  {
138  afterDurationCount =
139  std::min(endOfReceptionBin - maxEndOfReceptionBin_,durationBinCount);
140 
141  wheel_.set((startIndex + durationBinCount - afterDurationCount) % totalWheelBins_, afterDurationCount,dRxPower);
142  }
143 
144  auto remainderBinCount = durationBinCount - (beforeDurationCount + afterDurationCount);
145 
146  if(remainderBinCount)
147  {
148  // accumulate bins up to and including maxEndOfReceptionBin
149  wheel_.add((startIndex + beforeDurationCount) % totalWheelBins_,
150  remainderBinCount,
151  dRxPower);
152  }
153  else
154  {
155  // clear any gaps
156  if(beforeDurationCount)
157  {
158  wheel_.set((startIndex + durationBinCount) % totalWheelBins_,
159  minStartOfReceptionBin_ - endOfReceptionBin - 1,
160  0);
161  }
162  else
163  {
164  wheel_.set((maxEndOfReceptionBin_ + 1) % totalWheelBins_,
165  startOfReceptionBin - maxEndOfReceptionBin_ - 1,
166  0);
167  }
168  }
169 
170  if(beforeDurationCount)
171  {
172  minStartOfReceptionBin_ = startOfReceptionBin;
173  }
174 
175  if(afterDurationCount)
176  {
177  maxEndOfReceptionBin_ = endOfReceptionBin;
178  }
179  }
180 
181  // update the max EOR bin for all the transmitters
182  for(const auto & transmitter : transmitters)
183  {
184  nemEoRBinMap_[transmitter] = endOfReceptionBin;
185  }
186  }
187  //return {TimePoint{Microseconds{reportedStartOfReceptionBin} * binSizeMicroseconds_},
188  //TimePoint{Microseconds{endOfReceptionBin} * binSizeMicroseconds_}};
189  return {startOfReception,endOfReception};
190 }
191 
192 
193 std::pair<std::vector<double>, EMANE::TimePoint>
195  const Microseconds & duration,
196  const TimePoint & startTime)
197 {
198  auto nowBin = timepointToBin(now,true);
199 
200  auto minStartOfWindowTime =
201  TimePoint(Microseconds{nowBin - totalWindowBins_ + 1} * binSizeMicroseconds_);
202 
203  auto validStartTime = startTime;
204 
205  auto validDuration = duration;
206 
207  // no start time given, use minStartOfWindowTime
208  if(validStartTime == TimePoint::min())
209  {
210  validStartTime = minStartOfWindowTime;
211  }
212  else if(validStartTime < minStartOfWindowTime)
213  {
214  throw makeException<SpectrumServiceException>("window start time too far in the past");
215  }
216  else if(validStartTime > now)
217  {
218  throw makeException<SpectrumServiceException>("window start time in the future");
219  }
220 
221  auto startTimeBin = timepointToBin(validStartTime);
222 
223  auto endTime = now;
224 
225  if(validDuration != Microseconds::zero())
226  {
227  endTime = validStartTime + validDuration;
228 
229  if(endTime > now)
230  {
231  throw makeException<SpectrumServiceException>("window end time in the future");
232  }
233  }
234 
235  auto endTimeBin = timepointToBin(endTime,true);
236 
237  auto durationBinCount = endTimeBin - startTimeBin + 1;
238 
239  std::vector<double> window;
240 
241  window.reserve(durationBinCount);
242 
243  // if a startTime was specified that bin time equates window entry 0
244  auto startOfWindowTime =
245  TimePoint(Microseconds{startTimeBin} * binSizeMicroseconds_);
246 
247  if(startOfWindowTime >= minStartOfWindowTime)
248  {
249  if(maxEndOfReceptionBin_ && minStartOfReceptionBin_)
250  {
251  try
252  {
253  Microseconds::rep beforeDurationCount{};
254  Microseconds::rep afterDurationCount{};
255 
256  if(endTimeBin > maxEndOfReceptionBin_)
257  {
258  afterDurationCount =
259  std::min(endTimeBin - maxEndOfReceptionBin_,durationBinCount);
260  }
261 
262  if(startTimeBin < minStartOfReceptionBin_)
263  {
264  beforeDurationCount =
265  std::min(minStartOfReceptionBin_ - startTimeBin,durationBinCount);
266  }
267 
268  auto remainderBinCount =
269  durationBinCount - (beforeDurationCount + afterDurationCount);
270 
271  if(remainderBinCount)
272  {
273  window = wheel_.get((endTimeBin - afterDurationCount) % totalWheelBins_,remainderBinCount);
274  }
275 
276  window.insert(window.begin(),beforeDurationCount,0);
277  window.insert(window.end(),afterDurationCount,0);
278  }
280  {
281  throw makeException<SpectrumServiceException>("window internal access error");
282  }
283  }
284  else
285  {
286  // fill in window with 0
287  window.insert(window.begin(),durationBinCount,0);
288  }
289  }
290  else
291  {
292  throw makeException<SpectrumServiceException>("window start time invalid");
293  }
294 
295  return std::make_pair(std::move(window),startOfWindowTime);
296 }
297 
298 std::vector<double> EMANE::NoiseRecorder::dump() const
299 {
300  return wheel_.dump();
301 }
302 
303 EMANE::Microseconds::rep EMANE::NoiseRecorder::timepointToBin(const TimePoint & tp,bool bAdjust)
304 {
305  auto count =
306  std::chrono::duration_cast<Microseconds>(tp.time_since_epoch()).count();
307 
308  // times that fall on a bin boundary belong to the previous bin
309  // (count % binSizeMicroseconds_ == 0) will evaluate to 0 or 1
310  return count == 0 ? 0 : count / binSizeMicroseconds_ - (bAdjust && (count % binSizeMicroseconds_ == 0));
311 }
void set(std::size_t begin, std::size_t slots, T value)
Definition: wheel.inl:77
NoiseRecorder(const Microseconds &bin, const Microseconds &maxOffset, const Microseconds &maxPropagation, const Microseconds &maxDuration, double dRxSensitivityMilliWatt_)
std::vector< T > get(std::size_t begin, std::size_t slots)
Definition: wheel.inl:111
std::pair< std::vector< double >, TimePoint > get(const TimePoint &now, const Microseconds &duration=Microseconds::zero(), const TimePoint &startTime=TimePoint::min())
void add(std::size_t begin, std::size_t slots, T value)
Definition: wheel.inl:45
std::chrono::microseconds Microseconds
Definition: types.h:45
const std::vector< T > & dump() const
Definition: wheel.inl:39
std::pair< TimePoint, TimePoint > update(const TimePoint &now, const TimePoint &txTime, const Microseconds &offset, const Microseconds &propagation, const Microseconds &duration, double dRxPower, const std::vector< NEMId > &transmitters)
Clock::time_point TimePoint
Definition: types.h:50
std::vector< double > dump() const