1@startuml
2title "Torflow measurements scaling with PID control (Per relay scaled bandwidth)."
3
4' Own previous bwfile
5:prev_votes = VoteSet();
6note right
7initialize measurements from previous Bandwidth File
8end note
9:tot_net_bw = 0;
10:;
11note right
12    for every measurement
13end note
14while (for n in nodes.itervalues()?)
15    partition "Intialize ratios and pid_error" {
16        ' Anything not set is initialized to 0 or None
17        :n.fbw_ratio = n.filt_bw/true_filt_avg[n.node_class()];
18        :n.sbw_ratio = n.strm_bw/true_strm_avg[n.node_class()];
19        :n.use_bw = n.desc_bw;
20        :n.pid_error = max(bwstrm_i / bwstrm, bwfilt_i / bwfilt) - 1;
21        note right
22            if n.sbw_ratio > n.fbw_ratio:
23            #assert cs_junk.use_best_ratio == True
24            n.pid_error = (n.strm_bw - true_strm_avg[n.node_class()])
25                                / true_strm_avg[n.node_class()]
26            else:
27            n.pid_error = (n.filt_bw - true_filt_avg[n.node_class()])
28                                / true_filt_avg[n.node_class()]
29            0 <= n.pid_error <= 500.0
30        end note
31    }
32    if (n.idhex in prev_votes.vote_map?) then (yes)
33        :;
34        note right
35        if n.measured_at >
36        prev_votes.vote_map[n.idhex].measured_at;
37        end note
38        if (measurement newer?) then (yes)
39            :;
40            note right
41            if n.idhex in prev_consensus
42                and ("Guard" in prev_consensus[n.idhex].flags=
43            end note
44            if (in prev_consensus, \nis guard?) then (yes)
45                :;
46                note right
47                if n.idhex not in prev_votes.vote_map
48                    or n.measured_at - prev_votes.vote_map[n.idhex].measured_at
49                        > cs_junk.guard_sample_rate:
50                        # cs_jung.guard_sample_rate = 2*7*24*60*60 # 2wks
51                end note
52                if (not exit diff NOT bigger than 2 weeks) then (yes)
53                    :;
54                    note right
55                    \# Use new measurement but not feedback
56                    n.copy_vote(prev_vote.vote_map[n.idhex]));
57                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
58                                cs_junk.K_p,
59                                cs_junk.K_i,
60                                cs_junk.K_d,
61                                0.0, False)
62                    end note
63                    :\# self.new_bw = vote.bw * 1000
64                    self.pid_bw = vote.pid_bw
65                    self.pid_error_sum = vote.pid_error_sum
66                    self.pid_delta = vote.pid_delta
67
68                    n.new_bw = self.use_bw + self.use_bw * self_pid_error
69
70                    n.measured_at = prev_vote.measured_at
71                    n.pid_error = prev_vote.pid_error;
72                else (no)
73                    :;
74                    note right
75                    # full feedback
76                    n.new_bw = n.get_pid_bw(prev_votes.vote_map[n.idhex],
77                                    cs_junk.K_p,
78                                    cs_junk.K_i,
79                                    cs_junk.K_d,
80                                    cs_junk.K_i_decay)
81                        = n.get_pid_bw(prev_votes.vote_map[n.idhex],
82                                       1.0, 0, 0, 0)
83                    end note
84                    :self.prev_error = prev_vote.pid_error
85                    self.pid_bw = self.use_bw
86                        + self.use_bw * self.pid_error
87                        # + self.desc_bw * self.pid_error
88                    self.pid_error_sum = 0 + self.pid_error
89                    n.new_bw = self.pid_bw;
90                endif
91            endif
92        ' No new measurement (in prev bwfile, but havent check consensus), do not vote this round
93        else (no)
94            :;
95            note right
96            \# Reset values. Don't vote/sample this measurement round.
97            \# is in the previous bwfile, but haven't check the consensus
98            n.revert_to_vote(prev_votes.vote_map[n.idhex])
99            \# which calls again self.copy_vote(vote)
100            end note
101            :self.new_bw = prev_vote.bw*1000
102            self.pid_bw = prev_vote.pid_bw
103            self.pid_error_sum = prev_vote.pid_error_sum
104            self.pid_delta = prev_vote.pid_delta
105
106            self.pid_error = vote.pid_error
107            self.measured_at = vote.measured_at;
108
109        endif
110    ' Not in previous bwfile, usually only with authoritites, possibly not in conensus?
111    else (no)
112        ' :n.new_bw = n.use_bw + cs_junk.K_p*n.use_bw*n.pid_error = \n
113        :n.new_bw = n.use_bw + n.use_bw * n.pid_error
114        n.pid_error_sum = n.pid_error
115        n.pid_bw = n.new_bw;
116    endif
117    ' :n.change = n.new_bw - n.desc_bw;
118
119    ' For capping later
120    if (n.idhex in prev_consensus) then (yes)
121        if (prev_consensus[n.idhex].bandwidth != None) then (yes)
122            :prev_consensus[n.idhex].measured = True;
123            :tot_net_bw += n.new_bw;
124        endif
125    endif
126endwhile
127while (for n in nodes.itervalues()?)
128    :cap...;
129endwhile
130stop
131
132@enduml
133