A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
uan-mac-rc-gw.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 University of Washington
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Leonard Tracy <lentracy@gmail.com>
19  */
20 
21 #include "uan-mac-rc-gw.h"
22 #include "uan-mac-rc.h"
23 #include "uan-header-common.h"
24 #include "uan-header-rc.h"
25 #include "uan-phy.h"
26 #include "uan-tx-mode.h"
27 
28 #include "ns3/assert.h"
29 #include "ns3/log.h"
30 #include "ns3/trace-source-accessor.h"
31 #include "ns3/nstime.h"
32 #include "ns3/double.h"
33 #include "ns3/uinteger.h"
34 
35 #include <cfloat>
36 #include <utility>
37 #include <set>
38 #include <map>
39 #include <vector>
40 #include <algorithm>
41 
42 NS_LOG_COMPONENT_DEFINE ("UanMacRcGw");
43 
44 namespace ns3 {
45 
46 NS_OBJECT_ENSURE_REGISTERED (UanMacRcGw);
47 
48 bool
50 {
51  return a.GetAsInt () < b.GetAsInt ();
52 }
53 
54 
56  : UanMac (),
57  m_state (IDLE),
58  m_currentRateNum (0),
59  m_cleared (false)
60 {
61  UanHeaderCommon ch;
62  UanHeaderRcRts rts;
63  UanHeaderRcCts cts;
64  UanHeaderRcAck ack;
66 
71 
72  NS_LOG_DEBUG ("Gateway initialized");
73 }
74 
76 {
77 }
78 
79 void
81 {
82  if (m_cleared)
83  {
84  return;
85  }
86  m_cleared = true;
87  if (m_phy)
88  {
89  m_phy->Clear ();
90  m_phy = 0;
91  }
92  m_propDelay.clear ();
93  std::map<UanAddress, AckData>::iterator it = m_ackData.begin ();
94  for (; it != m_ackData.end (); it++)
95  {
96  it->second.rxFrames.clear ();
97  }
98  m_ackData.clear ();
99  m_requests.clear ();
100  m_sortedRes.clear ();
101 }
102 
103 void
105 {
106  Clear ();
108 }
109 TypeId
111 {
112  static TypeId tid = TypeId ("ns3::UanMacRcGw")
113  .SetParent<UanMac> ()
114  .AddConstructor<UanMacRcGw> ()
115  .AddAttribute ("MaxReservations",
116  "Maximum number of reservations to accept per cycle",
117  UintegerValue (10),
118  MakeUintegerAccessor (&UanMacRcGw::m_maxRes),
119  MakeUintegerChecker<uint32_t> ())
120  .AddAttribute ("NumberOfRates",
121  "Number of rates per Phy layer",
122  UintegerValue (1023),
123  MakeUintegerAccessor (&UanMacRcGw::m_numRates),
124  MakeUintegerChecker<uint32_t> ())
125  .AddAttribute ("RetryRate",
126  "Number of retry rates per second at non-gateway nodes",
127  DoubleValue (1 / 10.0),
128  MakeDoubleAccessor (&UanMacRcGw::m_retryRate),
129  MakeDoubleChecker<double> ())
130  .AddAttribute ("MaxPropDelay",
131  "Maximum propagation delay between gateway and non-gateway nodes",
132  TimeValue (Seconds (2)),
133  MakeTimeAccessor (&UanMacRcGw::m_maxDelta),
134  MakeTimeChecker ())
135  .AddAttribute ("SIFS",
136  "Spacing between frames to account for timing error and processing delay",
137  TimeValue (Seconds (0.2)),
138  MakeTimeAccessor (&UanMacRcGw::m_sifs),
139  MakeTimeChecker ())
140  .AddAttribute ("NumberOfNodes",
141  "Number of non-gateway nodes in this gateway's neighborhood",
142  UintegerValue (10),
143  MakeUintegerAccessor (&UanMacRcGw::m_numNodes),
144  MakeUintegerChecker<uint32_t> ())
145  .AddAttribute ("MinRetryRate",
146  "Smallest allowed RTS retry rate",
147  DoubleValue (0.01),
148  MakeDoubleAccessor (&UanMacRcGw::m_minRetryRate),
149  MakeDoubleChecker<double> ())
150  .AddAttribute ("RetryStep",
151  "Retry rate increment",
152  DoubleValue (0.01),
153  MakeDoubleAccessor (&UanMacRcGw::m_retryStep),
154  MakeDoubleChecker<double> ())
155  .AddAttribute ("NumberOfRetryRates",
156  "Number of retry rates",
157  UintegerValue (100),
158  MakeUintegerAccessor (&UanMacRcGw::m_numRetryRates),
159  MakeUintegerChecker<uint16_t> ())
160  .AddAttribute ("TotalRate",
161  "Total available channel rate in bps (for a single channel, without splitting reservation channel)",
162  UintegerValue (4096),
163  MakeUintegerAccessor (&UanMacRcGw::m_totalRate),
164  MakeUintegerChecker<uint32_t> ())
165  .AddAttribute ("RateStep",
166  "Increments available for rate assignment in bps",
167  UintegerValue (4),
168  MakeUintegerAccessor (&UanMacRcGw::m_rateStep),
169  MakeUintegerChecker<uint32_t> ())
170  .AddAttribute ("FrameSize",
171  "Size of data frames in bytes",
172  UintegerValue (1000),
173  MakeUintegerAccessor (&UanMacRcGw::m_frameSize),
174  MakeUintegerChecker<uint32_t> ())
175  .AddTraceSource ("RX",
176  "A packet was destined for and received at this MAC layer",
178  .AddTraceSource ("Cycle",
179  "Trace cycle statistics",
181 
182  ;
183 
184  return tid;
185 }
186 
187 Address
189 {
190  return m_address;
191 }
192 
193 void
195 {
196  m_address = addr;
197 }
198 
199 bool
200 UanMacRcGw::Enqueue (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
201 {
202  NS_LOG_WARN ("RCMAC Gateway transmission to acoustic nodes is not yet implemented");
203  return false;
204 }
205 
206 void
208 {
209  m_forwardUpCb = cb;
210 }
211 
212 void
214 {
215  m_phy = phy;
218 }
219 
220 void
222 {
223 }
224 
225 Address
227 {
228  return UanAddress::GetBroadcast ();
229 }
230 
231 void
233 {
234  UanHeaderCommon ch;
235  pkt->PeekHeader (ch);
236 
237  if (ch.GetDest () == m_address || ch.GetDest () == UanAddress::GetBroadcast ())
238  {
239  m_rxLogger (pkt, mode);
240  }
241  else
242  {
243  return;
244  }
245 
246  pkt->RemoveHeader (ch);
247 
248  switch (ch.GetType ())
249  {
250  case UanMacRc::TYPE_DATA:
251  {
252  UanHeaderRcData dh;
253  pkt->RemoveHeader (dh);
254  m_propDelay[ch.GetSrc ()] = dh.GetPropDelay ();
255  if (m_ackData.find (ch.GetSrc ()) == m_ackData.end ())
256  {
257  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " GATEWAY Received unexpected data packet");
258  }
259  else
260  {
261  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " GW Received data packet from " << ch.GetSrc () << " length = " << pkt->GetSize ());
262  m_ackData[ch.GetSrc ()].rxFrames.insert (dh.GetFrameNo ());
263  }
264  m_forwardUpCb (pkt, ch.GetSrc ());
265  }
266  break;
268  case UanMacRc::TYPE_RTS:
269  if (m_state == CTSING)
270  {
271  return;
272  }
273 
274  {
275  UanHeaderRcRts rh;
276  pkt->RemoveHeader (rh);
277 
278  if (m_requests.find (ch.GetSrc ()) == m_requests.end ())
279  {
280  Request req;
281  req.numFrames = rh.GetNoFrames ();
282  req.rxTime = Simulator::Now ();
283  req.frameNo = rh.GetFrameNo ();
284  req.retryNo = rh.GetRetryNo ();
285  req.length = rh.GetLength ();
286  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " GW storing reservation from " << ch.GetSrc () << " with length " << req.length);
287  m_requests.insert (std::make_pair (ch.GetSrc (), req));
288  std::map<UanAddress, Time>::iterator it = m_propDelay.find (ch.GetSrc ());
289  if (it == m_propDelay.end ())
290  {
291  m_sortedRes.insert (std::make_pair (m_maxDelta, ch.GetSrc ()));
292  }
293  else
294  {
295  m_sortedRes.insert (std::make_pair ( (*it).second, ch.GetSrc ()));
296  }
297  }
298  }
299  if (m_state == IDLE)
300  {
301  StartCycle ();
302  }
303  break;
304  case UanMacRc::TYPE_CTS:
305  NS_FATAL_ERROR ("Received CTS at GW. Currently only support single GW network!");
306  break;
307  case UanMacRc::TYPE_ACK:
308  NS_FATAL_ERROR ("Received ACK at GW. Currently only support single GW network!");
309  break;
310  default:
311  NS_FATAL_ERROR ("Received unknown packet at GW!");
312  }
313 }
314 
315 void
317 {
318  uint32_t numRts = m_sortedRes.size ();
319 
320  if (numRts)
321  {
322  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " Simulator starting non-empty cycle");
323  }
324  else
325  {
326  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " Simulator starting EMPTY cycle");
327  }
328 
329  // Calculate dataRate
330  uint32_t totalBytes = 0;
331  uint32_t totalFrames = 0;
332  double pDelay = 0;
333  if (numRts > 0)
334  {
335  std::map<UanAddress, Request>::iterator rit = m_requests.begin ();
336  for (; rit != m_requests.end (); rit++)
337  {
338  totalBytes += (*rit).second.length;
339  totalFrames += (*rit).second.numFrames;
340  }
341  pDelay = 2 * m_sortedRes.begin ()->first.GetSeconds ();
342  }
343 
344 
345  double minRate = m_phy->GetMode (m_numRates).GetDataRateBps ();
346 
347  uint32_t optA = m_maxRes;
348  if (m_maxRes == 0)
349  {
350  optA = FindOptA ();
351  }
352  double thAlpha = ComputeAlpha (totalFrames, totalBytes, m_numNodes, optA, pDelay / 2.0);
353 
354  double thCtlRate = m_totalRate * thAlpha;
355 
356  double temprate = (thCtlRate - minRate) / ((double) m_rateStep) + 0.5;
357  m_currentRateNum = (uint32_t) temprate;
359  {
361  }
362 
363  NS_LOG_DEBUG ("Found theoretical alpha: " << thAlpha << " Found associated rate = " << thCtlRate << " Giving rate number: " << temprate);
364  double thX = thAlpha * m_totalRate / (2.0 * m_numNodes * m_rtsSize * 8.0);
365 
366  double dataRate = m_phy->GetMode (m_currentRateNum).GetDataRateBps ();
367 
368 
369  if (thX < m_minRetryRate)
370  {
371  NS_LOG_WARN ("Gateway found optimum RTS retry rate is below minimum");
372  m_currentRetryRate = 0;
373  }
374  else
375  {
376  m_currentRetryRate = (uint16_t)((thX - m_minRetryRate) / m_retryStep + 0.5);
377  }
378 
379  double actualX = m_currentRetryRate * m_retryStep + m_minRetryRate;
380 
381  uint32_t ctlRate = m_phy->GetMode (m_currentRateNum + m_numRates).GetDataRateBps ();
382 
383 
384  double winSize = (double)(totalBytes) * 8.0 / dataRate + m_sifs.GetSeconds () * totalFrames + pDelay;
385  if (numRts == 0)
386  {
387  winSize = (optA * std::exp (1.0) + 0.5) * 2.0 * 8.0 * m_rtsSize / (thAlpha * m_totalRate) + 2 * m_maxDelta.GetSeconds ();
388  }
389  double effWinSize = winSize - m_rtsSize * 8 / ctlRate - 2 * m_maxDelta.GetSeconds ();
390 
391 
392  // Before fast CTS/ACK(below)
393  double cycleSeconds = winSize + (totalFrames + 1.0) * m_sifs.GetSeconds () + m_ctsSizeG * 8.0 / dataRate + (m_ctsSizeN + m_ackSize) * 8.0 * numRts / dataRate;
394 
395  Time ctsTxTimeG = Seconds (m_ctsSizeG * 8.0 / dataRate);
396  Time ctsTxTimeTotal = Seconds (m_ctsSizeN * 8.0 * numRts / dataRate) + ctsTxTimeG;
397  if (numRts == 0)
398  {
400  ctsg.SetWindowTime (Seconds (effWinSize));
403  ctsg.SetTxTimeStamp (Simulator::Now ());
404 
406  Ptr<Packet> p = Create<Packet> ();
407  p->AddHeader (ctsg);
408  p->AddHeader (ch);
410 
411 
412  Simulator::Schedule (Seconds (cycleSeconds), &UanMacRcGw::StartCycle, this);
413  m_state = INCYCLE;
414  m_cycleLogger (Simulator::Now (), Seconds (0), numRts, totalBytes, effWinSize, ctlRate, actualX);
415  return;
416  }
417 
418  Time nextEarliest = ctsTxTimeTotal + m_sifs;
419 
420  m_state = CTSING;
421  Simulator::Schedule (nextEarliest, &UanMacRcGw::CycleStarted, this);
422 
423  std::set<std::pair<Time, UanAddress> >::iterator it = m_sortedRes.begin ();
424  Time minPdelay = (*it).first;
425  Ptr<Packet> cts = Create<Packet> ();
426 
427  for (; it != m_sortedRes.end (); it++)
428  {
429  Request req = m_requests[(*it).second];
430  Time pdelay = (*it).first;
431 
432  AckData newData;
433  newData.expFrames = req.numFrames;
434  newData.frameNo = req.frameNo;
435  UanAddress dest = (*it).second;
436  m_ackData.insert (std::make_pair (dest, newData));
437 
438  Time earliestArr = ctsTxTimeTotal + pdelay + pdelay + m_sifs;
439  Time arrivalTime = std::max (earliestArr, nextEarliest);
440  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " GW: Scheduling request for prop. delay " << pdelay.GetSeconds () << " for " << (*it).second << " Earliest possible arrival=" << earliestArr.GetSeconds () << " Next arrival time=" << nextEarliest.GetSeconds ());
441  nextEarliest = arrivalTime + Seconds (req.length * 8.0 / dataRate) + Seconds (m_sifs.GetSeconds () * req.numFrames);
442 
443  UanHeaderRcCts ctsh;
444  ctsh.SetAddress (dest);
445  ctsh.SetRtsTimeStamp (req.rxTime);
446  ctsh.SetFrameNo (req.frameNo);
447  ctsh.SetRetryNo (req.retryNo);
448  ctsh.SetDelayToTx (arrivalTime);
449  cts->AddHeader (ctsh);
450 
451  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " GW Scheduling reception for " << (uint32_t) req.numFrames << " frames at " << (Simulator::Now () + arrivalTime).GetSeconds () << " (delaytiltx of " << arrivalTime.GetSeconds () << ") Total length is " << req.length << " with txtime " << req.length * 8 / dataRate << " seconds");
452  }
453 
457  ctsg.SetWindowTime (Seconds (effWinSize));
458  ctsg.SetTxTimeStamp (Simulator::Now ());
459  UanHeaderCommon ch;
461  ch.SetSrc (m_address);
463  cts->AddHeader (ctsg);
464  cts->AddHeader (ch);
466 
467  m_requests.clear ();
468  m_sortedRes.clear ();
469  Simulator::Schedule (nextEarliest, &UanMacRcGw::EndCycle, this);
470 
471 
472  m_cycleLogger (Simulator::Now (), minPdelay, numRts, totalBytes, cycleSeconds, ctlRate, actualX);
473 }
474 
475 void
477 {
478  m_state = INCYCLE;
479 }
480 void
482 {
483 
484  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " GW Ending cycle");
485 
486  Time nextAck = Seconds (0);
487 
488  Time ackTime = Seconds (m_ackSize * 8.0 / m_phy->GetMode (m_currentRateNum).GetDataRateBps ());
489 
490  std::map<UanAddress, AckData>::iterator it = m_ackData.begin ();
491  for (; it != m_ackData.end (); it++)
492  {
493  UanAddress dest = (*it).first;
494  AckData &data = (*it).second;
495 
496  std::list<uint32_t> toNack;
497  for (uint32_t i = 0; i < data.expFrames; i++)
498  {
499  if (data.rxFrames.find (i) == data.rxFrames.end ())
500  {
501  toNack.push_back (i);
502  }
503  }
504  UanHeaderCommon ch;
505  ch.SetDest (dest);
506  ch.SetSrc (m_address);
508  UanHeaderRcAck ah;
509  ah.SetFrameNo (data.frameNo);
510  std::list<uint32_t>::iterator nit = toNack.begin ();
511  for (; nit != toNack.end (); nit++)
512  {
513  ah.AddNackedFrame (*nit);
514  }
515 
516  Ptr<Packet> ack = Create<Packet> ();
517  ack->AddHeader (ah);
518  ack->AddHeader (ch);
520  nextAck = nextAck + ackTime + m_sifs;
521  }
522  m_ackData.clear ();
524 
525 }
526 void
528 {
529  UanHeaderCommon ch;
530  pkt->PeekHeader (ch);
531  std::string type;
532  switch (ch.GetType ())
533  {
534  case UanMacRc::TYPE_DATA:
535  type = "DATA";
536  break;
537  case UanMacRc::TYPE_RTS:
538  type = "RTS";
539  break;
540  case UanMacRc::TYPE_CTS:
541  type = "CTS";
542  break;
543  case UanMacRc::TYPE_ACK:
544  type = "ACK";
545  break;
547  type = "GWPING";
548  break;
549  default:
550  type = "UNKNOWN";
551  break;
552  }
553  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " GW sending " << type << " packet with size " << pkt->GetSize () << " to " << ch.GetDest () << " at rate " << rate);
554  m_phy->SendPacket (pkt, rate);
555 }
556 
557 
558 double
559 UanMacRcGw::ComputeAlpha (uint32_t totalFrames, uint32_t totalBytes, uint32_t n, uint32_t a, double deltaK)
560 {
561 
562  double alpha;
563  double lrae = m_rtsSize * 8.0 * a * std::exp (1.0);
564  if (totalFrames == 0)
565  {
566 
567  alpha = (2.0 * lrae + 8.0 * m_rtsSize - std::sqrt (m_ctsSizeG * 8.0 * 8.0 * m_rtsSize + 2 * 8.0 * m_ctsSizeG * 8.0 * m_rtsSize * a * std::exp (1.0)) ) /
568  (2 * lrae + 8.0 * m_rtsSize - 8.0 * m_ctsSizeG);
569  }
570  else
571  {
572  double w = totalBytes * 8.0 + totalFrames*m_sifs.GetSeconds () * m_totalRate;
573  double v = m_rtsSize * 8.0 + 2 * lrae;
574  double u = (2 * m_maxDelta.GetSeconds () - 2 * deltaK) * m_totalRate;
575 
576  double gamma = (w - u + v) / (2 * (u - totalFrames * m_sifs.GetSeconds () * m_totalRate));
577 
578  alpha = -gamma + std::sqrt (gamma * gamma + v / (u - totalFrames * m_sifs.GetSeconds () * m_totalRate));
579 
580  if (alpha < 0 || alpha > 1)
581  {
582  alpha = -gamma - std::sqrt (gamma * gamma + v / (u - totalFrames * m_sifs.GetSeconds () * m_totalRate));
583  }
584  }
585  NS_ASSERT_MSG (alpha > 0 && alpha < 1, "Error computing alpha. Alpha out of valid range!");
586  return alpha;
587 }
588 
589 std::vector<double>
591 {
592  uint32_t n = m_numNodes;
593  std::vector<double> pds;
594  std::map<UanAddress, Time>::iterator pdit = m_propDelay.begin ();
595 
596  for (; pdit != m_propDelay.end (); pdit++)
597  {
598  pds.push_back (pdit->second.GetSeconds ());
599  }
600  while (pds.size () < m_numNodes)
601  {
602  pds.push_back (m_maxDelta.GetSeconds ());
603  }
604 
605  std::sort (pds.begin (), pds.end ());
606  // Find expected min. prop. delay for k nodes
607  std::vector<double> exppdk;
608  exppdk.push_back (m_maxDelta.GetSeconds ());
609  for (uint32_t k = 1; k <= n; k++)
610  {
611  uint32_t ind = CompExpMinIndex (n,k) - 1;
612  exppdk.push_back (pds[ind]);
613  }
614  return exppdk;
615 }
616 
617 double
618 UanMacRcGw::ComputeExpS (uint32_t a, uint32_t ld, std::vector<double> exppdk)
619 {
620  UanHeaderCommon ch;
621  uint32_t lh = ch.GetSerializedSize ();
622 
623  uint32_t n = m_numNodes;
624  double expk = n * (1 - std::exp (-((double) a) / (double) n));
625  NS_LOG_DEBUG ("expk = " << expk);
626 
627  // Compute expected data per cycle
628  double expdata = 8 * ld * expk;
629 
630  // Compute expected time per cycle
631  double alpha0 = ComputeAlpha (0,0,n,a,exppdk[0]);
632  double c0 = 8.0 * m_ctsSizeG / ( m_totalRate * (1 - alpha0)) + 2 * m_maxDelta.GetSeconds () + (a * std::exp (1.0) + 0.5) * 2 * m_rtsSize * 8.0 / (alpha0 * m_totalRate);
633  double exptime = ComputePiK (a,n,0) * c0;
634  double expp = 0;
635  for (uint32_t i = 1; i <= n; i++)
636  {
637  expp += ComputePiK (a,n,i) * exppdk[i - 1];
638  }
639 
640  exptime += ComputeExpBOverA (n,a,ld + lh,exppdk) + expk * 2 * m_sifs.GetSeconds () + m_sifs.GetSeconds () + 2 * expp;
641  double s = (1.0 / m_totalRate) * expdata / exptime;
642 
643  return s;
644 }
645 
646 double
647 UanMacRcGw::ComputeExpS (uint32_t a, uint32_t ld)
648 {
649  return ComputeExpS (a, ld, GetExpPdk ());
650 }
651 
652 uint32_t
653 UanMacRcGw::CompExpMinIndex (uint32_t n, uint32_t k)
654 {
655  double sum = 0;
656  for (uint32_t i = 1; i <= n - k + 1; i++)
657  {
658  double nChK = NchooseK (n, k);
659  double p = (nChK > 0) ? (NchooseK (n - i, k - 1) / nChK) : DBL_MAX;
660  sum += p * i;
661  }
662  return (uint32_t)(sum + 0.5);
663 }
664 
665 double
666 UanMacRcGw::ComputePiK (uint32_t a, uint32_t n, uint32_t k)
667 {
668  double nck = (double) NchooseK (n, k);
669  return nck * std::pow ( (std::exp ( (double) a / (double) n) - 1.0), (double) k) * std::exp (-( (double) a));
670 }
671 
672 double
673 UanMacRcGw::ComputeExpBOverA (uint32_t n, uint32_t a, uint32_t ldlh, std::vector<double> deltaK)
674 {
675 
676  double sum = 0;
677  uint32_t lt = 8 * (m_ctsSizeN + ldlh + m_ackSize);
678  for (uint32_t k = 1; k <= n; k++)
679  {
680  double num = 8.0 * m_ctsSizeG + k * lt;
681  double denom = (1.0 - ComputeAlpha (k, k * ldlh, n, a, deltaK[k])) * m_totalRate;
682  double pik = ComputePiK (a, n, k);
683  double term = pik * num / denom;
684 
685  sum += term;
686  }
687 
688  return sum;
689 }
690 
691 uint64_t
692 UanMacRcGw::NchooseK (uint32_t n, uint32_t k)
693 {
694  if (k > n)
695  {
696  return 0;
697  }
698 
699  if (k > n / 2)
700  {
701  k = n - k;
702  }
703 
704  double accum = 1;
705  for (uint32_t i = 1; i <= k; i++)
706  {
707  accum = accum * (n - k + i) / i;
708  }
709 
710  return (uint64_t)(accum + 0.5);
711 
712 }
713 
714 uint32_t
716 {
717  double tput = 0;
718  uint32_t a = 1;
719  while (1)
720  {
721 
722  double newtput = ComputeExpS (a, m_frameSize);
723  if (newtput < tput)
724  {
725  a--;
726  break;
727  }
728  else
729  {
730  tput = newtput;
731  a++;
732  }
733  }
734  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " GW: Found optimum a = " << a);
735  return a;
736 }
737 
738 int64_t
740 {
741  NS_LOG_FUNCTION (this << stream);
742  return 0;
743 }
744 
745 } // namespace ns3