[tor-commits] [sbws/maint-1.1] fix: doc: Reorganize Torflow aggregation

juga at torproject.org juga at torproject.org
Fri Feb 26 10:17:25 UTC 2021


commit a374a65ceb04d279f3285daa826255492cdedaf9
Author: juga0 <juga at riseup.net>
Date:   Thu Feb 18 12:30:59 2021 +0000

    fix: doc: Reorganize Torflow aggregation
    
    - reorganize sections
    - add diagrams and links
    - add pseudocode
    - remove math
    - correct statements
    
    So that it's more accurate and easier to understand.
---
 docs/source/activity_torflow_aggr.puml             |  64 +++
 docs/source/activity_torflow_scaling.puml          | 168 ++++++++
 .../activity_torflow_scaling_simplified.puml       | 132 ++++++
 .../activity_torflow_scaling_simplified1.puml      |  38 ++
 docs/source/images/activity_torflow_aggr.svg       |  52 +++
 docs/source/images/activity_torflow_scaling.svg    | 169 ++++++++
 .../images/activity_torflow_scaling_simplified.svg | 138 +++++++
 .../activity_torflow_scaling_simplified1.svg       |  47 +++
 docs/source/torflow_aggr.rst                       | 452 ++++++++++++---------
 9 files changed, 1071 insertions(+), 189 deletions(-)

diff --git a/docs/source/activity_torflow_aggr.puml b/docs/source/activity_torflow_aggr.puml
new file mode 100644
index 0000000..92a3f38
--- /dev/null
+++ b/docs/source/activity_torflow_aggr.puml
@@ -0,0 +1,64 @@
+ at startuml
+title "Activity diagram Torflow measurements aggregation."
+
+' Constants in consensus
+' :Wbd=0 Wbe=0 Wbg=4148 Wbm=10000 Wdb=10000 Web=10000 Wed=10000 Wee=10000 Weg=10000 Wem=10000 Wgb=10000 Wgd=0 Wgg=5852 Wgm=5852 Wmb=10000 Wmd=0 Wme=0 Wmg=4148 Wmm=10000;
+' Constants in code
+' ;IGNORE_GUARD = 0 GUARD_SAMPLE_RATE = 2*7*24*60*60 # 2wks MAX_AGE = 2*GUARD_SAMPLE_RATE;
+' ;K_p = 1.0 T_i =0 T_i_decay = 0 T_d = 0;
+' Initialization ConsensusJunk
+' :self.bwauth_pid_control = True
+' self.group_by_class = False
+' self.use_pid_tgt = False
+' self.use_circ_fails = False
+' self.use_best_ratio = True
+' self.use_desc_bw = True
+' self.use_mercy = False
+' self.guard_sample_rate = GUARD_SAMPLE_RATE
+' self.pid_max = 500.0
+' self.K_p = K_p = 1.0
+' self.T_i = T_i = 0
+' self.T_d = T_d = 0
+' self.T_i_decay = T_i_decay = 0
+' self.K_i = 0 = self.K_i_decay = Kd;
+
+partition "Initialize relays from consensus (prev_consensus)" {
+    :ns_list = c.get_network_status();
+    'some ordering i don't understand yet
+    :ns_list.sort(lambda x, y: int(y.bandwidth/10000.0 - x.bandwidth/10000.0));
+
+    :prev_consensus = {};
+    while (for i in range(0, len(ns_list))?)
+        :n = ns_list[i];
+        :n.list_rank = i;
+        :n.measured = False;
+        :prev_consensus["$"+n.idhex] = n;
+    endwhile
+    ' If any relay doesn't have bandwidth, exit
+}
+
+partition "Aggregate raw measurements (nodes)"
+    ' Read measurements
+    :nodes = {};
+    while (for line in bw_file?)
+        if (line.idhex not in nodes?) then (yes)
+            :n = Node();
+            :nodes[line.idhex] = n;
+            :n.add_line(line);
+        endif
+    endwhile
+    ' If not measurements, exit
+}
+
+partition "Assign consensus flags"
+    ' Assign flags (G, M, E) from consensus to measurements
+    while (for idhex in nodes.iterkeys()?)
+        if (idhex in prev_consensus?) then (yes)
+            :nodes[idhex].flags = prev_consensus[idhex].flags;
+        endif
+    endwhile
+}
+
+:scaling;
+
+ at enduml
diff --git a/docs/source/activity_torflow_scaling.puml b/docs/source/activity_torflow_scaling.puml
new file mode 100644
index 0000000..7f36f22
--- /dev/null
+++ b/docs/source/activity_torflow_scaling.puml
@@ -0,0 +1,168 @@
+ at startuml
+title "Torflow measurements scaling."
+
+' Own previous bwfile
+:prev_votes = VoteSet();
+note right
+initialize measurements from previous Bandwidth File
+end note
+' while (for n in nodes.itervalues()?)
+'     if (n.idhex in prev_votes.vote_map and n.idhex in prev_consensus) then (yes)
+'     endif
+' endwhile
+:tot_net_bw = 0;
+:;
+note right
+    for every measurement
+end note
+while (for n in nodes.itervalues()?)
+    ' Anything not set is initialized to 0 or None
+    :n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()];
+    :n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()];
+    :n.use_bw = n.desc_bw;
+    :n.pid_error = ...;
+    note right
+        if n.sbw_ratio > n.fbw_ratio:
+        #assert cs_junk.use_best_ratio == True
+        n.pid_error = (n.strm_bw - true_strm_avg[n.node_class()])
+                            / true_strm_avg[n.node_class()]
+        else:
+        n.pid_error = (n.filt_bw - true_filt_avg[n.node_class()])
+                            / true_filt_avg[n.node_class()]
+        0 <= n.pid_error <= 500.0
+    end note
+    if (n.idhex in prev_votes.vote_map?) then (yes)
+        :;
+        note right
+        if n.measured_at >
+        prev_votes.vote_map[n.idhex].measured_at;
+        end note
+        if (measurement newer?) then (yes)
+            :;
+            note right
+            if n.idhex in prev_consensus
+                and ("Guard" in prev_consensus[n.idhex].flags
+                and "Exit" not in prev_consensus[n.idhex].flags)
+            end note
+            if (in prev_consensus, \nis guard \nbut not exit?) then (yes)
+                :;
+                note right
+                if n.idhex not in prev_votes.vote_map
+                    or n.measured_at - prev_votes.vote_map[n.idhex].measured_at
+                        > cs_junk.guard_sample_rate:
+                        # cs_jung.guard_sample_rate = 2*7*24*60*60 # 2wks
+                end note
+                if (diff bigger than 2 weeks) then (yes)
+                    :;
+                    note right
+                    # full feedback
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                    cs_junk.K_p,
+                                    cs_junk.K_i,
+                                    cs_junk.K_d,
+                                    cs_junk.K_i_decay)
+                        = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                       1.0, 0, 0, 0)
+                    end note
+                    :self.prev_error = prev_vote.pid_error
+                    self.pid_bw = self.use_bw
+                        + self.use_bw * self.pid_error
+                        # + self.desc_bw * self.pid_error
+                    self.pid_error_sum = 0 + self.pid_error
+                    n.new_bw = self.pid_bw;
+                else (no)
+                    :;
+                    note right
+                    \# Use new measurement but not feedback
+                    n.copy_vote(prev_vote.vote_map[n.idhex]));
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                cs_junk.K_p,
+                                cs_junk.K_i,
+                                cs_junk.K_d,
+                                0.0, False)
+                    end note
+                    :\# self.new_bw = vote.bw * 1000
+                    self.pid_bw = vote.pid_bw
+                    self.pid_error_sum = vote.pid_error_sum
+                    self.pid_delta = vote.pid_delta
+
+                    n.new_bw = self.use_bw + self.use_bw * self_pid_error
+
+                    n.measured_at = prev_vote.measured_at
+                    n.pid_error = prev_vote.pid_error;
+                endif
+            ' No (G and noE)
+            else (no)
+                if (in prev_consensus, \nis guard and exit) then (yes)
+                    :;
+                    note right
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                            cs_junk.K_p*weight,
+                            cs_junk.K_i*weight,
+                            cs_junk.K_d*weight,
+                            cs_junk.K_i_decay)
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                1.0*1.0, 0, 0, 0)
+                    \# so, same code as for when diff is bigger than 2 weeks
+                    end note
+                    :self.prev_error = prev_vote.pid_error
+                    self.pid_bw = self.use_bw
+                        + self.use_bw * self.pid_error
+                        # + self.desc_bw * self.pid_error
+                    self.pid_error_sum = 0 + self.pid_error
+                    n.new_bw = self.pid_bw;
+                else (no)
+                    :;
+                    note right
+                    \#again, same code
+                    end note
+                    :self.prev_error = prev_vote.pid_error
+                    self.pid_bw = self.use_bw
+                        + self.use_bw * self.pid_error
+                        # + self.desc_bw * self.pid_error
+                    self.pid_error_sum = 0 + self.pid_error
+                    n.new_bw = self.pid_bw;
+                endif
+            endif
+        ' No new measurement (in prev bwfile, but havent check consensus), do not vote this round
+        else (no)
+            :;
+            note right
+            \# Reset values. Don't vote/sample this measurement round.
+            \# is in the previous bwfile, but haven't check the consensus
+            n.revert_to_vote(prev_votes.vote_map[n.idhex])
+            \# which calls again self.copy_vote(vote)
+            end note
+            :self.new_bw = prev_vote.bw*1000
+            self.pid_bw = prev_vote.pid_bw
+            self.pid_error_sum = prev_vote.pid_error_sum
+            self.pid_delta = prev_vote.pid_delta
+
+            self.pid_error = vote.pid_error
+            self.measured_at = vote.measured_at;
+
+        endif
+    ' Not in previous bwfile, usually only with authoritites, possibly not in conensus?
+    else (no)
+        ' :n.new_bw = n.use_bw + cs_junk.K_p*n.use_bw*n.pid_error = \n
+        :n.new_bw = n.use_bw + n.use_bw * n.pid_error
+        n.pid_error_sum = n.pid_error
+        n.pid_bw = n.new_bw;
+    endif
+    ' :n.change = n.new_bw - n.desc_bw;
+
+    ' For capping later
+    if (n.idhex in prev_consensus) then (yes)
+        if (prev_consensus[n.idhex].bandwidth != None) then (yes)
+            :prev_consensus[n.idhex].measured = True;
+            :tot_net_bw += n.new_bw;
+        endif
+    endif
+endwhile
+while (for n in nodes.itervalues()?)
+    :cap...;
+endwhile
+stop
+
+footer last updated 2021-01-08
+ at enduml
diff --git a/docs/source/activity_torflow_scaling_simplified.puml b/docs/source/activity_torflow_scaling_simplified.puml
new file mode 100644
index 0000000..c52dd09
--- /dev/null
+++ b/docs/source/activity_torflow_scaling_simplified.puml
@@ -0,0 +1,132 @@
+ at startuml
+title "Torflow measurements scaling with PID control (Per relay scaled bandwidth)."
+
+' Own previous bwfile
+:prev_votes = VoteSet();
+note right
+initialize measurements from previous Bandwidth File
+end note
+:tot_net_bw = 0;
+:;
+note right
+    for every measurement
+end note
+while (for n in nodes.itervalues()?)
+    partition "Intialize ratios and pid_error" {
+        ' Anything not set is initialized to 0 or None
+        :n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()];
+        :n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()];
+        :n.use_bw = n.desc_bw;
+        :n.pid_error = max(bwstrm_i / bwstrm, bwfilt_i / bwfilt) - 1;
+        note right
+            if n.sbw_ratio > n.fbw_ratio:
+            #assert cs_junk.use_best_ratio == True
+            n.pid_error = (n.strm_bw - true_strm_avg[n.node_class()])
+                                / true_strm_avg[n.node_class()]
+            else:
+            n.pid_error = (n.filt_bw - true_filt_avg[n.node_class()])
+                                / true_filt_avg[n.node_class()]
+            0 <= n.pid_error <= 500.0
+        end note
+    }
+    if (n.idhex in prev_votes.vote_map?) then (yes)
+        :;
+        note right
+        if n.measured_at >
+        prev_votes.vote_map[n.idhex].measured_at;
+        end note
+        if (measurement newer?) then (yes)
+            :;
+            note right
+            if n.idhex in prev_consensus
+                and ("Guard" in prev_consensus[n.idhex].flags=
+            end note
+            if (in prev_consensus, \nis guard?) then (yes)
+                :;
+                note right
+                if n.idhex not in prev_votes.vote_map
+                    or n.measured_at - prev_votes.vote_map[n.idhex].measured_at
+                        > cs_junk.guard_sample_rate:
+                        # cs_jung.guard_sample_rate = 2*7*24*60*60 # 2wks
+                end note
+                if (not exit diff NOT bigger than 2 weeks) then (yes)
+                    :;
+                    note right
+                    \# Use new measurement but not feedback
+                    n.copy_vote(prev_vote.vote_map[n.idhex]));
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                cs_junk.K_p,
+                                cs_junk.K_i,
+                                cs_junk.K_d,
+                                0.0, False)
+                    end note
+                    :\# self.new_bw = vote.bw * 1000
+                    self.pid_bw = vote.pid_bw
+                    self.pid_error_sum = vote.pid_error_sum
+                    self.pid_delta = vote.pid_delta
+
+                    n.new_bw = self.use_bw + self.use_bw * self_pid_error
+
+                    n.measured_at = prev_vote.measured_at
+                    n.pid_error = prev_vote.pid_error;
+                else (no)
+                    :;
+                    note right
+                    # full feedback
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                    cs_junk.K_p,
+                                    cs_junk.K_i,
+                                    cs_junk.K_d,
+                                    cs_junk.K_i_decay)
+                        = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                       1.0, 0, 0, 0)
+                    end note
+                    :self.prev_error = prev_vote.pid_error
+                    self.pid_bw = self.use_bw
+                        + self.use_bw * self.pid_error
+                        # + self.desc_bw * self.pid_error
+                    self.pid_error_sum = 0 + self.pid_error
+                    n.new_bw = self.pid_bw;
+                endif
+            endif
+        ' No new measurement (in prev bwfile, but havent check consensus), do not vote this round
+        else (no)
+            :;
+            note right
+            \# Reset values. Don't vote/sample this measurement round.
+            \# is in the previous bwfile, but haven't check the consensus
+            n.revert_to_vote(prev_votes.vote_map[n.idhex])
+            \# which calls again self.copy_vote(vote)
+            end note
+            :self.new_bw = prev_vote.bw*1000
+            self.pid_bw = prev_vote.pid_bw
+            self.pid_error_sum = prev_vote.pid_error_sum
+            self.pid_delta = prev_vote.pid_delta
+
+            self.pid_error = vote.pid_error
+            self.measured_at = vote.measured_at;
+
+        endif
+    ' Not in previous bwfile, usually only with authoritites, possibly not in conensus?
+    else (no)
+        ' :n.new_bw = n.use_bw + cs_junk.K_p*n.use_bw*n.pid_error = \n
+        :n.new_bw = n.use_bw + n.use_bw * n.pid_error
+        n.pid_error_sum = n.pid_error
+        n.pid_bw = n.new_bw;
+    endif
+    ' :n.change = n.new_bw - n.desc_bw;
+
+    ' For capping later
+    if (n.idhex in prev_consensus) then (yes)
+        if (prev_consensus[n.idhex].bandwidth != None) then (yes)
+            :prev_consensus[n.idhex].measured = True;
+            :tot_net_bw += n.new_bw;
+        endif
+    endif
+endwhile
+while (for n in nodes.itervalues()?)
+    :cap...;
+endwhile
+stop
+
+ at enduml
diff --git a/docs/source/activity_torflow_scaling_simplified1.puml b/docs/source/activity_torflow_scaling_simplified1.puml
new file mode 100644
index 0000000..b32b30d
--- /dev/null
+++ b/docs/source/activity_torflow_scaling_simplified1.puml
@@ -0,0 +1,38 @@
+ at startuml
+title "Torflow measurements scaling with PID control (Per relay scaled bandwidth)."
+
+' Own previous bwfile
+:prev_votes = VoteSet();
+:tot_net_bw = 0;
+:;
+note right
+    for every measurement
+end note
+while (for n in nodes.itervalues()?)
+    partition "Intialize ratios and pid_error" {
+        ' Anything not set is initialized to 0 or None
+        :n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()];
+        :n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()];
+        :n.use_bw = n.desc_bw;
+        :n.pid_error = max(n.fbw_ratio, n.sbw_ratio) - 1;
+    }
+    if (n.idhex in prev_votes.vote_map \nand not newer measurement?) then (yes)
+        :self.new_bw = prev_vote.bw*1000
+        self.measured_at = vote.measured_at;
+    ' Not in previous bwfile, usually only with authoritites, possibly not in conensus?
+    else (no)
+        :n.new_bw = n.use_bw + n.use_bw * n.pid_error;
+    endif
+
+    ' For capping later
+    if (n.idhex in prev_consensus \nand prev_consensus[n.idhex].bandwidth != None) then (yes)
+        :prev_consensus[n.idhex].measured = True
+        tot_net_bw += n.new_bw;
+    endif
+endwhile
+while (for n in nodes.itervalues()?)
+    :cap...;
+endwhile
+stop
+
+ at enduml
diff --git a/docs/source/images/activity_torflow_aggr.svg b/docs/source/images/activity_torflow_aggr.svg
new file mode 100644
index 0000000..f672ae7
--- /dev/null
+++ b/docs/source/images/activity_torflow_aggr.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1241px" preserveAspectRatio="none" style="width:517px;height:1241px;" version="1.1" viewBox="0 0 517 1241" width="517px" zoomAndPan="magnify"><defs><filter height="300%" id="fz6rz3k2gra6i" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><text fill="#000000" font-family="sans-serif" font-size="18" lengthAdjust="spacingAndGlyphs" textLength="490" x="12.5" y="26.708">"Activity diagram Torflow measurements aggregation."</text><rect fill="#FFFFFF" filter="url(#fz6rz3k2gra6i)" height="480.0781" style=
 "stroke: #000000; stroke-width: 2.0;" width="496" x="10" y="31.7549"/><path d="M362,32.7549 L362,41.0518 L352,51.0518 L10,51.0518 " fill="none" style="stroke: #000000; stroke-width: 2.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="342" x="13" y="45.75">Initialize relays from consensus (prev_consensus)</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="221" x="147.5" y="61.0518"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="201" x="157.5" y="82.1904">ns_list = c.get_network_status()</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="476" x="20" y="115.0205"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="456" x="30" y="136.
 1592">ns_list.sort(lambda x, y: int(y.bandwidth/10000.0 - x.bandwidth/10000.0))</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="155" x="180.5" y="168.9893"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="135" x="190.5" y="190.1279">prev_consensus = {}</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="98" x="209" y="266.958"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="78" x="219" y="288.0967">n = ns_list[i]</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="105" x="205.5" y="320.9268"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength=
 "85" x="215.5" y="342.0654">n.list_rank = i</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="146" x="185" y="389.8955"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="126" x="195" y="411.0342">n.measured = False</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="230" x="143" y="443.8643"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="210" x="153" y="465.0029">prev_consensus["$"+n.idhex] = n</text><polygon fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" points="175.5,222.958,340.5,222.958,352.5,234.958,340.5,246.958,175.5,246.958,163.5,234.958,175.5,222.958" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGl
 yphs" textLength="165" x="175.5" y="238.7661">for i in range(0, len(ns_list))?</text><rect fill="#FFFFFF" filter="url(#fz6rz3k2gra6i)" height="402.5742" style="stroke: #000000; stroke-width: 2.0;" width="287" x="119" y="522.6348"/><path d="M396,523.6348 L396,531.9316 L386,541.9316 L119,541.9316 " fill="none" style="stroke: #000000; stroke-width: 2.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="267" x="122" y="536.6299">Aggregate raw measurements (nodes)</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="93" x="211.5" y="558.9316"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="73" x="221.5" y="580.0703">nodes = {}</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="89" x="213.5" y="
 705.3027"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="69" x="223.5" y="726.4414">n = Node()</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="154" x="181" y="759.2715"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="134" x="191" y="780.4102">nodes[line.idhex] = n</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="116" x="200" y="813.2402"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="96" x="210" y="834.3789">n.add_line(line)</text><polygon fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" points="190.5,656.9004,325.5,656.9004,337.5,668.9004,325.5,680.9004,190.5,680.9004,178.5,668.9004,190.5,656.9004" style="stroke: #A80036; stro
 ke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="262" y="691.1108">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="135" x="190.5" y="672.7085">line.idhex not in nodes?</text><polygon fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" points="258,867.209,270,879.209,258,891.209,246,879.209,258,867.209" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" points="206.5,612.9004,309.5,612.9004,321.5,624.9004,309.5,636.9004,206.5,636.9004,194.5,624.9004,206.5,612.9004" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="103" x="206.5" y="628.7085">for line in bw_file?</text><rect fill="#FFFFFF" filter="url(#fz6rz3k2gra6i)" height="240.668" style="stroke: #000000; stroke-width: 2.0;" width="429" x="48" y="936.
 0107"/><path d="M221,937.0107 L221,945.3076 L211,955.3076 L48,955.3076 " fill="none" style="stroke: #000000; stroke-width: 2.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="163" x="51" y="950.0059">Assign consensus flags</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="332" x="92" y="1064.71"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="312" x="102" y="1085.8486">nodes[idhex].flags = prev_consensus[idhex].flags</text><polygon fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" points="184.5,1016.3076,331.5,1016.3076,343.5,1028.3076,331.5,1040.3076,184.5,1040.3076,172.5,1028.3076,184.5,1016.3076" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="262" y="1050.5181">yes</tex
 t><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="147" x="184.5" y="1032.1157">idhex in prev_consensus?</text><polygon fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" points="258,1118.6787,270,1130.6787,258,1142.6787,246,1130.6787,258,1118.6787" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" points="175,972.3076,341,972.3076,353,984.3076,341,996.3076,175,996.3076,163,984.3076,175,972.3076" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="166" x="175" y="988.1157">for idhex in nodes.iterkeys()?</text><rect fill="#FEFECE" filter="url(#fz6rz3k2gra6i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="64" x="226" y="1196.6787"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="44" x="236" y="12
 17.8174">scaling</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="95.0205" y2="115.0205"/><polygon fill="#A80036" points="254,105.0205,258,115.0205,262,105.0205,258,109.0205" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="148.9893" y2="168.9893"/><polygon fill="#A80036" points="254,158.9893,258,168.9893,262,158.9893,258,162.9893" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="300.9268" y2="320.9268"/><polygon fill="#A80036" points="254,310.9268,258,320.9268,262,310.9268,258,314.9268" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="354.8955" y2="389.8955"/><polygon fill="#A80036" points="254,379.8955,258,389.8955,262,379.8955,258,383.8955" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258"
  y1="423.8643" y2="443.8643"/><polygon fill="#A80036" points="254,433.8643,258,443.8643,262,433.8643,258,437.8643" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="246.958" y2="266.958"/><polygon fill="#A80036" points="254,256.958,258,266.958,262,256.958,258,260.958" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="477.833" y2="487.833"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="385" y1="487.833" y2="487.833"/><polygon fill="#A80036" points="381,370.3955,385,360.3955,389,370.3955,385,366.3955" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="385" x2="385" y1="234.958" y2="487.833"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="385" x2="352.5" y1="234.958" y2="234.958"/><polygon fill="#A80036" points="362.5,230.958,352.5,234.958,362.5,238.958,358.5,234.958" style="stroke: 
 #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="163.5" x2="131" y1="234.958" y2="234.958"/><polygon fill="#A80036" points="127,356.3955,131,366.3955,135,356.3955,131,360.3955" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="131" x2="131" y1="234.958" y2="499.833"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="131" x2="258" y1="499.833" y2="499.833"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="499.833" y2="558.9316"/><polygon fill="#A80036" points="254,548.9316,258,558.9316,262,548.9316,258,552.9316" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="202.958" y2="222.958"/><polygon fill="#A80036" points="254,212.958,258,222.958,262,212.958,258,216.958" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="739.2715" y2="759.2715"/><polyg
 on fill="#A80036" points="254,749.2715,258,759.2715,262,749.2715,258,753.2715" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="793.2402" y2="813.2402"/><polygon fill="#A80036" points="254,803.2402,258,813.2402,262,803.2402,258,807.2402" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="680.9004" y2="705.3027"/><polygon fill="#A80036" points="254,695.3027,258,705.3027,262,695.3027,258,699.3027" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="337.5" x2="349.5" y1="668.9004" y2="668.9004"/><polygon fill="#A80036" points="345.5,766.2559,349.5,776.2559,353.5,766.2559,349.5,770.2559" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.5" x2="349.5" y1="668.9004" y2="879.209"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.5" x2="270" y1="879.20
 9" y2="879.209"/><polygon fill="#A80036" points="280,875.209,270,879.209,280,883.209,276,879.209" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="847.209" y2="867.209"/><polygon fill="#A80036" points="254,857.209,258,867.209,262,857.209,258,861.209" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="636.9004" y2="656.9004"/><polygon fill="#A80036" points="254,646.9004,258,656.9004,262,646.9004,258,650.9004" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="891.209" y2="901.209"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="369" y1="901.209" y2="901.209"/><polygon fill="#A80036" points="365,774.2559,369,764.2559,373,774.2559,369,770.2559" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="369" x2="369" y1="624.9004" y2="
 901.209"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="369" x2="321.5" y1="624.9004" y2="624.9004"/><polygon fill="#A80036" points="331.5,620.9004,321.5,624.9004,331.5,628.9004,327.5,624.9004" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="194.5" x2="159" y1="624.9004" y2="624.9004"/><polygon fill="#A80036" points="155,760.2559,159,770.2559,163,760.2559,159,764.2559" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="159" x2="159" y1="624.9004" y2="913.209"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="159" x2="258" y1="913.209" y2="913.209"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="913.209" y2="972.3076"/><polygon fill="#A80036" points="254,962.3076,258,972.3076,262,962.3076,258,966.3076" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="592.9004" y2="612.9004"/><polygo
 n fill="#A80036" points="254,602.9004,258,612.9004,262,602.9004,258,606.9004" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="1040.3076" y2="1064.71"/><polygon fill="#A80036" points="254,1054.71,258,1064.71,262,1054.71,258,1058.71" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="343.5" x2="434" y1="1028.3076" y2="1028.3076"/><polygon fill="#A80036" points="430,1071.6943,434,1081.6943,438,1071.6943,434,1075.6943" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="434" x2="434" y1="1028.3076" y2="1130.6787"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="434" x2="270" y1="1130.6787" y2="1130.6787"/><polygon fill="#A80036" points="280,1126.6787,270,1130.6787,280,1134.6787,276,1130.6787" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="1098.6787" y
 2="1118.6787"/><polygon fill="#A80036" points="254,1108.6787,258,1118.6787,262,1108.6787,258,1112.6787" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="996.3076" y2="1016.3076"/><polygon fill="#A80036" points="254,1006.3076,258,1016.3076,262,1006.3076,258,1010.3076" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="1142.6787" y2="1152.6787"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="458" y1="1152.6787" y2="1152.6787"/><polygon fill="#A80036" points="454,1079.6943,458,1069.6943,462,1079.6943,458,1075.6943" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="458" x2="458" y1="984.3076" y2="1152.6787"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="458" x2="353" y1="984.3076" y2="984.3076"/><polygon fill="#A80036" points="363,980.3076,353,984.3076,363,988.3076,359,984.3076" styl
 e="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="163" x2="70" y1="984.3076" y2="984.3076"/><polygon fill="#A80036" points="66,1065.6943,70,1075.6943,74,1065.6943,70,1069.6943" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="70" x2="70" y1="984.3076" y2="1164.6787"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="70" x2="258" y1="1164.6787" y2="1164.6787"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="258" x2="258" y1="1164.6787" y2="1196.6787"/><polygon fill="#A80036" points="254,1186.6787,258,1196.6787,262,1186.6787,258,1190.6787" style="stroke: #A80036; stroke-width: 1.0;"/><!--
