00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 #ifndef lint
00059 static const char rcsid[] =
00060 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/red.cc,v 1.76 2003/01/28 19:50:51 sfloyd Exp $ (LBL)";
00061 #endif
00062
00063 #include <math.h>
00064 #include <sys/types.h>
00065 #include "config.h"
00066 #include "template.h"
00067 #include "random.h"
00068 #include "flags.h"
00069 #include "delay.h"
00070 #include "red.h"
00071
00072 static class REDClass : public TclClass {
00073 public:
00074 REDClass() : TclClass("Queue/RED") {}
00075 TclObject* create(int argc, const char*const* argv) {
00076
00077
00078
00079 if (argc==5)
00080 return (new REDQueue(argv[4]));
00081 else
00082 return (new REDQueue("Drop"));
00083 }
00084 } class_red;
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 REDQueue::REDQueue(const char * trace) : link_(NULL), de_drop_(NULL), EDTrace(NULL), tchan_(0), idle_(1)
00097 {
00098
00099 if (strlen(trace) >=20) {
00100 printf("trace type too long - allocate more space to traceType in red.h and recompile\n");
00101 exit(0);
00102 }
00103 strcpy(traceType, trace);
00104 bind_bool("bytes_", &edp_.bytes);
00105 bind_bool("queue_in_bytes_", &qib_);
00106
00107
00108 bind("thresh_", &edp_.th_min_pkts);
00109 bind("maxthresh_", &edp_.th_max_pkts);
00110 bind("mean_pktsize_", &edp_.mean_pktsize);
00111 bind("idle_pktsize_", &edp_.idle_pktsize);
00112 bind("q_weight_", &edp_.q_w);
00113 bind("adaptive_", &edp_.adaptive);
00114 bind("cautious_", &edp_.cautious);
00115 bind("alpha_", &edp_.alpha);
00116 bind("beta_", &edp_.beta);
00117 bind("interval_", &edp_.interval);
00118 bind("feng_adaptive_",&edp_.feng_adaptive);
00119 bind("targetdelay_", &edp_.targetdelay);
00120 bind("top_", &edp_.top);
00121 bind("bottom_", &edp_.bottom);
00122 bind_bool("wait_", &edp_.wait);
00123 bind("linterm_", &edp_.max_p_inv);
00124 bind("mark_p_", &edp_.mark_p);
00125 bind_bool("setbit_", &edp_.setbit);
00126 bind_bool("gentle_", &edp_.gentle);
00127
00128
00129
00130
00131 bind_bool("summarystats_", &summarystats_);
00132 bind_bool("drop_tail_", &drop_tail_);
00133
00134
00135 bind_bool("drop_front_", &drop_front_);
00136
00137
00138 bind_bool("drop_rand_", &drop_rand_);
00139
00140
00141 bind_bool("ns1_compat_", &ns1_compat_);
00142
00143
00144 bind("ave_", &edv_.v_ave);
00145 bind("prob1_", &edv_.v_prob1);
00146 bind("curq_", &curq_);
00147 bind("cur_max_p_", &edv_.cur_max_p);
00148
00149
00150 q_ = new PacketQueue();
00151 pq_ = q_;
00152
00153 #ifdef notdef
00154 print_edp();
00155 print_edv();
00156 #endif
00157
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167 void REDQueue::initialize_params()
00168 {
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 if (edp_.q_w == 0.0) {
00183 edp_.q_w = 1.0 - exp(-1.0/edp_.ptc);
00184 } else if (edp_.q_w == -1.0) {
00185 double rtt = 3.0*(edp_.delay+1.0/edp_.ptc);
00186
00187 if (rtt < 0.1)
00188 rtt = 0.1;
00189 edp_.q_w = 1.0 - exp(-1.0/(10*rtt*edp_.ptc));
00190 } else if (edp_.q_w == -2.0) {
00191 edp_.q_w = 1.0 - exp(-10.0/edp_.ptc);
00192 }
00193
00194
00195
00196 if (edp_.th_min_pkts == 0) {
00197 edp_.th_min_pkts = 5.0;
00198
00199
00200 double targetqueue = edp_.targetdelay * edp_.ptc;
00201 if (edp_.th_min_pkts < targetqueue / 2.0 )
00202 edp_.th_min_pkts = targetqueue / 2.0 ;
00203 }
00204 if (edp_.th_max_pkts == 0)
00205 edp_.th_max_pkts = 3.0 * edp_.th_min_pkts;
00206
00207
00208 }
00209
00210 void REDQueue::reset()
00211 {
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 if (link_) {
00222 edp_.ptc = link_->bandwidth() / (8. * edp_.mean_pktsize);
00223 initialize_params();
00224 }
00225 if (edp_.th_max_pkts == 0)
00226 edp_.th_max_pkts = 3.0 * edp_.th_min_pkts;
00227
00228
00229
00230
00231 if (qib_) {
00232
00233 edp_.th_min = edp_.th_min_pkts * edp_.mean_pktsize;
00234 edp_.th_max = edp_.th_max_pkts * edp_.mean_pktsize;
00235
00236 } else {
00237 edp_.th_min = edp_.th_min_pkts;
00238 edp_.th_max = edp_.th_max_pkts;
00239 }
00240
00241 edv_.v_ave = 0.0;
00242 edv_.v_slope = 0.0;
00243 edv_.count = 0;
00244 edv_.count_bytes = 0;
00245 edv_.old = 0;
00246 edv_.v_a = 1 / (edp_.th_max - edp_.th_min);
00247 edv_.cur_max_p = 1.0 / edp_.max_p_inv;
00248 edv_.v_b = - edp_.th_min / (edp_.th_max - edp_.th_min);
00249 edv_.lastset = 0.0;
00250 if (edp_.gentle) {
00251 edv_.v_c = ( 1.0 - edv_.cur_max_p ) / edp_.th_max;
00252 edv_.v_d = 2 * edv_.cur_max_p - 1.0;
00253 }
00254
00255 idle_ = 1;
00256 if (&Scheduler::instance() != NULL)
00257 idletime_ = Scheduler::instance().clock();
00258 else
00259 idletime_ = 0.0;
00260
00261 if (debug_)
00262 printf("Doing a queue reset\n");
00263 Queue::reset();
00264 if (debug_)
00265 printf("Done queue reset\n");
00266 }
00267
00268
00269
00270
00271
00272
00273
00274 void REDQueue::updateMaxPFeng(double new_ave)
00275 {
00276 if ( edp_.th_min < new_ave && new_ave < edp_.th_max) {
00277 edv_.status = edv_.Between;
00278 }
00279 if (new_ave < edp_.th_min && edv_.status != edv_.Below) {
00280 edv_.status = edv_.Below;
00281 edv_.cur_max_p = edv_.cur_max_p / edp_.alpha;
00282
00283
00284 }
00285 if (new_ave > edp_.th_max && edv_.status != edv_.Above) {
00286 edv_.status = edv_.Above;
00287 edv_.cur_max_p = edv_.cur_max_p * edp_.beta;
00288
00289
00290 }
00291 }
00292
00293
00294
00295
00296
00297 void REDQueue::updateMaxP(double new_ave, double now)
00298 {
00299 double part = 0.4*(edp_.th_max - edp_.th_min);
00300
00301 if ( new_ave < edp_.th_min + part && edv_.cur_max_p > edp_.bottom) {
00302
00303 edv_.cur_max_p = edv_.cur_max_p * edp_.beta;
00304 edv_.lastset = now;
00305 } else if (new_ave > edp_.th_max - part && edp_.top > edv_.cur_max_p ) {
00306
00307 double alpha = edp_.alpha;
00308 if ( alpha > 0.25*edv_.cur_max_p )
00309 alpha = 0.25*edv_.cur_max_p;
00310 edv_.cur_max_p = edv_.cur_max_p + alpha;
00311 edv_.lastset = now;
00312 }
00313 }
00314
00315
00316
00317
00318
00319 double REDQueue::estimator(int nqueued, int m, double ave, double q_w)
00320 {
00321 double new_ave, old_ave;
00322
00323 new_ave = ave;
00324 while (--m >= 1) {
00325 new_ave *= 1.0 - q_w;
00326 }
00327 old_ave = new_ave;
00328 new_ave *= 1.0 - q_w;
00329 new_ave += q_w * nqueued;
00330
00331 double now = Scheduler::instance().clock();
00332 if (edp_.adaptive == 1) {
00333 if (edp_.feng_adaptive == 1)
00334 updateMaxPFeng(new_ave);
00335 else if (now > edv_.lastset + edp_.interval)
00336 updateMaxP(new_ave, now);
00337 }
00338 return new_ave;
00339 }
00340
00341
00342
00343
00344 Packet* REDQueue::deque()
00345 {
00346 Packet *p;
00347 if (summarystats_ && &Scheduler::instance() != NULL) {
00348 Queue::updateStats(qib_?q_->byteLength():q_->length());
00349 }
00350 p = q_->deque();
00351 if (p != 0) {
00352 idle_ = 0;
00353 } else {
00354 idle_ = 1;
00355
00356
00357
00358 if (&Scheduler::instance() != NULL)
00359 idletime_ = Scheduler::instance().clock();
00360 else
00361 idletime_ = 0.0;
00362 }
00363 return (p);
00364 }
00365
00366
00367
00368
00369 double
00370 REDQueue::calculate_p_new(double v_ave, double th_max, int gentle, double v_a,
00371 double v_b, double v_c, double v_d, double max_p)
00372 {
00373 double p;
00374 if (gentle && v_ave >= th_max) {
00375
00376
00377 p = v_c * v_ave + v_d;
00378 } else {
00379
00380
00381 p = v_a * v_ave + v_b;
00382 p *= max_p;
00383 }
00384 if (p > 1.0)
00385 p = 1.0;
00386 return p;
00387 }
00388
00389
00390
00391
00392
00393 double
00394 REDQueue::calculate_p(double v_ave, double th_max, int gentle, double v_a,
00395 double v_b, double v_c, double v_d, double max_p_inv)
00396 {
00397 double p = calculate_p_new(v_ave, th_max, gentle, v_a,
00398 v_b, v_c, v_d, 1.0 / max_p_inv);
00399 return p;
00400 }
00401
00402
00403
00404
00405 double
00406 REDQueue::modify_p(double p, int count, int count_bytes, int bytes,
00407 int mean_pktsize, int wait, int size)
00408 {
00409 double count1 = (double) count;
00410 if (bytes)
00411 count1 = (double) (count_bytes/mean_pktsize);
00412 if (wait) {
00413 if (count1 * p < 1.0)
00414 p = 0.0;
00415 else if (count1 * p < 2.0)
00416 p /= (2 - count1 * p);
00417 else
00418 p = 1.0;
00419 } else {
00420 if (count1 * p < 1.0)
00421 p /= (1.0 - count1 * p);
00422 else
00423 p = 1.0;
00424 }
00425 if (bytes && p < 1.0) {
00426 p = p * size / mean_pktsize;
00427 }
00428 if (p > 1.0)
00429 p = 1.0;
00430 return p;
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440 int
00441 REDQueue::drop_early(Packet* pkt)
00442 {
00443 hdr_cmn* ch = hdr_cmn::access(pkt);
00444
00445 edv_.v_prob1 = calculate_p_new(edv_.v_ave, edp_.th_max, edp_.gentle,
00446 edv_.v_a, edv_.v_b, edv_.v_c, edv_.v_d, edv_.cur_max_p);
00447 edv_.v_prob = modify_p(edv_.v_prob1, edv_.count, edv_.count_bytes,
00448 edp_.bytes, edp_.mean_pktsize, edp_.wait, ch->size());
00449
00450
00451 if (edp_.cautious == 1) {
00452
00453
00454
00455 int qsize = qib_?q_->byteLength():q_->length();
00456
00457 double pkts = edp_.ptc * 0.05;
00458 double fraction = pow( (1-edp_.q_w), pkts);
00459
00460 if ((double) qsize < fraction * edv_.v_ave) {
00461
00462
00463 return (0);
00464 }
00465 }
00466 double u = Random::uniform();
00467 if (edp_.cautious == 2) {
00468
00469
00470
00471 int qsize = qib_?q_->byteLength():q_->length();
00472
00473 double pkts = edp_.ptc * 0.05;
00474 double fraction = pow( (1-edp_.q_w), pkts);
00475
00476 double ratio = qsize / (fraction * edv_.v_ave);
00477 if (ratio < 1.0) {
00478
00479 u *= 1.0 / ratio;
00480 }
00481 }
00482 if (u <= edv_.v_prob) {
00483
00484 edv_.count = 0;
00485 edv_.count_bytes = 0;
00486 hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt));
00487 if (edp_.setbit && hf->ect() && edv_.v_prob1 < edp_.mark_p) {
00488 hf->ce() = 1;
00489
00490 return (0);
00491 } else {
00492 return (1);
00493 }
00494 }
00495 return (0);
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505 Packet*
00506 REDQueue::pickPacketForECN(Packet* pkt)
00507 {
00508 return pkt;
00509 }
00510
00511
00512
00513
00514
00515
00516 Packet*
00517 REDQueue::pickPacketToDrop()
00518 {
00519 int victim;
00520
00521 if (drop_front_)
00522 victim = min(1, q_->length()-1);
00523 else if (drop_rand_)
00524 victim = Random::integer(q_->length());
00525 else
00526 victim = q_->length() - 1;
00527
00528 return(q_->lookup(victim));
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 #define DTYPE_NONE 0
00549 #define DTYPE_FORCED 1
00550 #define DTYPE_UNFORCED 2
00551
00552 void REDQueue::enque(Packet* pkt)
00553 {
00554
00555
00556
00557
00558
00559
00560
00561 int m = 0;
00562 if (idle_) {
00563
00564
00565 double now = Scheduler::instance().clock();
00566
00567 idle_ = 0;
00568
00569
00570 if (edp_.cautious == 3) {
00571 double ptc = edp_.ptc *
00572 edp_.mean_pktsize / edp_.idle_pktsize;
00573 m = int(ptc * (now - idletime_));
00574 } else
00575 m = int(edp_.ptc * (now - idletime_));
00576 }
00577
00578
00579
00580
00581
00582 edv_.v_ave = estimator(qib_ ? q_->byteLength() : q_->length(), m + 1, edv_.v_ave, edp_.q_w);
00583
00584
00585 if (summarystats_) {
00586
00587 Queue::updateStats(qib_?q_->byteLength():q_->length());
00588 }
00589
00590
00591
00592
00593
00594
00595
00596 hdr_cmn* ch = hdr_cmn::access(pkt);
00597 ++edv_.count;
00598 edv_.count_bytes += ch->size();
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608 register double qavg = edv_.v_ave;
00609 int droptype = DTYPE_NONE;
00610 int qlen = qib_ ? q_->byteLength() : q_->length();
00611 int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_;
00612
00613 curq_ = qlen;
00614
00615 if (qavg >= edp_.th_min && qlen > 1) {
00616 if ((!edp_.gentle && qavg >= edp_.th_max) ||
00617 (edp_.gentle && qavg >= 2 * edp_.th_max)) {
00618 droptype = DTYPE_FORCED;
00619 } else if (edv_.old == 0) {
00620
00621
00622
00623
00624
00625
00626 edv_.count = 1;
00627 edv_.count_bytes = ch->size();
00628 edv_.old = 1;
00629 } else if (drop_early(pkt)) {
00630 droptype = DTYPE_UNFORCED;
00631 }
00632 } else {
00633
00634 edv_.v_prob = 0.0;
00635 edv_.old = 0;
00636 }
00637 if (qlen >= qlim) {
00638
00639 droptype = DTYPE_FORCED;
00640 }
00641
00642 if (droptype == DTYPE_UNFORCED) {
00643
00644 Packet *pkt_to_drop = pickPacketForECN(pkt);
00645
00646
00647
00648
00649 if (pkt_to_drop != pkt) {
00650 q_->enque(pkt);
00651 q_->remove(pkt_to_drop);
00652 pkt = pkt_to_drop;
00653 }
00654
00655
00656 if (de_drop_ != NULL) {
00657
00658
00659
00660
00661 if (EDTrace != NULL)
00662 ((Trace *)EDTrace)->recvOnly(pkt);
00663
00664 reportDrop(pkt);
00665 de_drop_->recv(pkt);
00666 }
00667 else {
00668 reportDrop(pkt);
00669 drop(pkt);
00670 }
00671 } else {
00672
00673 q_->enque(pkt);
00674
00675
00676 if (droptype == DTYPE_FORCED) {
00677
00678 pkt = pickPacketToDrop();
00679 q_->remove(pkt);
00680 reportDrop(pkt);
00681 drop(pkt);
00682 if (!ns1_compat_) {
00683
00684 edv_.count = 0;
00685 edv_.count_bytes = 0;
00686 }
00687 }
00688 }
00689 return;
00690 }
00691
00692 int REDQueue::command(int argc, const char*const* argv)
00693 {
00694 Tcl& tcl = Tcl::instance();
00695 if (argc == 2) {
00696 if (strcmp(argv[1], "reset") == 0) {
00697 reset();
00698 return (TCL_OK);
00699 }
00700 if (strcmp(argv[1], "early-drop-target") == 0) {
00701 if (de_drop_ != NULL)
00702 tcl.resultf("%s", de_drop_->name());
00703 return (TCL_OK);
00704 }
00705 if (strcmp(argv[1], "edrop-trace") == 0) {
00706 if (EDTrace != NULL) {
00707 tcl.resultf("%s", EDTrace->name());
00708 if (debug_)
00709 printf("edrop trace exists according to RED\n");
00710 }
00711 else {
00712 if (debug_)
00713 printf("edrop trace doesn't exist according to RED\n");
00714 tcl.resultf("0");
00715 }
00716 return (TCL_OK);
00717 }
00718 if (strcmp(argv[1], "trace-type") == 0) {
00719 tcl.resultf("%s", traceType);
00720 return (TCL_OK);
00721 }
00722 if (strcmp(argv[1], "printstats") == 0) {
00723 print_summarystats();
00724 return (TCL_OK);
00725 }
00726 }
00727 else if (argc == 3) {
00728
00729 if (strcmp(argv[1], "attach") == 0) {
00730 int mode;
00731 const char* id = argv[2];
00732 tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00733 if (tchan_ == 0) {
00734 tcl.resultf("RED: trace: can't attach %s for writing", id);
00735 return (TCL_ERROR);
00736 }
00737 return (TCL_OK);
00738 }
00739
00740 if (strcmp(argv[1], "link") == 0) {
00741 LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
00742 if (del == 0) {
00743 tcl.resultf("RED: no LinkDelay object %s",
00744 argv[2]);
00745 return(TCL_ERROR);
00746 }
00747
00748 link_ = del;
00749 edp_.ptc = link_->bandwidth() /
00750 (8. * edp_.mean_pktsize);
00751 edp_.delay = link_->delay();
00752 if (
00753 (edp_.q_w <= 0.0 || edp_.th_min_pkts == 0 ||
00754 edp_.th_max_pkts == 0))
00755 initialize_params();
00756 return (TCL_OK);
00757 }
00758 if (strcmp(argv[1], "early-drop-target") == 0) {
00759 NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
00760 if (p == 0) {
00761 tcl.resultf("no object %s", argv[2]);
00762 return (TCL_ERROR);
00763 }
00764 de_drop_ = p;
00765 return (TCL_OK);
00766 }
00767 if (strcmp(argv[1], "edrop-trace") == 0) {
00768 if (debug_)
00769 printf("Ok, Here\n");
00770 NsObject * t = (NsObject *)TclObject::lookup(argv[2]);
00771 if (debug_)
00772 printf("Ok, Here too\n");
00773 if (t == 0) {
00774 tcl.resultf("no object %s", argv[2]);
00775 return (TCL_ERROR);
00776 }
00777 EDTrace = t;
00778 if (debug_)
00779 printf("Ok, Here too too too %d\n", ((Trace *)EDTrace)->type_);
00780 return (TCL_OK);
00781 }
00782 if (!strcmp(argv[1], "packetqueue-attach")) {
00783 delete q_;
00784 if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
00785 return (TCL_ERROR);
00786 else {
00787 pq_ = q_;
00788 return (TCL_OK);
00789 }
00790 }
00791 }
00792 return (Queue::command(argc, argv));
00793 }
00794
00795
00796
00797
00798
00799
00800
00801
00802 void
00803 REDQueue::trace(TracedVar* v)
00804 {
00805 char wrk[500], *p;
00806
00807 if (((p = strstr(v->name(), "ave")) == NULL) &&
00808 ((p = strstr(v->name(), "prob")) == NULL) &&
00809 ((p = strstr(v->name(), "curq")) == NULL) &&
00810 ((p = strstr(v->name(), "cur_max_p"))==NULL) ) {
00811 fprintf(stderr, "RED:unknown trace var %s\n",
00812 v->name());
00813 return;
00814 }
00815
00816 if (tchan_) {
00817 int n;
00818 double t = Scheduler::instance().clock();
00819
00820 if (strstr(v->name(), "curq") != NULL) {
00821 sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
00822 } else {
00823 sprintf(wrk, "%c %g %g", *p, t,
00824 double(*((TracedDouble*) v)));
00825 }
00826 n = strlen(wrk);
00827 wrk[n] = '\n';
00828 wrk[n+1] = 0;
00829 (void)Tcl_Write(tchan_, wrk, n+1);
00830 }
00831 return;
00832 }
00833
00834
00835 void REDQueue::print_edp()
00836 {
00837 printf("mean_pktsz: %d\n", edp_.mean_pktsize);
00838 printf("bytes: %d, wait: %d, setbit: %d\n",
00839 edp_.bytes, edp_.wait, edp_.setbit);
00840 printf("minth: %f, maxth: %f\n", edp_.th_min, edp_.th_max);
00841 printf("max_p: %f, qw: %f, ptc: %f\n",
00842 (double) edv_.cur_max_p, edp_.q_w, edp_.ptc);
00843 printf("qlim: %d, idletime: %f\n", qlim_, idletime_);
00844 printf("=========\n");
00845 }
00846
00847 void REDQueue::print_edv()
00848 {
00849 printf("v_a: %f, v_b: %f\n", edv_.v_a, edv_.v_b);
00850 }
00851
00852 void REDQueue::print_summarystats()
00853 {
00854
00855 printf("True average queue: %5.3f", true_ave_);
00856 if (qib_)
00857 printf(" (in bytes)");
00858 printf(" time: %5.3f\n", total_time_);
00859 }
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872 void REDQueue::run_estimator(int nqueued, int m)
00873 {
00874 double f, f_sl, f_old;
00875
00876 f = edv_.v_ave;
00877 f_sl = edv_.v_slope;
00878 #define RED_EWMA
00879 #ifdef RED_EWMA
00880 while (--m >= 1) {
00881 f_old = f;
00882 f *= 1.0 - edp_.q_w;
00883 }
00884 f_old = f;
00885 f *= 1.0 - edp_.q_w;
00886 f += edp_.q_w * nqueued;
00887 #endif
00888 #ifdef RED_HOLT_WINTERS
00889 while (--m >= 1) {
00890 f_old = f;
00891 f += f_sl;
00892 f *= 1.0 - edp_.q_w;
00893 f_sl *= 1.0 - 0.5 * edp_.q_w;
00894 f_sl += 0.5 * edp_.q_w * (f - f_old);
00895 }
00896 f_old = f;
00897 f += f_sl;
00898 f *= 1.0 - edp_.q_w;
00899 f += edp_.q_w * nqueued;
00900 f_sl *= 1.0 - 0.5 * edp_.q_w;
00901 f_sl += 0.5 * edp_.q_w * (f - f_old);
00902 #endif
00903 edv_.v_ave = f;
00904 edv_.v_slope = f_sl;
00905 }
00906