-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch16.rb
99 lines (76 loc) · 1.64 KB
/
ch16.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
require 'distribution'
require_relative './feedback'
include Distribution::Shorthand
class AbstractServerPool < Component
def initialize(n, server, incoming_load)
@n = n
@queue = 0
@server = server
@incoming_load = incoming_load
end
def work(u)
@n = [0, u.to_i]
completed = 0
@n.times do |_|
completed += @server.call
completed = @queue if completed >= @queue
end
@queue -= completed
completed
end
def monitoring
"#{@n} #{@queue}"
end
end
class QueueingServerPool < AbstractServerPool
def work(u)
incoming_load = @incoming_load
@queue += incoming_load
completed = super
incoming_load - completed
end
end
class InnerLoop < Component
def initialize(kp, ki, loader)
k = 0.01
@c = PIDController.new(kp * k, ki * k)
@p = QueueingServerPool.new(0, consume_queue, loader)
@y = 0
end
def work(u)
e = u - @y # u is setpoint from outer loop
e = -e # inverted dynamics
v = @c.work(e)
@y = @p.work(v) # y is net change
@p.queue
end
def monitoring
"#{@p.monitoring} #{@y}"
end
end
$global_time = 0
load_queue = -> {
$global_time += 1
case $global_time
when $global_time > 2500
norm_rng(mean: 1200, stddev: 5)
when $global_time > 2200
norm_rng(mean: 800, stddev: 5)
else
norm_rng(mean: 1000, stddev: 5)
end
}
setpoint = -> t {
case t
when t < 2000
100
when t < 3000
125
else
25
end
}
DT = 1
p = InnerLoop(0.5, 0.25, load_queue) # "plant" for outer loop
c = AdvancedController.new(0.35, 0.0025, 4.5, smooth = 0.15)
Feedback.closed_loop(setpoint, c, p, actuator = RecursiveFilter.new(0.5))