+ at startuml
+title "Activity diagram Torflow measurements aggregation."
+
+
+partition "Initialize relays from consensus (prev_consensus)" {
+    :ns_list = c.get_network_status();
+    :ns_list.sort(lambda x, y: int(y.bandwidth/10000.0 - x.bandwidth/10000.0));
+
+    :prev_consensus = {};
+    while (for i in range(0, len(ns_list))?)
+        :n = ns_list[i];
+        :n.list_rank = i;
+        :n.measured = False;
+        :prev_consensus["$"+n.idhex] = n;
+    endwhile
+}
+
+partition "Aggregate raw measurements (nodes)"
+    :nodes = {};
+    while (for line in bw_file?)
+        if (line.idhex not in nodes?) then (yes)
+            :n = Node();
+            :nodes[line.idhex] = n;
+            :n.add_line(line);
+        endif
+    endwhile
+}
+
+partition "Assign consensus flags"
+    while (for idhex in nodes.iterkeys()?)
+        if (idhex in prev_consensus?) then (yes)
+            :nodes[idhex].flags = prev_consensus[idhex].flags;
+        endif
+    endwhile
+}
+
+:scaling;
+
+ at enduml
+
+PlantUML version 1.2018.13(Mon Nov 26 17:11:51 GMT 2018)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.9.1+1-post-Debian-1deb10u2
+Operating System: Linux
+OS Version: 4.19.0-13-amd64
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/images/activity_torflow_scaling.svg b/docs/source/images/activity_torflow_scaling.svg
new file mode 100644
index 0000000..c9cb6c4
--- /dev/null
+++ b/docs/source/images/activity_torflow_scaling.svg
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1850px" preserveAspectRatio="none" style="width:3144px;height:1850px;" version="1.1" viewBox="0 0 3144 1850" width="3144px" zoomAndPan="magnify"><defs><filter height="300%" id="f9dswc3p3ycf8" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><text fill="#000000" font-family="sans-serif" font-size="18" lengthAdjust="spacingAndGlyphs" textLength="292" x="1425.2188" y="26.708">"Torflow measurements scaling."</text><path d="M2421.5,35.3711 L2421.5,43.9375 L2401.5,47.9375 L2421.5,51.9375 L2421.5,60.503
 9 A0,0 0 0 0 2421.5,60.5039 L2782.5,60.5039 A0,0 0 0 0 2782.5,60.5039 L2782.5,45.3711 L2772.5,35.3711 L2421.5,35.3711 A0,0 0 0 0 2421.5,35.3711 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M2772.5,35.3711 L2772.5,45.3711 L2782.5,45.3711 L2772.5,35.3711 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="340" x="2427.5" y="52.438">initialize measurements from previous Bandwidth File</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="165" x="2236.5" y="30.9531"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="145" x="2246.5" y="52.0918">prev_votes = VoteSet()</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A800
 36; stroke-width: 1.5;" width="114" x="2262" y="84.9219"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="94" x="2272" y="106.0605">tot_net_bw = 0</text><path d="M2351,143.3086 L2351,151.875 L2331,155.875 L2351,159.875 L2351,168.4414 A0,0 0 0 0 2351,168.4414 L2523,168.4414 A0,0 0 0 0 2523,168.4414 L2523,153.3086 L2513,143.3086 L2351,143.3086 A0,0 0 0 0 2351,143.3086 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M2513,143.3086 L2513,153.3086 L2523,153.3086 L2513,143.3086 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="151" x="2357" y="160.3755">for every measurement</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="2307" y="138.8906"/><text fill="#000000" fon
 t-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="2321" y="160.0293"/><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="337" x="2150.5" y="236.8594"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="317" x="2160.5" y="257.998">n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()]</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="366" x="2136" y="290.8281"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="346" x="2146" y="311.9668">n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()]</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="161" x="2238.5" y="344.7969"/><te
 xt fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="141" x="2248.5" y="365.9355">n.use_bw = n.desc_bw</text><path d="M2398,388.7656 L2398,450.2969 L2378,454.2969 L2398,458.2969 L2398,519.8281 A0,0 0 0 0 2398,519.8281 L2792,519.8281 A0,0 0 0 0 2792,519.8281 L2792,398.7656 L2782,388.7656 L2398,388.7656 A0,0 0 0 0 2398,388.7656 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M2782,388.7656 L2782,398.7656 L2792,398.7656 L2782,388.7656 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="175" x="2404" y="405.8325">if n.sbw_ratio > n.fbw_ratio:</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="12" x="2404" y="420.9653">1.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGl
 yphs" textLength="247" x="2420" y="420.9653">assert cs_junk.use_best_ratio == True</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="373" x="2404" y="436.0981">n.pid_error = (n.strm_bw - true_strm_avg[n.node_class()])</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="204" x="2484" y="451.231">/ true_strm_avg[n.node_class()]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="30" x="2404" y="466.3638">else:</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="343" x="2404" y="481.4966">n.pid_error = (n.filt_bw - true_filt_avg[n.node_class()])</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="189" x="2484" y="496.6294">/ true_filt_avg[n.node_class()]</text><text fill="#000000" font-family="
 sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="173" x="2404" y="511.7622">0 <= n.pid_error <= 500.0</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="118" x="2260" y="437.3125"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="98" x="2270" y="458.4512">n.pid_error = ...</text><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="2226,539.8281,2412,539.8281,2424,551.8281,2412,563.8281,2226,563.8281,2214,551.8281,2226,539.8281" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="186" x="2226" y="555.6362">n.idhex in prev_votes.vote_map?</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="2194" y="549.2339">yes</text><text fill="#000000" fon
 t-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="2424" y="549.2339">no</text><path d="M1725.125,573.8281 L1725.125,589.9609 L1705.125,593.9609 L1725.125,597.9609 L1725.125,614.0938 A0,0 0 0 0 1725.125,614.0938 L2033.125,614.0938 A0,0 0 0 0 2033.125,614.0938 L2033.125,583.8281 L2023.125,573.8281 L1725.125,573.8281 A0,0 0 0 0 1725.125,573.8281 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M2023.125,573.8281 L2023.125,583.8281 L2033.125,583.8281 L2023.125,573.8281 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="123" x="1731.125" y="590.895">if n.measured_at ></text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="287" x="1731.125" y="606.0278">prev_votes.vote_map[n.idhex].measured_at;</text><rect fill="#FEFECE" filter="
 url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="1681.125" y="576.9766"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="1695.125" y="598.1152"/><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="1630.625,649.0938,1755.625,649.0938,1767.625,661.0938,1755.625,673.0938,1630.625,673.0938,1618.625,661.0938,1630.625,649.0938" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="125" x="1630.625" y="664.9019">measurement newer?</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="1598.625" y="658.4995">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="1767.625" y="658.4995">no</text><path d="M1100.25,683.0938 L1100.25,706
 .793 L1080.25,710.793 L1100.25,714.793 L1100.25,738.4922 A0,0 0 0 0 1100.25,738.4922 L1440.25,738.4922 A0,0 0 0 0 1440.25,738.4922 L1440.25,693.0938 L1430.25,683.0938 L1100.25,683.0938 A0,0 0 0 0 1100.25,683.0938 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M1430.25,683.0938 L1430.25,693.0938 L1440.25,693.0938 L1430.25,683.0938 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="179" x="1106.25" y="700.1606">if n.idhex in prev_consensus</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="294" x="1122.25" y="715.2935">and ("Guard" in prev_consensus[n.idhex].flags</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="303" x="1122.25" y="730.4263">and "Exit" not in prev_consensus[n.idhex].flags)</text><re
 ct fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="1056.25" y="693.8086"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="1070.25" y="714.9473"/><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="1010.75,773.4922,1125.75,773.4922,1137.75,792.6992,1125.75,811.9063,1010.75,811.9063,998.75,792.6992,1010.75,773.4922" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="111" x="1010.75" y="783.7026">in prev_consensus,</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="47" x="1010.75" y="796.5073">is guard</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="70" x="1010.75" y="809.312">but not exit?</text><text fill=
 "#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="978.75" y="790.105">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="1137.75" y="790.105">no</text><path d="M509,821.9063 L509,853.1719 L489,857.1719 L509,861.1719 L509,892.4375 A0,0 0 0 0 509,892.4375 L956,892.4375 A0,0 0 0 0 956,892.4375 L956,831.9063 L946,821.9063 L509,821.9063 A0,0 0 0 0 509,821.9063 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M946,821.9063 L946,831.9063 L956,831.9063 L946,821.9063 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="239" x="515" y="838.9731">if n.idhex not in prev_votes.vote_map</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="410" x="531" y="854
 .106">or n.measured_at - prev_votes.vote_map[n.idhex].measured_at</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="194" x="547" y="869.2388">> cs_junk.guard_sample_rate:</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="352" x="547" y="884.3716"># cs_jung.guard_sample_rate = 2*7*24*60*60 # 2wks</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="465" y="840.1875"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="479" y="861.3262"/><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="408,927.4375,546,927.4375,558,939.4375,546,951.4375,408,951.4375,396,939.4375,408,927.4375" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="sp
 acingAndGlyphs" textLength="138" x="408" y="943.2456">diff bigger than 2 weeks</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="376" y="936.8433">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="558" y="936.8433">no</text><path d="M200,961.4375 L200,1022.9688 L180,1026.9688 L200,1030.9688 L200,1092.5 A0,0 0 0 0 200,1092.5 L587,1092.5 A0,0 0 0 0 587,1092.5 L587,971.4375 L577,961.4375 L200,961.4375 A0,0 0 0 0 200,961.4375 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M577,961.4375 L577,971.4375 L587,971.4375 L577,961.4375 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="12" x="206" y="978.5044">1.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust=
 "spacingAndGlyphs" textLength="80" x="222" y="978.5044">full feedback</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="366" x="206" y="993.6372">n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="78" x="270" y="1008.77">cs_junk.K_p,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="73" x="270" y="1023.9028">cs_junk.K_i,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="78" x="270" y="1039.0356">cs_junk.K_d,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="119" x="270" y="1054.1685">cs_junk.K_i_decay)</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="301" x="222" y="1069
 .3013">= n.get_pid_bw(prev_votes.vote_map[n.idhex],</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="73" x="282" y="1084.4341">1.0, 0, 0, 0)</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="156" y="1009.9844"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="170" y="1031.123"/><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="103.8125" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="260" x="38" y="1127.5"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="228" x="48" y="1148.6387">self.prev_error = prev_vote.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="158" x="48" y="1162.6074">self.pid_bw = self.use_b
 w</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="182" x="64" y="1176.5762">+ self.use_bw * self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="203" x="64" y="1190.5449"># + self.desc_bw * self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="240" x="48" y="1204.5137">self.pid_error_sum = 0 + self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="146" x="48" y="1218.4824">n.new_bw = self.pid_bw</text><path d="M818,961.4375 L818,1015.4023 L798,1019.4023 L818,1023.4023 L818,1077.3672 A0,0 0 0 0 818,1077.3672 L1205,1077.3672 A0,0 0 0 0 1205,1077.3672 L1205,971.4375 L1195,961.4375 L818,961.4375 A0,0 0 0 0 818,961.4375 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><pat
 h d="M1195,961.4375 L1195,971.4375 L1205,971.4375 L1195,961.4375 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="280" x="824" y="978.5044">\# Use new measurement but not feedback</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="283" x="824" y="993.6372">n.copy_vote(prev_vote.vote_map[n.idhex]));</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="366" x="824" y="1008.77">n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="78" x="872" y="1023.9028">cs_junk.K_p,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="73" x="872" y="1039.0356">cs_junk.K_i,</text><text fill="#000000" fo
 nt-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="78" x="872" y="1054.1685">cs_junk.K_d,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="66" x="872" y="1069.3013">0.0, False)</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="774" y="1002.418"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="788" y="1023.5566"/><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="145.7188" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="358" x="607" y="1112.3672"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="204" x="617" y="1133.5059">\# self.new_bw = vote.bw * 1000</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyp
 hs" textLength="159" x="617" y="1147.4746">self.pid_bw = vote.pid_bw</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="251" x="617" y="1161.4434">self.pid_error_sum = vote.pid_error_sum</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="189" x="617" y="1175.4121">self.pid_delta = vote.pid_delta</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="621" y="1189.3809"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="338" x="617" y="1203.3496">n.new_bw = self.use_bw + self.use_bw * self_pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="621" y="1217.3184"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="258" x="617" y=
 "1231.2871">n.measured_at = prev_vote.measured_at</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="206" x="617" y="1245.2559">n.pid_error = prev_vote.pid_error</text><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="477,1264.0859,489,1276.0859,477,1288.0859,465,1276.0859,477,1264.0859" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="1602,821.9063,1717,821.9063,1729,834.7109,1717,847.5156,1602,847.5156,1590,834.7109,1602,821.9063" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="111" x="1602" y="832.1167">in prev_consensus,</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="96" x="1602" y="844.9214">is guard and exit</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="
 spacingAndGlyphs" textLength="20" x="1570" y="832.1167">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="1729" y="832.1167">no</text><path d="M1407,857.5156 L1407,919.0469 L1387,923.0469 L1407,927.0469 L1407,988.5781 A0,0 0 0 0 1407,988.5781 L1794,988.5781 A0,0 0 0 0 1794,988.5781 L1794,867.5156 L1784,857.5156 L1407,857.5156 A0,0 0 0 0 1407,857.5156 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M1784,857.5156 L1784,867.5156 L1794,867.5156 L1784,857.5156 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="366" x="1413" y="874.5825">n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="126" x="1445" y="889.7153">cs_junk.K_p*weight,</text>
 <text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="121" x="1445" y="904.8481">cs_junk.K_i*weight,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="126" x="1445" y="919.981">cs_junk.K_d*weight,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="119" x="1445" y="935.1138">cs_junk.K_i_decay)</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="366" x="1413" y="950.2466">n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="100" x="1461" y="965.3794">1.0*1.0, 0, 0, 0)</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="359" x="1413" y="980.5122">\# so, same code as for when diff is bigger t
 han 2 weeks</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="1363" y="906.0625"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="1377" y="927.2012"/><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="103.8125" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="260" x="1245" y="1023.5781"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="228" x="1255" y="1044.7168">self.prev_error = prev_vote.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="158" x="1255" y="1058.6855">self.pid_bw = self.use_bw</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="182" x="1271" y="1072.6543">+ self.use_bw * self.pid_error</text><te
 xt fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="203" x="1271" y="1086.623"># + self.desc_bw * self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="240" x="1255" y="1100.5918">self.pid_error_sum = 0 + self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="146" x="1255" y="1114.5605">n.new_bw = self.pid_bw</text><path d="M1976,861.9336 L1976,870.5 L1956,874.5 L1976,878.5 L1976,887.0664 A0,0 0 0 0 1976,887.0664 L2126,887.0664 A0,0 0 0 0 2126,887.0664 L2126,871.9336 L2116,861.9336 L1976,861.9336 A0,0 0 0 0 1976,861.9336 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M2116,861.9336 L2116,871.9336 L2126,871.9336 L2116,861.9336 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size
 ="13" lengthAdjust="spacingAndGlyphs" textLength="129" x="1982" y="879.0005">\#again, same code</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="1932" y="857.5156"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="1946" y="878.6543"/><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="103.8125" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="260" x="1814" y="926.4844"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="228" x="1824" y="947.623">self.prev_error = prev_vote.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="158" x="1824" y="961.5918">self.pid_bw = self.use_bw</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" 
 textLength="182" x="1840" y="975.5605">+ self.use_bw * self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="203" x="1840" y="989.5293"># + self.desc_bw * self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="240" x="1824" y="1003.498">self.pid_error_sum = 0 + self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="146" x="1824" y="1017.4668">n.new_bw = self.pid_bw</text><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="1659.5,1133.3906,1671.5,1145.3906,1659.5,1157.3906,1647.5,1145.3906,1659.5,1133.3906" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="1068.25,1294.0859,1080.25,1306.0859,1068.25,1318.0859,1056.25,1306.0859,1068.25,1294.0859" style="stroke: #A80036; stroke-width: 1.5;"/><path d="M2347.4375,
 683.0938 L2347.4375,714.3594 L2327.4375,718.3594 L2347.4375,722.3594 L2347.4375,753.625 A0,0 0 0 0 2347.4375,753.625 L2760.4375,753.625 A0,0 0 0 0 2760.4375,753.625 L2760.4375,693.0938 L2750.4375,683.0938 L2347.4375,683.0938 A0,0 0 0 0 2347.4375,683.0938 " fill="#FBFB77" filter="url(#f9dswc3p3ycf8)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M2750.4375,683.0938 L2750.4375,693.0938 L2760.4375,693.0938 L2750.4375,683.0938 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="392" x="2353.4375" y="700.1606">\# Reset values. Don't vote/sample this measurement round.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="384" x="2353.4375" y="715.2935">\# is in the previous bwfile, but haven't check the consensus</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" 
 textLength="309" x="2353.4375" y="730.4263">n.revert_to_vote(prev_votes.vote_map[n.idhex])</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="258" x="2353.4375" y="745.5591">\# which calls again self.copy_vote(vote)</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="2303.4375" y="701.375"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="2317.4375" y="722.5137"/><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="117.7813" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="304" x="2163.4375" y="788.625"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="211" x="2173.4375" y="809.7637">self.new_bw = prev_vote.bw*1000</text><text fill="#000000" font-family="sans-serif" font-size="12" len
 gthAdjust="spacingAndGlyphs" textLength="192" x="2173.4375" y="823.7324">self.pid_bw = prev_vote.pid_bw</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="284" x="2173.4375" y="837.7012">self.pid_error_sum = prev_vote.pid_error_sum</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="222" x="2173.4375" y="851.6699">self.pid_delta = prev_vote.pid_delta</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="2177.4375" y="865.6387"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="187" x="2173.4375" y="879.6074">self.pid_error = vote.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="239" x="2173.4375" y="893.5762">self.measured_at = vote.measured_at</text><polygon fill="#FEFECE" filte
 r="url(#f9dswc3p3ycf8)" points="1693.125,1324.0859,1705.125,1336.0859,1693.125,1348.0859,1681.125,1336.0859,1693.125,1324.0859" style="stroke: #A80036; stroke-width: 1.5;"/><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="61.9063" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="314" x="2790.4375" y="573.8281"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="294" x="2800.4375" y="594.9668">n.new_bw = n.use_bw + n.use_bw * n.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="186" x="2800.4375" y="608.9355">n.pid_error_sum = n.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="132" x="2800.4375" y="622.9043">n.pid_bw = n.new_bw</text><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="2319,1354.0859,2331,1366.0859,2319,1378.0859,2307,1366.0859,2319,135
 4.0859" style="stroke: #A80036; stroke-width: 1.5;"/><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="289" x="2174.5" y="1494.8906"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="269" x="2184.5" y="1516.0293">prev_consensus[n.idhex].measured = True</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="176" x="2231" y="1563.8594"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="156" x="2241" y="1584.998">tot_net_bw += n.new_bw</text><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="2192.5,1446.4883,2445.5,1446.4883,2457.5,1458.4883,2445.5,1470.4883,2192.5,1470.4883,2180.5,1458.4883,2192.5,1446.4883" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-s
 erif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="2323" y="1480.6987">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="253" x="2192.5" y="1462.2964">prev_consensus[n.idhex].bandwidth != None</text><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="2319,1617.8281,2331,1629.8281,2319,1641.8281,2307,1629.8281,2319,1617.8281" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="2243,1398.0859,2395,1398.0859,2407,1410.0859,2395,1422.0859,2243,1422.0859,2231,1410.0859,2243,1398.0859" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="2323" y="1432.2964">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="152" x="2243" y="1413.894">n.idhex in prev_consensus</text><polygon fil
 l="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="2319,1661.8281,2331,1673.8281,2319,1685.8281,2307,1673.8281,2319,1661.8281" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="2242,192.8594,2396,192.8594,2408,204.8594,2396,216.8594,2242,216.8594,2230,204.8594,2242,192.8594" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="154" x="2242" y="208.6675">for n in nodes.itervalues()?</text><rect fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="55" x="2291.5" y="1771.8281"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="35" x="2301.5" y="1792.9668">cap...</text><polygon fill="#FEFECE" filter="url(#f9dswc3p3ycf8)" points="2242,1727.8281,2396,1727.8281,2408,1739.8281,2396,1751.8281,2242,1751.8281,2230
 ,1739.8281,2242,1727.8281" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="154" x="2242" y="1743.6362">for n in nodes.itervalues()?</text><ellipse cx="2220" cy="1781.8281" fill="none" filter="url(#f9dswc3p3ycf8)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="2220.5" cy="1782.3281" fill="#000000" filter="url(#f9dswc3p3ycf8)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="64.9219" y2="84.9219"/><polygon fill="#A80036" points="2315,74.9219,2319,84.9219,2323,74.9219,2319,78.9219" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="118.8906" y2="138.8906"/><polygon fill="#A80036" points="2315,128.8906,2319,138.8906,2323,128.8906,2319,132.8906" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80
 036; stroke-width: 1.5;" x1="2319" x2="2319" y1="270.8281" y2="290.8281"/><polygon fill="#A80036" points="2315,280.8281,2319,290.8281,2323,280.8281,2319,284.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="324.7969" y2="344.7969"/><polygon fill="#A80036" points="2315,334.7969,2319,344.7969,2323,334.7969,2319,338.7969" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="378.7656" y2="437.3125"/><polygon fill="#A80036" points="2315,427.3125,2319,437.3125,2323,427.3125,2319,431.3125" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="168" x2="168" y1="1043.9531" y2="1127.5"/><polygon fill="#A80036" points="164,1117.5,168,1127.5,172,1117.5,168,1121.5" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="786" x2="786" y1="1036.3867" y2="1112.3672"/><polyg
 on fill="#A80036" points="782,1102.3672,786,1112.3672,790,1102.3672,786,1106.3672" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="396" x2="168" y1="939.4375" y2="939.4375"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="168" x2="168" y1="939.4375" y2="1009.9844"/><polygon fill="#A80036" points="164,999.9844,168,1009.9844,172,999.9844,168,1003.9844" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="558" x2="786" y1="939.4375" y2="939.4375"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="786" x2="786" y1="939.4375" y2="1002.418"/><polygon fill="#A80036" points="782,992.418,786,1002.418,790,992.418,786,996.418" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="168" x2="168" y1="1231.3125" y2="1276.0859"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="168" x2="465" y1="1276.0859" y2="1276.0859"/><polygon fill="#A80036"
  points="455,1272.0859,465,1276.0859,455,1280.0859,459,1276.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="786" x2="786" y1="1258.0859" y2="1276.0859"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="786" x2="489" y1="1276.0859" y2="1276.0859"/><polygon fill="#A80036" points="499,1272.0859,489,1276.0859,499,1280.0859,495,1276.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="477" x2="477" y1="874.1563" y2="927.4375"/><polygon fill="#A80036" points="473,917.4375,477,927.4375,481,917.4375,477,921.4375" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1375" x2="1375" y1="940.0313" y2="1023.5781"/><polygon fill="#A80036" points="1371,1013.5781,1375,1023.5781,1379,1013.5781,1375,1017.5781" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1944" x2="1944" y1="891.4844" y2="9
 26.4844"/><polygon fill="#A80036" points="1940,916.4844,1944,926.4844,1948,916.4844,1944,920.4844" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1590" x2="1375" y1="834.7109" y2="834.7109"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1375" x2="1375" y1="834.7109" y2="906.0625"/><polygon fill="#A80036" points="1371,896.0625,1375,906.0625,1379,896.0625,1375,900.0625" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1729" x2="1944" y1="834.7109" y2="834.7109"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1944" x2="1944" y1="834.7109" y2="857.5156"/><polygon fill="#A80036" points="1940,847.5156,1944,857.5156,1948,847.5156,1944,851.5156" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1375" x2="1375" y1="1127.3906" y2="1145.3906"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1375" x2="1647.5" y1="1145.3906" y
 2="1145.3906"/><polygon fill="#A80036" points="1637.5,1141.3906,1647.5,1145.3906,1637.5,1149.3906,1641.5,1145.3906" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1944" x2="1944" y1="1030.2969" y2="1145.3906"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1944" x2="1671.5" y1="1145.3906" y2="1145.3906"/><polygon fill="#A80036" points="1681.5,1141.3906,1671.5,1145.3906,1681.5,1149.3906,1677.5,1145.3906" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="998.75" x2="477" y1="792.6992" y2="792.6992"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="477" x2="477" y1="792.6992" y2="840.1875"/><polygon fill="#A80036" points="473,830.1875,477,840.1875,481,830.1875,477,834.1875" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1137.75" x2="1659.5" y1="792.6992" y2="792.6992"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1
 659.5" x2="1659.5" y1="792.6992" y2="821.9063"/><polygon fill="#A80036" points="1655.5,811.9063,1659.5,821.9063,1663.5,811.9063,1659.5,815.9063" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="477" x2="477" y1="1288.0859" y2="1306.0859"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="477" x2="1056.25" y1="1306.0859" y2="1306.0859"/><polygon fill="#A80036" points="1046.25,1302.0859,1056.25,1306.0859,1046.25,1310.0859,1050.25,1306.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1659.5" x2="1659.5" y1="1157.3906" y2="1306.0859"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1659.5" x2="1080.25" y1="1306.0859" y2="1306.0859"/><polygon fill="#A80036" points="1090.25,1302.0859,1080.25,1306.0859,1090.25,1310.0859,1086.25,1306.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1068.25" x2="1068.25" y1="727.7773" y2="
 773.4922"/><polygon fill="#A80036" points="1064.25,763.4922,1068.25,773.4922,1072.25,763.4922,1068.25,767.4922" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2315.4375" x2="2315.4375" y1="735.3438" y2="788.625"/><polygon fill="#A80036" points="2311.4375,778.625,2315.4375,788.625,2319.4375,778.625,2315.4375,782.625" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1618.625" x2="1068.25" y1="661.0938" y2="661.0938"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1068.25" x2="1068.25" y1="661.0938" y2="693.8086"/><polygon fill="#A80036" points="1064.25,683.8086,1068.25,693.8086,1072.25,683.8086,1068.25,687.8086" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1767.625" x2="2315.4375" y1="661.0938" y2="661.0938"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2315.4375" x2="2315.4375" y1="661.0938" y2="701.375"/><polygon 
 fill="#A80036" points="2311.4375,691.375,2315.4375,701.375,2319.4375,691.375,2315.4375,695.375" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1068.25" x2="1068.25" y1="1318.0859" y2="1336.0859"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1068.25" x2="1681.125" y1="1336.0859" y2="1336.0859"/><polygon fill="#A80036" points="1671.125,1332.0859,1681.125,1336.0859,1671.125,1340.0859,1675.125,1336.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2315.4375" x2="2315.4375" y1="906.4063" y2="1336.0859"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2315.4375" x2="1705.125" y1="1336.0859" y2="1336.0859"/><polygon fill="#A80036" points="1715.125,1332.0859,1705.125,1336.0859,1715.125,1340.0859,1711.125,1336.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1693.125" x2="1693.125" y1="610.9453" y2="649.0938"/><polyg
 on fill="#A80036" points="1689.125,639.0938,1693.125,649.0938,1697.125,639.0938,1693.125,643.0938" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2214" x2="1693.125" y1="551.8281" y2="551.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1693.125" x2="1693.125" y1="551.8281" y2="576.9766"/><polygon fill="#A80036" points="1689.125,566.9766,1693.125,576.9766,1697.125,566.9766,1693.125,570.9766" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2424" x2="2947.4375" y1="551.8281" y2="551.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2947.4375" x2="2947.4375" y1="551.8281" y2="573.8281"/><polygon fill="#A80036" points="2943.4375,563.8281,2947.4375,573.8281,2951.4375,563.8281,2947.4375,567.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1693.125" x2="1693.125" y1="1348.0859" y2="1366.0859"/><line style="stro
 ke: #A80036; stroke-width: 1.5;" x1="1693.125" x2="2307" y1="1366.0859" y2="1366.0859"/><polygon fill="#A80036" points="2297,1362.0859,2307,1366.0859,2297,1370.0859,2301,1366.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2947.4375" x2="2947.4375" y1="635.7344" y2="1366.0859"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2947.4375" x2="2331" y1="1366.0859" y2="1366.0859"/><polygon fill="#A80036" points="2341,1362.0859,2331,1366.0859,2341,1370.0859,2337,1366.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="471.2813" y2="539.8281"/><polygon fill="#A80036" points="2315,529.8281,2319,539.8281,2323,529.8281,2319,533.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1528.8594" y2="1563.8594"/><polygon fill="#A80036" points="2315,1553.8594,2319,1563.8594,2323,1553.8594,2319,1
 557.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1470.4883" y2="1494.8906"/><polygon fill="#A80036" points="2315,1484.8906,2319,1494.8906,2323,1484.8906,2319,1488.8906" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2457.5" x2="2473.5" y1="1458.4883" y2="1458.4883"/><polygon fill="#A80036" points="2469.5,1536.3594,2473.5,1546.3594,2477.5,1536.3594,2473.5,1540.3594" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2473.5" x2="2473.5" y1="1458.4883" y2="1629.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2473.5" x2="2331" y1="1629.8281" y2="1629.8281"/><polygon fill="#A80036" points="2341,1625.8281,2331,1629.8281,2341,1633.8281,2337,1629.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1597.8281" y2="1617.8281"/><poly
 gon fill="#A80036" points="2315,1607.8281,2319,1617.8281,2323,1607.8281,2319,1611.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1422.0859" y2="1446.4883"/><polygon fill="#A80036" points="2315,1436.4883,2319,1446.4883,2323,1436.4883,2319,1440.4883" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2407" x2="2495.5" y1="1410.0859" y2="1410.0859"/><polygon fill="#A80036" points="2491.5,1536.3594,2495.5,1546.3594,2499.5,1536.3594,2495.5,1540.3594" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2495.5" x2="2495.5" y1="1410.0859" y2="1673.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2495.5" x2="2331" y1="1673.8281" y2="1673.8281"/><polygon fill="#A80036" points="2341,1669.8281,2331,1673.8281,2341,1677.8281,2337,1673.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; 
 stroke-width: 1.5;" x1="2319" x2="2319" y1="1641.8281" y2="1661.8281"/><polygon fill="#A80036" points="2315,1651.8281,2319,1661.8281,2323,1651.8281,2319,1655.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1378.0859" y2="1398.0859"/><polygon fill="#A80036" points="2315,1388.0859,2319,1398.0859,2323,1388.0859,2319,1392.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="216.8594" y2="236.8594"/><polygon fill="#A80036" points="2315,226.8594,2319,236.8594,2323,226.8594,2319,230.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1685.8281" y2="1695.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="3118.4375" y1="1695.8281" y2="1695.8281"/><polygon fill="#A80036" points="3114.4375,936.2461,3118.4375,926.2461,3122.4375,936.2461,3118.4375,932.2461" 
 style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="3118.4375" x2="3118.4375" y1="204.8594" y2="1695.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="3118.4375" x2="2408" y1="204.8594" y2="204.8594"/><polygon fill="#A80036" points="2418,200.8594,2408,204.8594,2418,208.8594,2414,204.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2230" x2="24" y1="204.8594" y2="204.8594"/><polygon fill="#A80036" points="20,922.2461,24,932.2461,28,922.2461,24,926.2461" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="24" x2="24" y1="204.8594" y2="1707.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="24" x2="2319" y1="1707.8281" y2="1707.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1707.8281" y2="1727.8281"/><polygon fill="#A80036" points="2315,1717.8281,2319,1727.8281,2323,1717.8281,2319,172
 1.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="172.8594" y2="192.8594"/><polygon fill="#A80036" points="2315,182.8594,2319,192.8594,2323,182.8594,2319,186.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1751.8281" y2="1771.8281"/><polygon fill="#A80036" points="2315,1761.8281,2319,1771.8281,2323,1761.8281,2319,1765.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2319" y1="1805.7969" y2="1815.7969"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2319" x2="2420" y1="1815.7969" y2="1815.7969"/><polygon fill="#A80036" points="2416,1786.8125,2420,1776.8125,2424,1786.8125,2420,1782.8125" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2420" x2="2420" y1="1739.8281" y2="1815.7969"/><line style="stroke: #A80036; s
 troke-width: 1.5;" x1="2420" x2="2408" y1="1739.8281" y2="1739.8281"/><polygon fill="#A80036" points="2418,1735.8281,2408,1739.8281,2418,1743.8281,2414,1739.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2230" x2="2220" y1="1739.8281" y2="1739.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2220" x2="2220" y1="1739.8281" y2="1771.8281"/><polygon fill="#A80036" points="2216,1761.8281,2220,1771.8281,2224,1761.8281,2220,1765.8281" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#888888" font-family="sans-serif" font-size="10" lengthAdjust="spacingAndGlyphs" textLength="119" x="1511.7188" y="1837.0791">last updated 2021-01-08</text><!--
+ at startuml
+title "Torflow measurements scaling."
+
+:prev_votes = VoteSet();
+note right
+initialize measurements from previous Bandwidth File
+end note
+:tot_net_bw = 0;
+:;
+note right
+    for every measurement
+end note
+while (for n in nodes.itervalues()?)
+    :n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()];
+    :n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()];
+    :n.use_bw = n.desc_bw;
+    :n.pid_error = ...;
+    note right
+        if n.sbw_ratio > n.fbw_ratio:
+        #assert cs_junk.use_best_ratio == True
+        n.pid_error = (n.strm_bw - true_strm_avg[n.node_class()])
+                            / true_strm_avg[n.node_class()]
+        else:
+        n.pid_error = (n.filt_bw - true_filt_avg[n.node_class()])
+                            / true_filt_avg[n.node_class()]
+        0 <= n.pid_error <= 500.0
+    end note
+    if (n.idhex in prev_votes.vote_map?) then (yes)
+        :;
+        note right
+        if n.measured_at >
+        prev_votes.vote_map[n.idhex].measured_at;
+        end note
+        if (measurement newer?) then (yes)
+            :;
+            note right
+            if n.idhex in prev_consensus
+                and ("Guard" in prev_consensus[n.idhex].flags
+                and "Exit" not in prev_consensus[n.idhex].flags)
+            end note
+            if (in prev_consensus, \nis guard \nbut not exit?) then (yes)
+                :;
+                note right
+                if n.idhex not in prev_votes.vote_map
+                    or n.measured_at - prev_votes.vote_map[n.idhex].measured_at
+                        > cs_junk.guard_sample_rate:
+                        # cs_jung.guard_sample_rate = 2*7*24*60*60 # 2wks
+                end note
+                if (diff bigger than 2 weeks) then (yes)
+                    :;
+                    note right
+                    # full feedback
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                    cs_junk.K_p,
+                                    cs_junk.K_i,
+                                    cs_junk.K_d,
+                                    cs_junk.K_i_decay)
+                        = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                       1.0, 0, 0, 0)
+                    end note
+                    :self.prev_error = prev_vote.pid_error
+                    self.pid_bw = self.use_bw
+                        + self.use_bw * self.pid_error
+                        # + self.desc_bw * self.pid_error
+                    self.pid_error_sum = 0 + self.pid_error
+                    n.new_bw = self.pid_bw;
+                else (no)
+                    :;
+                    note right
+                    \# Use new measurement but not feedback
+                    n.copy_vote(prev_vote.vote_map[n.idhex]));
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                cs_junk.K_p,
+                                cs_junk.K_i,
+                                cs_junk.K_d,
+                                0.0, False)
+                    end note
+                    :\# self.new_bw = vote.bw * 1000
+                    self.pid_bw = vote.pid_bw
+                    self.pid_error_sum = vote.pid_error_sum
+                    self.pid_delta = vote.pid_delta
+
+                    n.new_bw = self.use_bw + self.use_bw * self_pid_error
+
+                    n.measured_at = prev_vote.measured_at
+                    n.pid_error = prev_vote.pid_error;
+                endif
+            else (no)
+                if (in prev_consensus, \nis guard and exit) then (yes)
+                    :;
+                    note right
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                            cs_junk.K_p*weight,
+                            cs_junk.K_i*weight,
+                            cs_junk.K_d*weight,
+                            cs_junk.K_i_decay)
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                1.0*1.0, 0, 0, 0)
+                    \# so, same code as for when diff is bigger than 2 weeks
+                    end note
+                    :self.prev_error = prev_vote.pid_error
+                    self.pid_bw = self.use_bw
+                        + self.use_bw * self.pid_error
+                        # + self.desc_bw * self.pid_error
+                    self.pid_error_sum = 0 + self.pid_error
+                    n.new_bw = self.pid_bw;
+                else (no)
+                    :;
+                    note right
+                    \#again, same code
+                    end note
+                    :self.prev_error = prev_vote.pid_error
+                    self.pid_bw = self.use_bw
+                        + self.use_bw * self.pid_error
+                        # + self.desc_bw * self.pid_error
+                    self.pid_error_sum = 0 + self.pid_error
+                    n.new_bw = self.pid_bw;
+                endif
+            endif
+        else (no)
+            :;
+            note right
+            \# Reset values. Don't vote/sample this measurement round.
+            \# is in the previous bwfile, but haven't check the consensus
+            n.revert_to_vote(prev_votes.vote_map[n.idhex])
+            \# which calls again self.copy_vote(vote)
+            end note
+            :self.new_bw = prev_vote.bw*1000
+            self.pid_bw = prev_vote.pid_bw
+            self.pid_error_sum = prev_vote.pid_error_sum
+            self.pid_delta = prev_vote.pid_delta
+
+            self.pid_error = vote.pid_error
+            self.measured_at = vote.measured_at;
+
+        endif
+    else (no)
+        :n.new_bw = n.use_bw + n.use_bw * n.pid_error
+        n.pid_error_sum = n.pid_error
+        n.pid_bw = n.new_bw;
+    endif
+
+    if (n.idhex in prev_consensus) then (yes)
+        if (prev_consensus[n.idhex].bandwidth != None) then (yes)
+            :prev_consensus[n.idhex].measured = True;
+            :tot_net_bw += n.new_bw;
+        endif
+    endif
+endwhile
+while (for n in nodes.itervalues()?)
+    :cap...;
+endwhile
+stop
+
+footer last updated 2021-01-08
+ at enduml
+
+PlantUML version 1.2018.13(Mon Nov 26 17:11:51 GMT 2018)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.9.1+1-post-Debian-1deb10u2
+Operating System: Linux
+OS Version: 4.19.0-13-amd64
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/images/activity_torflow_scaling_simplified.svg b/docs/source/images/activity_torflow_scaling_simplified.svg
new file mode 100644
index 0000000..42ab119
--- /dev/null
+++ b/docs/source/images/activity_torflow_scaling_simplified.svg
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1879px" preserveAspectRatio="none" style="width:2238px;height:1879px;" version="1.1" viewBox="0 0 2238 1879" width="2238px" zoomAndPan="magnify"><defs><filter height="300%" id="f1g4fkgeqyp6on" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><text fill="#000000" font-family="sans-serif" font-size="18" lengthAdjust="spacingAndGlyphs" textLength="702" x="767" y="26.708">"Torflow measurements scaling with PID control (Per relay scaled bandwidth)."</text><path d="M1600.625,35.3711 L1600.625,43.9375 L
 1580.625,47.9375 L1600.625,51.9375 L1600.625,60.5039 A0,0 0 0 0 1600.625,60.5039 L1961.625,60.5039 A0,0 0 0 0 1961.625,60.5039 L1961.625,45.3711 L1951.625,35.3711 L1600.625,35.3711 A0,0 0 0 0 1600.625,35.3711 " fill="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M1951.625,35.3711 L1951.625,45.3711 L1961.625,45.3711 L1951.625,35.3711 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="340" x="1606.625" y="52.438">initialize measurements from previous Bandwidth File</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="165" x="1415.625" y="30.9531"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="145" x="1425.625" y="52.0918">prev_votes = VoteSet()</text><rect fill="#FEFECE" filte
 r="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="114" x="1441.125" y="84.9219"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="94" x="1451.125" y="106.0605">tot_net_bw = 0</text><path d="M1530.125,143.3086 L1530.125,151.875 L1510.125,155.875 L1530.125,159.875 L1530.125,168.4414 A0,0 0 0 0 1530.125,168.4414 L1702.125,168.4414 A0,0 0 0 0 1702.125,168.4414 L1702.125,153.3086 L1692.125,143.3086 L1530.125,143.3086 A0,0 0 0 0 1530.125,143.3086 " fill="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M1692.125,143.3086 L1692.125,153.3086 L1702.125,153.3086 L1692.125,143.3086 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="151" x="1536.125" y="160.3755">for every measurement</text><rect fill="#FEFECE" filter="u
 rl(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="1486.125" y="138.8906"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="1500.125" y="160.0293"/><rect fill="#FFFFFF" filter="url(#f1g4fkgeqyp6on)" height="331.2656" style="stroke: #000000; stroke-width: 2.0;" width="799.5" x="1305.125" y="227.6611"/><path d="M1503.125,228.6611 L1503.125,236.958 L1493.125,246.958 L1305.125,246.958 " fill="none" style="stroke: #000000; stroke-width: 2.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="188" x="1308.125" y="241.6563">Intialize ratios and pid_error</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="337" x="1329.625" y="263.958"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAn
 dGlyphs" textLength="317" x="1339.625" y="285.0967">n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()]</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="366" x="1315.125" y="317.9268"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="346" x="1325.125" y="339.0654">n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()]</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="161" x="1417.625" y="371.8955"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="141" x="1427.625" y="393.0342">n.use_bw = n.desc_bw</text><path d="M1700.625,415.8643 L1700.625,477.3955 L1680.625,481.3955 L1700.625,485.3955 L1700.625,546.9268 A0,0 0 0 0 1700.625,546.9268 L2094.625,546.9268 A0,0 0 0 0 2094.625,546.9268 L20
 94.625,425.8643 L2084.625,415.8643 L1700.625,415.8643 A0,0 0 0 0 1700.625,415.8643 " fill="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M2084.625,415.8643 L2084.625,425.8643 L2094.625,425.8643 L2084.625,415.8643 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="175" x="1706.625" y="432.9312">if n.sbw_ratio > n.fbw_ratio:</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="12" x="1706.625" y="448.064">1.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="247" x="1722.625" y="448.064">assert cs_junk.use_best_ratio == True</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="373" x="1706.625" y="463.1968">n.pid_error = (n.strm_bw - true_strm_avg[n
 .node_class()])</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="204" x="1786.625" y="478.3296">/ true_strm_avg[n.node_class()]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="30" x="1706.625" y="493.4624">else:</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="343" x="1706.625" y="508.5952">n.pid_error = (n.filt_bw - true_filt_avg[n.node_class()])</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="189" x="1786.625" y="523.728">/ true_filt_avg[n.node_class()]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="173" x="1706.625" y="538.8608">0 <= n.pid_error <= 500.0</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80
 036; stroke-width: 1.5;" width="365" x="1315.625" y="464.4111"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="345" x="1325.625" y="485.5498">n.pid_error = max(bwstrm_i / bwstrm, bwfilt_i / bwfilt) - 1</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="1405.125,578.9268,1591.125,578.9268,1603.125,590.9268,1591.125,602.9268,1405.125,602.9268,1393.125,590.9268,1405.125,578.9268" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="186" x="1405.125" y="594.7349">n.idhex in prev_votes.vote_map?</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="1373.125" y="588.3325">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="1603.125" y="588.3325">no</text><path d="M987.25,612.9268 L987.25,
 629.0596 L967.25,633.0596 L987.25,637.0596 L987.25,653.1924 A0,0 0 0 0 987.25,653.1924 L1295.25,653.1924 A0,0 0 0 0 1295.25,653.1924 L1295.25,622.9268 L1285.25,612.9268 L987.25,612.9268 A0,0 0 0 0 987.25,612.9268 " fill="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M1285.25,612.9268 L1285.25,622.9268 L1295.25,622.9268 L1285.25,612.9268 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="123" x="993.25" y="629.9937">if n.measured_at ></text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="287" x="993.25" y="645.1265">prev_votes.vote_map[n.idhex].measured_at;</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="943.25" y="616.0752"/><text fill="#000000" font-family="san
 s-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="957.25" y="637.2139"/><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="892.75,688.1924,1017.75,688.1924,1029.75,700.1924,1017.75,712.1924,892.75,712.1924,880.75,700.1924,892.75,688.1924" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="125" x="892.75" y="704.0005">measurement newer?</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="860.75" y="697.5981">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="1029.75" y="697.5981">no</text><path d="M533.5,722.1924 L533.5,738.3252 L513.5,742.3252 L533.5,746.3252 L533.5,762.458 A0,0 0 0 0 533.5,762.458 L875.5,762.458 A0,0 0 0 0 875.5,762.458 L875.5,732.1924 L865.5,722.1924 L533.5,722.1924 A0,0 0 0 0 533.5,722.1924 " fill
 ="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M865.5,722.1924 L865.5,732.1924 L875.5,732.1924 L865.5,722.1924 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="179" x="539.5" y="739.2593">if n.idhex in prev_consensus</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="305" x="555.5" y="754.3921">and ("Guard" in prev_consensus[n.idhex].flags=</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="489.5" y="725.3408"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="503.5" y="746.4795"/><path d="M533.5,847.4697 L533.5,878.7354 L513.5,882.7354 L533.5,886.7354 L533.5,918.001 A0,0 0 0 0 533.5,918.001 L980.5,918
 .001 A0,0 0 0 0 980.5,918.001 L980.5,857.4697 L970.5,847.4697 L533.5,847.4697 A0,0 0 0 0 533.5,847.4697 " fill="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M970.5,847.4697 L970.5,857.4697 L980.5,857.4697 L970.5,847.4697 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="239" x="539.5" y="864.5366">if n.idhex not in prev_votes.vote_map</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="410" x="555.5" y="879.6694">or n.measured_at - prev_votes.vote_map[n.idhex].measured_at</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="194" x="571.5" y="894.8022">> cs_junk.guard_sample_rate:</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="352" x="571.5"
  y="909.9351"># cs_jung.guard_sample_rate = 2*7*24*60*60 # 2wks</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="489.5" y="865.751"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="503.5" y="886.8896"/><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="395.5,953.001,607.5,953.001,619.5,965.001,607.5,977.001,395.5,977.001,383.5,965.001,395.5,953.001" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="212" x="395.5" y="968.8091">not exit diff NOT bigger than 2 weeks</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="363.5" y="962.4067">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength=
 "14" x="619.5" y="962.4067">no</text><path d="M249,987.001 L249,1040.9658 L229,1044.9658 L249,1048.9658 L249,1102.9307 A0,0 0 0 0 249,1102.9307 L636,1102.9307 A0,0 0 0 0 636,1102.9307 L636,997.001 L626,987.001 L249,987.001 A0,0 0 0 0 249,987.001 " fill="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M626,987.001 L626,997.001 L636,997.001 L626,987.001 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="280" x="255" y="1004.0679">\# Use new measurement but not feedback</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="283" x="255" y="1019.2007">n.copy_vote(prev_vote.vote_map[n.idhex]));</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="366" x="255" y="1034.3335">n.new_bw = n.get_pid_bw(prev_votes.vote_map[n
 .idhex],</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="78" x="303" y="1049.4663">cs_junk.K_p,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="73" x="303" y="1064.5991">cs_junk.K_i,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="78" x="303" y="1079.7319">cs_junk.K_d,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="66" x="303" y="1094.8647">0.0, False)</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="205" y="1027.9814"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="219" y="1049.1201"/><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="145.7188" rx="12.5" ry="12.
 5" style="stroke: #A80036; stroke-width: 1.5;" width="358" x="38" y="1137.9307"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="204" x="48" y="1159.0693">\# self.new_bw = vote.bw * 1000</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="159" x="48" y="1173.0381">self.pid_bw = vote.pid_bw</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="251" x="48" y="1187.0068">self.pid_error_sum = vote.pid_error_sum</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="189" x="48" y="1200.9756">self.pid_delta = vote.pid_delta</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="52" y="1214.9443"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="338
 " x="48" y="1228.9131">n.new_bw = self.use_bw + self.use_bw * self_pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="52" y="1242.8818"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="258" x="48" y="1256.8506">n.measured_at = prev_vote.measured_at</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="206" x="48" y="1270.8193">n.pid_error = prev_vote.pid_error</text><path d="M818,987.001 L818,1048.5322 L798,1052.5322 L818,1056.5322 L818,1118.0635 A0,0 0 0 0 818,1118.0635 L1205,1118.0635 A0,0 0 0 0 1205,1118.0635 L1205,997.001 L1195,987.001 L818,987.001 A0,0 0 0 0 818,987.001 " fill="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M1195,987.001 L1195,997.001 L1205,997.001 L1195,987.001 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text 
 fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="12" x="824" y="1004.0679">1.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="80" x="840" y="1004.0679">full feedback</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="366" x="824" y="1019.2007">n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="78" x="888" y="1034.3335">cs_junk.K_p,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="73" x="888" y="1049.4663">cs_junk.K_i,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="78" x="888" y="1064.5991">cs_junk.K_d,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdj
 ust="spacingAndGlyphs" textLength="119" x="888" y="1079.7319">cs_junk.K_i_decay)</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="301" x="840" y="1094.8647">= n.get_pid_bw(prev_votes.vote_map[n.idhex],</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="73" x="900" y="1109.9976">1.0, 0, 0, 0)</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="774" y="1035.5479"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="788" y="1056.6865"/><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="103.8125" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="260" x="656" y="1153.0635"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="228" x
 ="666" y="1174.2021">self.prev_error = prev_vote.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="158" x="666" y="1188.1709">self.pid_bw = self.use_bw</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="182" x="682" y="1202.1396">+ self.use_bw * self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="203" x="682" y="1216.1084"># + self.desc_bw * self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="240" x="666" y="1230.0771">self.pid_error_sum = 0 + self.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="146" x="666" y="1244.0459">n.new_bw = self.pid_bw</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="501.5,1289.6494,513.5,1301
 .6494,501.5,1313.6494,489.5,1301.6494,501.5,1289.6494" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="444,797.458,559,797.458,571,810.2627,559,823.0674,444,823.0674,432,810.2627,444,797.458" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="505.5" y="833.2778">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="111" x="444" y="807.6685">in prev_consensus,</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="53" x="444" y="820.4731">is guard?</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="501.5,1333.6494,513.5,1345.6494,501.5,1357.6494,489.5,1345.6494,501.5,1333.6494" style="stroke: #A80036; stroke-width: 1.5;"/><path d="M1441,722.1924 L1441,753.458 L1421,757.458 L1441,761.458 L14
 41,792.7236 A0,0 0 0 0 1441,792.7236 L1854,792.7236 A0,0 0 0 0 1854,792.7236 L1854,732.1924 L1844,722.1924 L1441,722.1924 A0,0 0 0 0 1441,722.1924 " fill="#FBFB77" filter="url(#f1g4fkgeqyp6on)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M1844,722.1924 L1844,732.1924 L1854,732.1924 L1844,722.1924 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="392" x="1447" y="739.2593">\# Reset values. Don't vote/sample this measurement round.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="384" x="1447" y="754.3921">\# is in the previous bwfile, but haven't check the consensus</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="309" x="1447" y="769.5249">n.revert_to_vote(prev_votes.vote_map[n.idhex])</text><text fill="#000000" font-family="sans-serif"
  font-size="13" lengthAdjust="spacingAndGlyphs" textLength="258" x="1447" y="784.6577">\# which calls again self.copy_vote(vote)</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="1397" y="740.4736"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="1411" y="761.6123"/><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="117.7813" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="304" x="1257" y="827.7236"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="211" x="1267" y="848.8623">self.new_bw = prev_vote.bw*1000</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="192" x="1267" y="862.8311">self.pid_bw = prev_vote.pid_bw</text><text fill="#000000" font-family="sans-serif" font-size="1
 2" lengthAdjust="spacingAndGlyphs" textLength="284" x="1267" y="876.7998">self.pid_error_sum = prev_vote.pid_error_sum</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="222" x="1267" y="890.7686">self.pid_delta = prev_vote.pid_delta</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="1271" y="904.7373"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="187" x="1267" y="918.7061">self.pid_error = vote.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="239" x="1267" y="932.6748">self.measured_at = vote.measured_at</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="955.25,1363.6494,967.25,1375.6494,955.25,1387.6494,943.25,1375.6494,955.25,1363.6494" style="stroke: #A80036; stroke-width: 1.5;"/><rect fill="#FEFECE" filter="
 url(#f1g4fkgeqyp6on)" height="61.9063" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="314" x="1884" y="612.9268"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="294" x="1894" y="634.0654">n.new_bw = n.use_bw + n.use_bw * n.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="186" x="1894" y="648.0342">n.pid_error_sum = n.pid_error</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="132" x="1894" y="662.0029">n.pid_bw = n.new_bw</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="1498.125,1393.6494,1510.125,1405.6494,1498.125,1417.6494,1486.125,1405.6494,1498.125,1393.6494" style="stroke: #A80036; stroke-width: 1.5;"/><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="289" x="
 1353.625" y="1534.4541"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="269" x="1363.625" y="1555.5928">prev_consensus[n.idhex].measured = True</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="176" x="1410.125" y="1603.4229"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="156" x="1420.125" y="1624.5615">tot_net_bw += n.new_bw</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="1371.625,1486.0518,1624.625,1486.0518,1636.625,1498.0518,1624.625,1510.0518,1371.625,1510.0518,1359.625,1498.0518,1371.625,1486.0518" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="1502.125" y="1520.2622">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" len
 gthAdjust="spacingAndGlyphs" textLength="253" x="1371.625" y="1501.8599">prev_consensus[n.idhex].bandwidth != None</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="1498.125,1657.3916,1510.125,1669.3916,1498.125,1681.3916,1486.125,1669.3916,1498.125,1657.3916" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="1422.125,1437.6494,1574.125,1437.6494,1586.125,1449.6494,1574.125,1461.6494,1422.125,1461.6494,1410.125,1449.6494,1422.125,1437.6494" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="1502.125" y="1471.8599">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="152" x="1422.125" y="1453.4575">n.idhex in prev_consensus</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="1498.125,1701.3916,1510.125,1713.3916,1498.125,1725.391
 6,1486.125,1713.3916,1498.125,1701.3916" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="1421.125,192.8594,1575.125,192.8594,1587.125,204.8594,1575.125,216.8594,1421.125,216.8594,1409.125,204.8594,1421.125,192.8594" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="154" x="1421.125" y="208.6675">for n in nodes.itervalues()?</text><rect fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="55" x="1470.625" y="1811.3916"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="35" x="1480.625" y="1832.5303">cap...</text><polygon fill="#FEFECE" filter="url(#f1g4fkgeqyp6on)" points="1421.125,1767.3916,1575.125,1767.3916,1587.125,1779.3916,1575.125,1791.3916,1421.125,1791.3916,1409.125,1779.3916,1421.125,1
 767.3916" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="154" x="1421.125" y="1783.1997">for n in nodes.itervalues()?</text><ellipse cx="1399.125" cy="1821.3916" fill="none" filter="url(#f1g4fkgeqyp6on)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="1399.625" cy="1821.8916" fill="#000000" filter="url(#f1g4fkgeqyp6on)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="64.9219" y2="84.9219"/><polygon fill="#A80036" points="1494.125,74.9219,1498.125,84.9219,1502.125,74.9219,1498.125,78.9219" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="118.8906" y2="138.8906"/><polygon fill="#A80036" points="1494.125,128.8906,1498.125,138.8906,1502.125,128.8906,1498.125,132.8906" style="stroke: #A80036; str
 oke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="297.9268" y2="317.9268"/><polygon fill="#A80036" points="1494.125,307.9268,1498.125,317.9268,1502.125,307.9268,1498.125,311.9268" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="351.8955" y2="371.8955"/><polygon fill="#A80036" points="1494.125,361.8955,1498.125,371.8955,1502.125,361.8955,1498.125,365.8955" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="405.8643" y2="464.4111"/><polygon fill="#A80036" points="1494.125,454.4111,1498.125,464.4111,1502.125,454.4111,1498.125,458.4111" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="217" x2="217" y1="1061.9502" y2="1137.9307"/><polygon fill="#A80036" points="213,1127.9307,217,1137.9307,221,1127.9307,217,1131.9307" style="stroke: #A800
 36; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="786" x2="786" y1="1069.5166" y2="1153.0635"/><polygon fill="#A80036" points="782,1143.0635,786,1153.0635,790,1143.0635,786,1147.0635" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="383.5" x2="217" y1="965.001" y2="965.001"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="217" x2="217" y1="965.001" y2="1027.9814"/><polygon fill="#A80036" points="213,1017.9814,217,1027.9814,221,1017.9814,217,1021.9814" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="619.5" x2="786" y1="965.001" y2="965.001"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="786" x2="786" y1="965.001" y2="1035.5479"/><polygon fill="#A80036" points="782,1025.5479,786,1035.5479,790,1025.5479,786,1029.5479" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="217" x2="217" y1="1283.6494" 
 y2="1301.6494"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="217" x2="489.5" y1="1301.6494" y2="1301.6494"/><polygon fill="#A80036" points="479.5,1297.6494,489.5,1301.6494,479.5,1305.6494,483.5,1301.6494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="786" x2="786" y1="1256.876" y2="1301.6494"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="786" x2="513.5" y1="1301.6494" y2="1301.6494"/><polygon fill="#A80036" points="523.5,1297.6494,513.5,1301.6494,523.5,1305.6494,519.5,1301.6494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="501.5" x2="501.5" y1="899.7197" y2="953.001"/><polygon fill="#A80036" points="497.5,943.001,501.5,953.001,505.5,943.001,501.5,947.001" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="501.5" x2="501.5" y1="823.0674" y2="865.751"/><polygon fill="#A80036" points="497.5,855.751,501.5,865.751,505
 .5,855.751,501.5,859.751" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="571" x2="1225" y1="810.2627" y2="810.2627"/><polygon fill="#A80036" points="1221,1070.1572,1225,1080.1572,1229,1070.1572,1225,1074.1572" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1225" x2="1225" y1="810.2627" y2="1345.6494"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1225" x2="513.5" y1="1345.6494" y2="1345.6494"/><polygon fill="#A80036" points="523.5,1341.6494,513.5,1345.6494,523.5,1349.6494,519.5,1345.6494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="501.5" x2="501.5" y1="1313.6494" y2="1333.6494"/><polygon fill="#A80036" points="497.5,1323.6494,501.5,1333.6494,505.5,1323.6494,501.5,1327.6494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="501.5" x2="501.5" y1="759.3096" y2="797.458"/><
 polygon fill="#A80036" points="497.5,787.458,501.5,797.458,505.5,787.458,501.5,791.458" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1409" x2="1409" y1="774.4424" y2="827.7236"/><polygon fill="#A80036" points="1405,817.7236,1409,827.7236,1413,817.7236,1409,821.7236" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="880.75" x2="501.5" y1="700.1924" y2="700.1924"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="501.5" x2="501.5" y1="700.1924" y2="725.3408"/><polygon fill="#A80036" points="497.5,715.3408,501.5,725.3408,505.5,715.3408,501.5,719.3408" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1029.75" x2="1409" y1="700.1924" y2="700.1924"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1409" x2="1409" y1="700.1924" y2="740.4736"/><polygon fill="#A80036" points="1405,730.4736,1409,740.4736,1413,730.4736,1409,734.4736" 
 style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="501.5" x2="501.5" y1="1357.6494" y2="1375.6494"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="501.5" x2="943.25" y1="1375.6494" y2="1375.6494"/><polygon fill="#A80036" points="933.25,1371.6494,943.25,1375.6494,933.25,1379.6494,937.25,1375.6494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1409" x2="1409" y1="945.5049" y2="1375.6494"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1409" x2="967.25" y1="1375.6494" y2="1375.6494"/><polygon fill="#A80036" points="977.25,1371.6494,967.25,1375.6494,977.25,1379.6494,973.25,1375.6494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="955.25" x2="955.25" y1="650.0439" y2="688.1924"/><polygon fill="#A80036" points="951.25,678.1924,955.25,688.1924,959.25,678.1924,955.25,682.1924" style="stroke: #A80036; stroke-width: 1.0;"/><line
  style="stroke: #A80036; stroke-width: 1.5;" x1="1393.125" x2="955.25" y1="590.9268" y2="590.9268"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="955.25" x2="955.25" y1="590.9268" y2="616.0752"/><polygon fill="#A80036" points="951.25,606.0752,955.25,616.0752,959.25,606.0752,955.25,610.0752" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1603.125" x2="2041" y1="590.9268" y2="590.9268"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2041" x2="2041" y1="590.9268" y2="612.9268"/><polygon fill="#A80036" points="2037,602.9268,2041,612.9268,2045,602.9268,2041,606.9268" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="955.25" x2="955.25" y1="1387.6494" y2="1405.6494"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="955.25" x2="1486.125" y1="1405.6494" y2="1405.6494"/><polygon fill="#A80036" points="1476.125,1401.6494,1486.125,1405.6494,1476.125,1409.6494,1480.125,1405.6
 494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2041" x2="2041" y1="674.833" y2="1405.6494"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2041" x2="1510.125" y1="1405.6494" y2="1405.6494"/><polygon fill="#A80036" points="1520.125,1401.6494,1510.125,1405.6494,1520.125,1409.6494,1516.125,1405.6494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="498.3799" y2="578.9268"/><polygon fill="#A80036" points="1494.125,568.9268,1498.125,578.9268,1502.125,568.9268,1498.125,572.9268" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1568.4229" y2="1603.4229"/><polygon fill="#A80036" points="1494.125,1593.4229,1498.125,1603.4229,1502.125,1593.4229,1498.125,1597.4229" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1
 498.125" y1="1510.0518" y2="1534.4541"/><polygon fill="#A80036" points="1494.125,1524.4541,1498.125,1534.4541,1502.125,1524.4541,1498.125,1528.4541" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1636.625" x2="1652.625" y1="1498.0518" y2="1498.0518"/><polygon fill="#A80036" points="1648.625,1575.9229,1652.625,1585.9229,1656.625,1575.9229,1652.625,1579.9229" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1652.625" x2="1652.625" y1="1498.0518" y2="1669.3916"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1652.625" x2="1510.125" y1="1669.3916" y2="1669.3916"/><polygon fill="#A80036" points="1520.125,1665.3916,1510.125,1669.3916,1520.125,1673.3916,1516.125,1669.3916" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1637.3916" y2="1657.3916"/><polygon fill="#A80036" points="1494.125,1647.3916,1498.125
 ,1657.3916,1502.125,1647.3916,1498.125,1651.3916" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1461.6494" y2="1486.0518"/><polygon fill="#A80036" points="1494.125,1476.0518,1498.125,1486.0518,1502.125,1476.0518,1498.125,1480.0518" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1586.125" x2="1674.625" y1="1449.6494" y2="1449.6494"/><polygon fill="#A80036" points="1670.625,1575.9229,1674.625,1585.9229,1678.625,1575.9229,1674.625,1579.9229" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1674.625" x2="1674.625" y1="1449.6494" y2="1713.3916"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1674.625" x2="1510.125" y1="1713.3916" y2="1713.3916"/><polygon fill="#A80036" points="1520.125,1709.3916,1510.125,1713.3916,1520.125,1717.3916,1516.125,1713.3916" style="stroke: #A80036; stroke-width: 1.0;"/><lin
 e style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1681.3916" y2="1701.3916"/><polygon fill="#A80036" points="1494.125,1691.3916,1498.125,1701.3916,1502.125,1691.3916,1498.125,1695.3916" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1417.6494" y2="1437.6494"/><polygon fill="#A80036" points="1494.125,1427.6494,1498.125,1437.6494,1502.125,1427.6494,1498.125,1431.6494" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="216.8594" y2="263.958"/><polygon fill="#A80036" points="1494.125,253.958,1498.125,263.958,1502.125,253.958,1498.125,257.958" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1725.3916" y2="1735.3916"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="2212" y1="1735.3916" y2="1735.3916"/><polygon 
 fill="#A80036" points="2208,949.6299,2212,939.6299,2216,949.6299,2212,945.6299" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2212" x2="2212" y1="204.8594" y2="1735.3916"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="2212" x2="1587.125" y1="204.8594" y2="204.8594"/><polygon fill="#A80036" points="1597.125,200.8594,1587.125,204.8594,1597.125,208.8594,1593.125,204.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1409.125" x2="24" y1="204.8594" y2="204.8594"/><polygon fill="#A80036" points="20,935.6299,24,945.6299,28,935.6299,24,939.6299" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="24" x2="24" y1="204.8594" y2="1747.3916"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="24" x2="1498.125" y1="1747.3916" y2="1747.3916"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1747.3916" 
 y2="1767.3916"/><polygon fill="#A80036" points="1494.125,1757.3916,1498.125,1767.3916,1502.125,1757.3916,1498.125,1761.3916" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="172.8594" y2="192.8594"/><polygon fill="#A80036" points="1494.125,182.8594,1498.125,192.8594,1502.125,182.8594,1498.125,186.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1791.3916" y2="1811.3916"/><polygon fill="#A80036" points="1494.125,1801.3916,1498.125,1811.3916,1502.125,1801.3916,1498.125,1805.3916" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1498.125" y1="1845.3604" y2="1855.3604"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1498.125" x2="1599.125" y1="1855.3604" y2="1855.3604"/><polygon fill="#A80036" points="1595.125,1826.376,1599.125,1816.376,1603.125,1826.376,159
 9.125,1822.376" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1599.125" x2="1599.125" y1="1779.3916" y2="1855.3604"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1599.125" x2="1587.125" y1="1779.3916" y2="1779.3916"/><polygon fill="#A80036" points="1597.125,1775.3916,1587.125,1779.3916,1597.125,1783.3916,1593.125,1779.3916" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1409.125" x2="1399.125" y1="1779.3916" y2="1779.3916"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="1399.125" x2="1399.125" y1="1779.3916" y2="1811.3916"/><polygon fill="#A80036" points="1395.125,1801.3916,1399.125,1811.3916,1403.125,1801.3916,1399.125,1805.3916" style="stroke: #A80036; stroke-width: 1.0;"/><!--
+ at startuml
+title "Torflow measurements scaling with PID control (Per relay scaled bandwidth)."
+
+:prev_votes = VoteSet();
+note right
+initialize measurements from previous Bandwidth File
+end note
+:tot_net_bw = 0;
+:;
+note right
+    for every measurement
+end note
+while (for n in nodes.itervalues()?)
+    partition "Intialize ratios and pid_error" {
+        :n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()];
+        :n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()];
+        :n.use_bw = n.desc_bw;
+        :n.pid_error = max(bwstrm_i / bwstrm, bwfilt_i / bwfilt) - 1;
+        note right
+            if n.sbw_ratio > n.fbw_ratio:
+            #assert cs_junk.use_best_ratio == True
+            n.pid_error = (n.strm_bw - true_strm_avg[n.node_class()])
+                                / true_strm_avg[n.node_class()]
+            else:
+            n.pid_error = (n.filt_bw - true_filt_avg[n.node_class()])
+                                / true_filt_avg[n.node_class()]
+            0 <= n.pid_error <= 500.0
+        end note
+    }
+    if (n.idhex in prev_votes.vote_map?) then (yes)
+        :;
+        note right
+        if n.measured_at >
+        prev_votes.vote_map[n.idhex].measured_at;
+        end note
+        if (measurement newer?) then (yes)
+            :;
+            note right
+            if n.idhex in prev_consensus
+                and ("Guard" in prev_consensus[n.idhex].flags=
+            end note
+            if (in prev_consensus, \nis guard?) then (yes)
+                :;
+                note right
+                if n.idhex not in prev_votes.vote_map
+                    or n.measured_at - prev_votes.vote_map[n.idhex].measured_at
+                        > cs_junk.guard_sample_rate:
+                        # cs_jung.guard_sample_rate = 2*7*24*60*60 # 2wks
+                end note
+                if (not exit diff NOT bigger than 2 weeks) then (yes)
+                    :;
+                    note right
+                    \# Use new measurement but not feedback
+                    n.copy_vote(prev_vote.vote_map[n.idhex]));
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                cs_junk.K_p,
+                                cs_junk.K_i,
+                                cs_junk.K_d,
+                                0.0, False)
+                    end note
+                    :\# self.new_bw = vote.bw * 1000
+                    self.pid_bw = vote.pid_bw
+                    self.pid_error_sum = vote.pid_error_sum
+                    self.pid_delta = vote.pid_delta
+
+                    n.new_bw = self.use_bw + self.use_bw * self_pid_error
+
+                    n.measured_at = prev_vote.measured_at
+                    n.pid_error = prev_vote.pid_error;
+                else (no)
+                    :;
+                    note right
+                    # full feedback
+                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                    cs_junk.K_p,
+                                    cs_junk.K_i,
+                                    cs_junk.K_d,
+                                    cs_junk.K_i_decay)
+                        = n.get_pid_bw(prev_votes.vote_map[n.idhex],
+                                       1.0, 0, 0, 0)
+                    end note
+                    :self.prev_error = prev_vote.pid_error
+                    self.pid_bw = self.use_bw
+                        + self.use_bw * self.pid_error
+                        # + self.desc_bw * self.pid_error
+                    self.pid_error_sum = 0 + self.pid_error
+                    n.new_bw = self.pid_bw;
+                endif
+            endif
+        else (no)
+            :;
+            note right
+            \# Reset values. Don't vote/sample this measurement round.
+            \# is in the previous bwfile, but haven't check the consensus
+            n.revert_to_vote(prev_votes.vote_map[n.idhex])
+            \# which calls again self.copy_vote(vote)
+            end note
+            :self.new_bw = prev_vote.bw*1000
+            self.pid_bw = prev_vote.pid_bw
+            self.pid_error_sum = prev_vote.pid_error_sum
+            self.pid_delta = prev_vote.pid_delta
+
+            self.pid_error = vote.pid_error
+            self.measured_at = vote.measured_at;
+
+        endif
+    else (no)
+        :n.new_bw = n.use_bw + n.use_bw * n.pid_error
+        n.pid_error_sum = n.pid_error
+        n.pid_bw = n.new_bw;
+    endif
+
+    if (n.idhex in prev_consensus) then (yes)
+        if (prev_consensus[n.idhex].bandwidth != None) then (yes)
+            :prev_consensus[n.idhex].measured = True;
+            :tot_net_bw += n.new_bw;
+        endif
+    endif
+endwhile
+while (for n in nodes.itervalues()?)
+    :cap...;
+endwhile
+stop
+
+ at enduml
+
+PlantUML version 1.2018.13(Mon Nov 26 17:11:51 GMT 2018)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.9.1+1-post-Debian-1deb10u2
+Operating System: Linux
+OS Version: 4.19.0-13-amd64
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/images/activity_torflow_scaling_simplified1.svg b/docs/source/images/activity_torflow_scaling_simplified1.svg
new file mode 100644
index 0000000..c1de0ba
--- /dev/null
+++ b/docs/source/images/activity_torflow_scaling_simplified1.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="976px" preserveAspectRatio="none" style="width:726px;height:976px;" version="1.1" viewBox="0 0 726 976" width="726px" zoomAndPan="magnify"><defs><filter height="300%" id="f1pyhrde7xrk7i" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><text fill="#000000" font-family="sans-serif" font-size="18" lengthAdjust="spacingAndGlyphs" textLength="702" x="12" y="26.708">"Torflow measurements scaling with PID control (Per relay scaled bandwidth)."</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" he
 ight="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="165" x="266.75" y="30.9531"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="145" x="276.75" y="52.0918">prev_votes = VoteSet()</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="114" x="292.25" y="84.9219"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="94" x="302.25" y="106.0605">tot_net_bw = 0</text><path d="M381.25,143.3086 L381.25,151.875 L361.25,155.875 L381.25,159.875 L381.25,168.4414 A0,0 0 0 0 381.25,168.4414 L553.25,168.4414 A0,0 0 0 0 553.25,168.4414 L553.25,153.3086 L543.25,143.3086 L381.25,143.3086 A0,0 0 0 0 381.25,143.3086 " fill="#FBFB77" filter="url(#f1pyhrde7xrk7i)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M543.25,143.3086 L543.25,153.3086 L553.25,153.3086 L543.2
 5,143.3086 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="151" x="387.25" y="160.3755">for every measurement</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="24" x="337.25" y="138.8906"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="0" x="351.25" y="160.0293"/><rect fill="#FFFFFF" filter="url(#f1pyhrde7xrk7i)" height="244.1719" style="stroke: #000000; stroke-width: 2.0;" width="386" x="156.25" y="227.6611"/><path d="M354.25,228.6611 L354.25,236.958 L344.25,246.958 L156.25,246.958 " fill="none" style="stroke: #000000; stroke-width: 2.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="188" x="159.25" y="241.6563">Intialize ratios and pid_error</text><rect f
 ill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="337" x="180.75" y="263.958"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="317" x="190.75" y="285.0967">n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()]</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="366" x="166.25" y="317.9268"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="346" x="176.25" y="339.0654">n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()]</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="161" x="268.75" y="371.8955"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="141" 
 x="278.75" y="393.0342">n.use_bw = n.desc_bw</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="308" x="195.25" y="425.8643"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="288" x="205.25" y="447.0029">n.pid_error = max(n.fbw_ratio, n.sbw_ratio) - 1</text><polygon fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" points="257.25,491.833,441.25,491.833,453.25,504.6377,441.25,517.4424,257.25,517.4424,245.25,504.6377,257.25,491.833" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="180" x="257.25" y="502.0435">n.idhex in prev_votes.vote_map</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="172" x="257.25" y="514.8481">and not newer measurement?</text><text fill="#000000" font-family="
 sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="225.25" y="502.0435">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="453.25" y="502.0435">no</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="47.9375" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="259" x="66.5" y="527.4424"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="211" x="76.5" y="548.5811">self.new_bw = prev_vote.bw*1000</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="239" x="76.5" y="562.5498">self.measured_at = vote.measured_at</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="314" x="345.5" y="527.4424"/><text fill="#000000" font-family="sans-serif" font-size="12" length
 Adjust="spacingAndGlyphs" textLength="294" x="355.5" y="548.5811">n.new_bw = n.use_bw + n.use_bw * n.pid_error</text><polygon fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" points="349.25,581.3799,361.25,593.3799,349.25,605.3799,337.25,593.3799,349.25,581.3799" style="stroke: #A80036; stroke-width: 1.5;"/><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="289" x="204.75" y="675.3916"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="269" x="214.75" y="696.5303">prev_consensus[n.idhex].measured = True</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="176" x="261.25" y="744.3604"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="156" x="271.25" y="765.499">tot_net_bw += n.new_bw</text><polygon fil
 l="#FEFECE" filter="url(#f1pyhrde7xrk7i)" points="210.25,625.3799,488.25,625.3799,500.25,638.1846,488.25,650.9893,210.25,650.9893,198.25,638.1846,210.25,625.3799" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="353.25" y="661.1997">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="152" x="210.25" y="635.5903">n.idhex in prev_consensus</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="278" x="210.25" y="648.395">and prev_consensus[n.idhex].bandwidth != None</text><polygon fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" points="349.25,798.3291,361.25,810.3291,349.25,822.3291,337.25,810.3291,349.25,798.3291" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" points="272.25,192.8594,426.25,192.8594,438.25,204.85
 94,426.25,216.8594,272.25,216.8594,260.25,204.8594,272.25,192.8594" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="154" x="272.25" y="208.6675">for n in nodes.itervalues()?</text><rect fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="55" x="321.75" y="908.3291"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="35" x="331.75" y="929.4678">cap...</text><polygon fill="#FEFECE" filter="url(#f1pyhrde7xrk7i)" points="272.25,864.3291,426.25,864.3291,438.25,876.3291,426.25,888.3291,272.25,888.3291,260.25,876.3291,272.25,864.3291" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="154" x="272.25" y="880.1372">for n in nodes.itervalues()?</text><ellipse cx=
 "250.25" cy="918.3291" fill="none" filter="url(#f1pyhrde7xrk7i)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="250.75" cy="918.8291" fill="#000000" filter="url(#f1pyhrde7xrk7i)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="64.9219" y2="84.9219"/><polygon fill="#A80036" points="345.25,74.9219,349.25,84.9219,353.25,74.9219,349.25,78.9219" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="118.8906" y2="138.8906"/><polygon fill="#A80036" points="345.25,128.8906,349.25,138.8906,353.25,128.8906,349.25,132.8906" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="297.9268" y2="317.9268"/><polygon fill="#A80036" points="345.25,307.9268,349.25,317.9268,353.25,307.9268,349.25,311.9268" style="stroke: #A80036; stroke-width: 1.0;"/><line 
 style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="351.8955" y2="371.8955"/><polygon fill="#A80036" points="345.25,361.8955,349.25,371.8955,353.25,361.8955,349.25,365.8955" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="405.8643" y2="425.8643"/><polygon fill="#A80036" points="345.25,415.8643,349.25,425.8643,353.25,415.8643,349.25,419.8643" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="245.25" x2="196" y1="504.6377" y2="504.6377"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="196" x2="196" y1="504.6377" y2="527.4424"/><polygon fill="#A80036" points="192,517.4424,196,527.4424,200,517.4424,196,521.4424" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="453.25" x2="502.5" y1="504.6377" y2="504.6377"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="502.5" x2="502.5" y1="504.6377
 " y2="527.4424"/><polygon fill="#A80036" points="498.5,517.4424,502.5,527.4424,506.5,517.4424,502.5,521.4424" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="196" x2="196" y1="575.3799" y2="593.3799"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="196" x2="337.25" y1="593.3799" y2="593.3799"/><polygon fill="#A80036" points="327.25,589.3799,337.25,593.3799,327.25,597.3799,331.25,593.3799" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="502.5" x2="502.5" y1="561.4111" y2="593.3799"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="502.5" x2="361.25" y1="593.3799" y2="593.3799"/><polygon fill="#A80036" points="371.25,589.3799,361.25,593.3799,371.25,597.3799,367.25,593.3799" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="459.833" y2="491.833"/><polygon fill="#A80036" points="345.25,481.833,349.25,491
 .833,353.25,481.833,349.25,485.833" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="709.3604" y2="744.3604"/><polygon fill="#A80036" points="345.25,734.3604,349.25,744.3604,353.25,734.3604,349.25,738.3604" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="650.9893" y2="675.3916"/><polygon fill="#A80036" points="345.25,665.3916,349.25,675.3916,353.25,665.3916,349.25,669.3916" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="500.25" x2="512.25" y1="638.1846" y2="638.1846"/><polygon fill="#A80036" points="508.25,716.458,512.25,726.458,516.25,716.458,512.25,720.458" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="512.25" x2="512.25" y1="638.1846" y2="810.3291"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="512.25" x2="361.25" y1="810.
 3291" y2="810.3291"/><polygon fill="#A80036" points="371.25,806.3291,361.25,810.3291,371.25,814.3291,367.25,810.3291" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="778.3291" y2="798.3291"/><polygon fill="#A80036" points="345.25,788.3291,349.25,798.3291,353.25,788.3291,349.25,792.3291" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="605.3799" y2="625.3799"/><polygon fill="#A80036" points="345.25,615.3799,349.25,625.3799,353.25,615.3799,349.25,619.3799" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="216.8594" y2="263.958"/><polygon fill="#A80036" points="345.25,253.958,349.25,263.958,353.25,253.958,349.25,257.958" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="822.3291" y2="832.3291"/><
 line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="673.5" y1="832.3291" y2="832.3291"/><polygon fill="#A80036" points="669.5,498.6963,673.5,488.6963,677.5,498.6963,673.5,494.6963" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="673.5" x2="673.5" y1="204.8594" y2="832.3291"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="673.5" x2="438.25" y1="204.8594" y2="204.8594"/><polygon fill="#A80036" points="448.25,200.8594,438.25,204.8594,448.25,208.8594,444.25,204.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="260.25" x2="52.5" y1="204.8594" y2="204.8594"/><polygon fill="#A80036" points="48.5,484.6963,52.5,494.6963,56.5,484.6963,52.5,488.6963" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="52.5" x2="52.5" y1="204.8594" y2="844.3291"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="52.5" x2="349.25" y1="844
 .3291" y2="844.3291"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="844.3291" y2="864.3291"/><polygon fill="#A80036" points="345.25,854.3291,349.25,864.3291,353.25,854.3291,349.25,858.3291" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="172.8594" y2="192.8594"/><polygon fill="#A80036" points="345.25,182.8594,349.25,192.8594,353.25,182.8594,349.25,186.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="888.3291" y2="908.3291"/><polygon fill="#A80036" points="345.25,898.3291,349.25,908.3291,353.25,898.3291,349.25,902.3291" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="349.25" y1="942.2979" y2="952.2979"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="349.25" x2="450.25" y1="952.2979" y2="952.2979"/><polygon fill="#A80036" points="44
 6.25,923.3135,450.25,913.3135,454.25,923.3135,450.25,919.3135" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="450.25" x2="450.25" y1="876.3291" y2="952.2979"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="450.25" x2="438.25" y1="876.3291" y2="876.3291"/><polygon fill="#A80036" points="448.25,872.3291,438.25,876.3291,448.25,880.3291,444.25,876.3291" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="260.25" x2="250.25" y1="876.3291" y2="876.3291"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="250.25" x2="250.25" y1="876.3291" y2="908.3291"/><polygon fill="#A80036" points="246.25,898.3291,250.25,908.3291,254.25,898.3291,250.25,902.3291" style="stroke: #A80036; stroke-width: 1.0;"/><!--
+ at startuml
+title "Torflow measurements scaling with PID control (Per relay scaled bandwidth)."
+
+:prev_votes = VoteSet();
+:tot_net_bw = 0;
+:;
+note right
+    for every measurement
+end note
+while (for n in nodes.itervalues()?)
+    partition "Intialize ratios and pid_error" {
+        :n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()];
+        :n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()];
+        :n.use_bw = n.desc_bw;
+        :n.pid_error = max(n.fbw_ratio, n.sbw_ratio) - 1;
+    }
+    if (n.idhex in prev_votes.vote_map \nand not newer measurement?) then (yes)
+        :self.new_bw = prev_vote.bw*1000
+        self.measured_at = vote.measured_at;
+    else (no)
+        :n.new_bw = n.use_bw + n.use_bw * n.pid_error;
+    endif
+
+    if (n.idhex in prev_consensus \nand prev_consensus[n.idhex].bandwidth != None) then (yes)
+            :prev_consensus[n.idhex].measured = True;
+            :tot_net_bw += n.new_bw;
+    endif
+endwhile
+while (for n in nodes.itervalues()?)
+    :cap...;
+endwhile
+stop
+
+ at enduml
+
+PlantUML version 1.2018.13(Mon Nov 26 17:11:51 GMT 2018)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.9.1+1-post-Debian-1deb10u2
+Operating System: Linux
+OS Version: 4.19.0-13-amd64
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/torflow_aggr.rst b/docs/source/torflow_aggr.rst
index e9ae3b6..ee832cd 100644
--- a/docs/source/torflow_aggr.rst
+++ b/docs/source/torflow_aggr.rst
@@ -1,7 +1,9 @@
 .. _torflow_aggr:
 
-Torflow measurements aggregation
-==================================
+Torflow aggregation and scaling
+===============================
+
+.. seealso:: :ref:`generator` and :ref:`differences`.
 
 Torflow aggregation or scaling goal is:
 
@@ -11,11 +13,180 @@ From Torflow's `README.spec.txt`_ (section 2.2)::
     are effectively re-weighted proportional to how much faster the node
     was as compared to the rest of the network.
 
-With and without PID control
+Initialization
+--------------
+
+Constants in consensus that Torflow uses and don't change::
+
+  bandwidth-weights Wbd=0 Wbe=0 [] Wbm=10000 Wdb=10000 Web=10000 Wed=10000 Wee=10000 Weg=10000 Wem=10000 Wgb=10000 Wgd=0 Wgg=5852 [] Wmb=10000 Wmd=0 Wme=0 [] Wmm=10000
+
+  params [] bwauthpid=1
+
+Constants in the code::
+
+  IGNORE_GUARD = 0
+  GUARD_SAMPLE_RATE = 2*7*24*60*60 # 2wks
+  MAX_AGE = 2*GUARD_SAMPLE_RATE;  # 4 weeks
+
+  K_p = 1.0
+  T_i = 0
+  T_i_decay = 0
+  T_d = 0
+
+Initialization ``ConsensusJunk``::
+
+  self.bwauth_pid_control = True
+  self.group_by_class = False
+  self.use_pid_tgt = False
+  self.use_circ_fails = False
+  self.use_best_ratio = True
+  self.use_desc_bw = True
+  self.use_mercy = False
+  self.guard_sample_rate = GUARD_SAMPLE_RATE
+  self.pid_max = 500.0
+  self.K_p = K_p = 1.0
+  self.T_i = T_i = 0
+  self.T_d = T_d = 0
+  self.T_i_decay = T_i_decay = 0
+
+  self.K_i = 0
+  self.K_d = self.K_p*self.T_d = 0
+
+Initialization ``Node``::
+
+    self.sbw_ratio = None
+    self.fbw_ratio = None
+    self.pid_bw = 0
+    self.pid_error = 0
+    self.prev_error = 0
+    self.pid_error_sum = 0
+    self.pid_delta = 0
+    self.ratio = None
+    self.new_bw = None
+    self.use_bw = -1
+    self.flags = ""
+
+    # measurement vars from bwauth lines
+    self.measured_at = 0
+    self.strm_bw = 0
+    self.filt_bw = 0
+    self.ns_bw = 0
+    self.desc_bw = 0
+    self.circ_fail_rate = 0
+    self.strm_fail_rate = 0
+    self.updated_at = 0
+
+.. image:: ./images/activity_torflow_aggr.svg
+
+
+.. _relay-descriptors-bandwidth:
+
+Descriptor values for each relay
+--------------------------------
+
+From `TorCtl.py`_ code, it is the minimum of all the descriptor bandwidth
+values::
+
+    bws = map(int, g)
+    bw_observed = min(bws)
+
+    [snip]
+
+    return Router(ns.idhex, ns.nickname, bw_observed, dead, exitpolicy,
+    ns.flags, ip, version, os, uptime, published, contact, rate_limited,
+    ns.orhash, ns.bandwidth, extra_info_digest, ns.unmeasured)
+
+``ns.bandwidth`` is the consensus bandwidth, already multiplied by 1000::
+
+  yield NetworkStatus(*(m.groups()+(flags,)+(int(w.group(1))*1000,))+(unmeasured,))
+
+Because of the matched regular expression, ``bws`` is **not** all the descriptor
+bandwidth values, but the average bandwidth and the observed bandwidth, ie., it
+does not take the average burst, what seems to be a bug in Torflow.
+
+Eg. ``bandwidth`` line in a descriptor::
+
+  bandwidth 1536000 4096000 1728471
+
+Only takes the first and last values, so::
+
+  bw_observed = min(bandwidth-avg, bandwidth-observed)
+
+This is passed to ``Router``, in which the descriptors bandwidth is assigned to
+the consensus bandwidth when there is no consensus bandwidth::
+
+    (idhex, name, bw, down, exitpolicy, flags, ip, version, os, uptime,
+       published, contact, rate_limited, orhash,
+       ns_bandwidth,extra_info_digest,unmeasured) = args
+
+    [snip]
+
+    if ns_bandwidth != None:
+      self.bw = max(ns_bandwidth,1) # Avoid div by 0
+    else:
+      self.bw = max(bw,1) # Avoid div by 0
+
+    [snip]
+
+    self.desc_bw = max(bw,1) # Avoid div by 0
+
+So::
+
+  self.bw = ns_bwandwidth or min(bandwidth-avg, bandwidth-observed) or 1
+  desc_bw = min(bandwidth-avg, bandwidth-observed) or 1
+
+And written by `SQLSupport.py`_ as descriptor and conensus bandwidth::
+
+      f.write(" desc_bw="+str(int(cvt(s.avg_desc_bw,0))))
+      f.write(" ns_bw="+str(int(cvt(s.avg_bw,0)))+"\n")
+
+.. _relay-descriptor-bandwidth-pid:
+
+Descriptor bandwidth with PID control
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Even though `README.spec.txt`_ talks about the consensus bandwidth, in
+`aggregate.py`_ code, the consensus bandwidth is never used, since
+``use_desc_bw`` is initialized to True and never changed::
+
+    if cs_junk.bwauth_pid_control:
+      if cs_junk.use_desc_bw:
+        n.use_bw = n.desc_bw
+      else:
+        n.use_bw = n.ns_bw
+
+So::
+
+  n.use_bw = n.desc_bw = min(bandwidth-avg, bandwidth-observed) or 1
+
+
+Scaling the raw measurements
 ----------------------------
 
-Per relay measurements' bandwidth
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. _overview:
+
+Overview
+~~~~~~~~
+
+This diagram also includes
+:ref:`relay-descriptor-bandwidth-pid`,
+:ref:`relay-bandwidth-ratio` and :ref:`relay-scaled-bandwidth-pid`.
+
+.. image:: ./images/activity_torflow_scaling_simplified1.svg
+
+Simplified image from:
+
+.. image:: ./images/activity_torflow_scaling_simplified.svg
+
+`<./_images/activity_torflow_scaling_simplified.svg>`_
+
+.. image:: ./images/activity_torflow_scaling.svg
+
+`<./_images/activity_torflow_scaling.svg>`_
+
+
+Stream and filtered bandwidth for each relay
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 They are calculated in the same way whether or not `PID controller`_ feedback
 is used.
@@ -56,21 +227,16 @@ In the code, `SQLSupport.py`_, ``strm_bw`` is ``sbw`` and
 This is also expressed in pseudocode in the `bandwidth file spec`_, section B.4
 step 1.
 
-Calling ``bw_i`` to ``strm_bw`` and ``bwfilt_i`` to ``filt_bw``,
-if ``bw_j`` is a measurement for a relay ``i`` and ``m`` is the number of
-measurements for that relay, then:
-
-.. math::
+Calling ``bwstrm_i`` to ``strm_bw`` and ``bwfilt_i`` to ``filt_bw``,
+if ``bw_j`` is a measurement for a relay ``i``, then:::
 
-    bw_i = \mu(bw_j) = \frac{\sum_{j=1}^{m}bw_j}{m}
+  bwstrm_i = mean(bw_j)  # for a relay, the average of all its measurements
+  bwfilt_i = mean(max(bwstrm_i, bw_j))
 
-.. math::
+.. _stream-and-filtered-bandwidth-for-all-relays:
 
-    bwfilt_i &= \mu(max(\mu(bw_j), bw_j))
-              = \frac{\sum_{j=1}^{m} max\left(\frac{\sum_{j=1}^{m}bw_j}{m}, bw_j\right)}{m}
-
-Network measurements' bandwidth average
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Stream and filtered bandwidth for all relays
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 From `README.spec.txt`_ (section 2.1)::
 
@@ -79,34 +245,35 @@ From `README.spec.txt`_ (section 2.1)::
 
 In Torflow's `aggregate.py`_ code::
 
-    filt_avg = sum(map(lambda n: n.filt_bw, nodes.itervalues()))/float(len(nodes))
-    strm_avg = sum(map(lambda n: n.strm_bw, nodes.itervalues()))/float(len(nodes))
-
-Both in the code with PID and without, all types of nodes get the same
-average.
+  for cl in ["Guard+Exit", "Guard", "Exit", "Middle"]:
+    c_nodes = filter(lambda n: n.node_class() == cl, nodes.itervalues())
+    if len(c_nodes) > 0:
+      true_filt_avg[cl] = sum(map(lambda n: n.filt_bw, c_nodes))/float(len(c_nodes))
+      true_strm_avg[cl] = sum(map(lambda n: n.strm_bw, c_nodes))/float(len(c_nodes))
+      true_circ_avg[cl] = sum(map(lambda n: (1.0-n.circ_fail_rate),
+                            c_nodes))/float(len(c_nodes))
 
-This is also expressed in pseudocode in the `bandwidth file spec`_, section B.4
-step 2.
+The following code seems to be used only to log::
 
-Calling ``bwstrm`` to ``strm_avg`` and ``bwfilt`` to ``fitl_avg``, if ``n`` is
-the number of relays in the network, then:
+    filt_avg = sum(map(lambda n: n.filt_bw, nodes.itervalues()))/float(len(nodes))
+    strm_avg = sum(map(lambda n: n.strm_bw, nodes.itervalues()))/float(len(nodes))
 
-.. math::
+So it seems the ``filt_avg`` and ``strm_avg`` are calculated by class in both
+the cases with PID control and without PID control.
 
-   bwstrm &= \mu(bw_i)
-           = \frac{\sum_{i=1}^{n}bw_i}{n}
-           = \frac{\sum_{i=1}^{n} \frac{\sum_{j=1}^{m}bw_j}{m} }{n}
+Calling ``bwstrm`` to ``strm_avg`` and ``bwfilt`` to ``fitl_avg``, without
+taking into account the different types of nodes::
 
-.. math::
+  bwstrm = mean(bwstrm_i)
+  bwfilt = mean(bwfilt_i)
 
-   bwfilt &= \mu(bwfilt_i)
-           = \frac{\sum_{i=1}^{n}bwfilt_i}{n}
-           = \frac{\sum_{i=1}^{n}\frac{\sum_{j=1}^{m}max(\mu(bw_j), bw_j)}{m}}{n}
-           = \frac{\sum_{i=1}^{n}\frac{\sum_{j=1}^{m}max\left(\frac{\sum_{j=1}^{m}bw_j}{m}, bw_j\right)}{m}}{n}
+This is also expressed in pseudocode in the `bandwidth file spec`_, section B.4
+step 2.
 
+.. _relay-bandwidth-ratio:
 
-Per relay bandwidth ratio
-~~~~~~~~~~~~~~~~~~~~~~~~~
+Ratio for each relay
+~~~~~~~~~~~~~~~~~~~~
 
 From `README.spec.txt`_ (section 2.2)::
 
@@ -127,72 +294,17 @@ In Torflow's `aggregate.py`_ code::
       else:
         n.ratio = n.fbw_ratio
 
-This is also expressed in pseudocode in the `bandwidth file spec`_, section B.4
-step 2 and 3.
-
-Calling ``rf_i`` to ``fbw_ratio`` and ``rs_i`` to ``sbw_ration`` and ``r_i``
-to ``ratio``:
-
-.. math::
-
-    rf_i = \frac{bwfilt_i}{bwfilt}
-
-    rs_i = \frac{bw_i}{bwstrm}
-
-
-.. math::
-
-    r_i = max(rf_i, rs_i)
-        = max\left(\frac{bwfilt_i}{bwfilt}, \frac{bw_i}{bwstrm}\right)
-        = max\left(\frac{bwfilt_i}{\mu(bwfilt_i)}, \frac{bw_i}{\mu(bwfilt_i)}\right)
-
-Per relay descriptors bandwidth
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-From `TorCtl.py`_ code, it is the minimum of all the descriptor bandwidth
-values::
-
-    bws = map(int, g)
-    bw_observed = min(bws)
-
-    [snip]
-
-    return Router(ns.idhex, ns.nickname, bw_observed, dead, exitpolicy,
-    ns.flags, ip, version, os, uptime, published, contact, rate_limited,
-    ns.orhash, ns.bandwidth, extra_info_digest, ns.unmeasured)
-
-Because of the matched regular expression, ``bws`` is **not** all the descriptor
-bandwidth values, but the observed bandwidth and the burst bandwidth, ie., it
-does not take the average bandwidth, what seems to be a bug in Torflow.
-
-This is passed to ``Router``, in which the consensus bandwidth is assigned to the
-descriptor bandwidth when there is no consensus bandwidth::
-
-    (idhex, name, bw, down, exitpolicy, flags, ip, version, os, uptime,
-       published, contact, rate_limited, orhash,
-       ns_bandwidth,extra_info_digest,unmeasured) = args
-
-    [snip]
-
-    if ns_bandwidth != None:
-      self.bw = max(ns_bandwidth,1) # Avoid div by 0
-    else:
-      self.bw = max(bw,1) # Avoid div by 0
-
-    [snip]
-
-    self.desc_bw = max(bw,1) # Avoid div by 0
+So::
 
-And written by `SQLSupport.py`_ as descriptor and conensus bandwidth::
+  n.ratio = max(sbw_ratio, n.fbw_ratio)
 
-      f.write(" desc_bw="+str(int(cvt(s.avg_desc_bw,0))))
-      f.write(" ns_bw="+str(int(cvt(s.avg_bw,0)))+"\n")
+This is also expressed in pseudocode in the `bandwidth file spec`_, section B.4
+step 2 and 3.
 
-Without PID control
--------------------
+.. relay-scaled-no-pid:
 
-Per relay scaled bandwidth
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+Scaled bandwidth for each relay without PID control
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 From `README.spec.txt`_ (section 2.2)::
 
@@ -204,46 +316,20 @@ In `aggregate.py`_ code::
 
     n.new_bw = n.desc_bw*n.ratio
 
-This is also expressed in pseudocode in the `bandwidth file spec`_, section B.4
-step 5.
-
-Calling ``bwnew_i`` to ``new_bw`` and ``descbw_i`` to ``use_bw``:
-
-.. math::
-
-    descbw_i = min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right)
-
-    bwnew_i =& descbw_i \times r_i \
-
-            &= min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times max(rf_i, rs_i) \
-
-            &= min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times max\left(\frac{bwfilt_i}{bwfilt}, \frac{bw_i}{bwstrm}\right) \
-
-            &= min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times max\left(\frac{bwfilt_i}{\mu(bwfilt_i)}, \frac{bw_i}{\mu(bw_i)}\right)
-
-
-With PID control
-----------------
-
-Per relay descriptors bandwidth
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Even though `README.spec.txt`_ talks about the consensus bandwidth, in
-`aggregate.py`_ code, the consensus bandwidth is never used, since
-``use_desc_bw`` is initialized to True and never changed::
+So::
 
-    self.use_desc_bw = True
+    n.new_bw = (
+        min(bandwidth-avg, bandwidth-observed) or 1 \
+        * max(bwstrm_i / bwstrm, bwfilt_i / bwfilt_i)
+    )
 
-    [snip]
+This is also expressed in pseudocode in the `bandwidth file spec`_, section B.4
+step 5.
 
-    if cs_junk.bwauth_pid_control:
-      if cs_junk.use_desc_bw:
-        n.use_bw = n.desc_bw
-      else:
-        n.use_bw = n.ns_bw
+.. _relay-scaled-bandwidth-pid:
 
-Per relay scaled bandwidth
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+Scaled bandwidth for each relay with PID control
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 From `README.spec.txt`_ section 3.1::
 
@@ -292,38 +378,58 @@ greater::
 
     n.new_bw = n.use_bw + cs_junk.K_p*n.use_bw*n.pid_error
 
-Calling ``e_i`` to ``pid_error``, in the case that ``rs_i`` > ``rf_i``:
+So::
 
-.. math::
+  if (bwstrm_i / bwstrm) > (bwfilt_i / bwfilt):
+      pid_error = (bwstrm_i - bwstrm) / bwstrm = (bwstrm_i / bwstrm) - 1
+  else:
+      pid_error = (bwfilt_i - bwfilt_i) / bwfilt = (bwfilt_i / bwfilt) - 1
 
-    e_i = \frac{bw_i - bwstrm}{bwstrm} = \frac{bw_i}{bwstrm} - 1
+  new_bw = use_bw + use_bw * pid_error
 
-    bwn_i = descbw_i + descbw_i \times e_i = descbw_i \times (1 + e_i)
-          = descbw_i \times (1 + \frac{bw_i}{bwstrm} - 1)
-          = descbw_i \times \frac{bw_i}{bwstrm} = descbw_i \times rs_i
+Or::
 
-And in the case that ``rs_i`` < ``rf_i``:
+  if (bwstrm_i / bwstrm) > (bwfilt_i / bwfilt):
+      new_bw = use_bw + use_bw * ((bwstrm_i / bwstrm) - 1)
+      new_bw = use_bw + use_bw * (bwstrm_i / bwstrm) - use_bw
+      new_bw = use_bw * (bwstrm_i / bwstrm)
+  else:
+      new_bw = use_bw + use_bw * ((bwfilt_i / bwfilt) - 1)
+      new_bw = use_bw + use_bw * (bwfilt_i / bwfilt) - use_bw
+      new_bw = use_bw * (bwfilt_i / bwfilt)
 
-.. math::
+Or::
 
-    e_i = \frac{bwfilt_i - bwfilt}{bwfilt} = \frac{bwfilt_i}{bwfilt} - 1
+  new_bw = use_bw * max(bwstrm_i / bwstrm, bwfilt_i / bwfilt)
+  new_bw = (
+      min(bandwidth-avg, bandwidth-observed) or 1
+      * max(bwstrm_i / bwstrm, bwfilt_i / bwfilt)
+  )
 
-    bwn_i = descbw_i + descbw_i \times e_i = descbw_i \times (1 + e_i)
-          = descbw_i \times (1 + \frac{bwfilt_i}{bwfilt} - 1)
-          = descbw_i \times \frac{bwfilt_i}{bwfilt} = descbw_i \times rf_i
+.. note::
+    So, the new scaled bandwidth is the same for both cases with and without
+    PID controller!
 
-So, it is the same as the scaled bandwidth in the case without PID controller,
-ie.:
+Other pid KeyValues in the Bandwidth File
+-----------------------------------------
 
-.. math::
+.. note::
 
-    bwn_i = descbw_i \times max(rf_i, rs_i)
+  From the :ref:`overview` it seems that the only variable needed to
+  calculate the new scaled bandwidth is the ``pid_error``, and from
+  :ref:`relay-descriptor-bandwidth-pid`, it can be substituted
+  by the stream and filtered bandwidths.
 
-With and without PID control
-----------------------------
+This are the variables that can then be ignored::
+
+  pid_error_sum
+  pid_delta
+  prev_error
+
+Limit scaled bandwidth for each relay
+-------------------------------------
 
-Per relay scaled bandwidth limit
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+It's calculated the same with and without PID control
 
 Once each relay bandwidth is scaled, it is limited to a maximum, that is
 calculated as the sum of all the relays in the current consensus scaled
@@ -347,40 +453,8 @@ From `aggregate.py`_ code::
       n.new_bw = int(tot_net_bw*NODE_CAP)
 
 
-.. math::
-
-   bwn_i =& min\left(bwnew_i,
-              \sum_{i=1}^{n}bwnew_i \times 0.05\right) \
-
-         &= min\left(
-              \left(min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times r_i\right),
-                \sum_{i=1}^{n}\left(min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times r_i\right)
-                \times 0.05\right)\
-
-         &= min\left(
-              \left(min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times max\left(rf_i, rs_i\right)\right),
-                \sum_{i=1}^{n}\left(min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times
-                  max\left(rf_i, rs_i\right)\right) \times 0.05\right)\
-
-         &= min\left(
-              \left(min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times max\left(\frac{bwfilt_i}{bwfilt},
-                  \frac{bw_i}{bwstrm}\right)\right),
-                \sum_{i=1}^{n}\left(min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times
-                  max\left(\frac{bwfilt_i}{bwfilt},
-                    \frac{bw_i}{bwstrm}\right)\right) \times 0.05\right)
-
-.. math::
-
-      bwn_i = min\left(
-              \left(min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times max\left(\frac{bwfilt_i}{bwfilt},
-                  \frac{bw_i}{bwstrm}\right)\right),
-                \sum_{i=1}^{n}\left(min\left(bwobs_i, bwavg_i, bwburst_i, measuredconsensusbw_i \right) \times
-                  max\left(\frac{bwfilt_i}{bwfilt},
-                    \frac{bw_i}{bwstrm}\right)\right) \times 0.05\right)
-
-
-Per relay scaled bandwidth rounding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Round the scaled bandwidth for each relay
+-----------------------------------------
 
 Finally, the new scaled bandwidth is expressed in kilobytes and rounded a number
 of digits.





More information about the tor-commits mailing list