diff --git a/src/doubletank.jl b/src/doubletank.jl index 9637d60692c147199ca46cd4abaf6501858ff03f..64225df696abbd4f1c981c06092b20ca054bfeae 100644 --- a/src/doubletank.jl +++ b/src/doubletank.jl @@ -31,8 +31,10 @@ function (p::PID)(r, y, onv=(1,1,1)) bd = N*K*Td/(N*h+Td) Tot = 0.0 - P = K*(b*r-y) + P = 0 + D = 0 if onv[1]==1 + P = K*(b*r-y) Tot += P end if onv[3]==1 @@ -46,6 +48,8 @@ function (p::PID)(r, y, onv=(1,1,1)) I += Ichange end Tot += I + else + I = 0 end y_old = y @pack! p = P, I, D, Tot, y_old @@ -77,14 +81,14 @@ function qu(p, u) u*p.α end -function control(p::DoubleTankSimulator, u::Number) +function control(p::DoubleTankSimulator, u::Number, load::Number, flow::Bool) @unpack a1, a2, g, x, A, h, scale = p x *= scale #The simulator should operate on physical values but u should be in [0,1] - u = clamp(u, inputrange(p)[1]...) + u = clamp(u, inputrange(p)[1]...) + load - qut = a1*sqrt(2*g*x[1]) #m^3/s + qut = flow ? a1*sqrt(2*g*x[1]) : 0 #m^3/s dA1 = qu(p,u) - qut #m^3/s if -dA1*h>x[1]*A @@ -95,7 +99,7 @@ function control(p::DoubleTankSimulator, u::Number) end dA2 = qut - a2*sqrt(2*g*x[2]) #m^3/s - if(-dA2*h>x[2]*A) + if -dA2*h>x[2]*A dA2 = -x[2]*A/h end x[1] += (dA1*h)/A diff --git a/src/tankdemo.jl b/src/tankdemo.jl index 113ec301209f0035f0fab0138996adba3f634e4d..9ad96608d03611ce84c0a386178f6b75098ad835 100644 --- a/src/tankdemo.jl +++ b/src/tankdemo.jl @@ -24,12 +24,14 @@ function runsimulation(;simulated=true, webservice=true, port=8000, σ = 0.001, n = 2 end onv = Int.([gui[s]=="On" for s in [:pOn, :iOn, :dOn]]) + load = gui[:load]=="Upper" ? 0.1 : 0 + flow = gui[:flow]=="None" rv = pidcontroller(r, y, onv) if gui[:mode]=="Automatic" gui[:u] = clamp(round(rv,digits=2), 0, 1) #u's constructor has only a dummy graphic so this is fine - control(P, rv) + control(P, rv, load, flow) elseif gui[:mode]=="Manual" - control(P, gui[:u]) + control(P, gui[:u], load, flow) #bumpless transfer: if gui[:iOn]=="On" pidcontroller.I = gui[:u]-(pidcontroller.Tot-pidcontroller.I) diff --git a/src/tankgraphic.jl b/src/tankgraphic.jl index c6ee8176fc89d0d38041c2f4e178123b787a48be..d139abbf56c76afe158f01faafa8912231dcc4d3 100644 --- a/src/tankgraphic.jl +++ b/src/tankgraphic.jl @@ -54,7 +54,7 @@ function water_container(width, height, fill, x=0, y=0) end -function tank_construct(upper, lower, pump_speed = 1, tnum = 0, r = -1) +function tank_construct(upper, lower, pump_speed = 1, tnum = 0, r = -1, load = 0, blocked = false) height = 250 width = 200 @@ -86,8 +86,9 @@ function tank_construct(upper, lower, pump_speed = 1, tnum = 0, r = -1) w1 = mouth_width*sqrt(max(0,pump_speed)) - w2 = mouth_width*sqrt(max(0, upper)) + w2 = blocked ? 0 : mouth_width*sqrt(max(0, upper)) w3 = mouth_width*sqrt(max(0, lower)) + w4 = mouth_width*sqrt(max(0, load)) container1 = water_container(width, height, upper, upper_x, upper_y) container2 = water_container(width, height, lower, lower_x, lower_y) @@ -98,6 +99,7 @@ function tank_construct(upper, lower, pump_speed = 1, tnum = 0, r = -1) stream(w1, height+50, upper_x+(width-w1)/2, 50)..., stream(w2, height+50, upper_x+(width-w2)/2, height+100)..., stream(w3, 100, upper_x+(width-w3)/2, 2*height+150)..., + stream(w4, height, upper_x, 100)..., container1, container2, redarrow, svg_rect(tank_width, tank_height, tank_x, tank_y), pipe, diff --git a/src/tanklabgui.jl b/src/tanklabgui.jl index b242fc57bc36e35d95c17f15112a960e264a6981..2169bc0b1f4a7b8e4778cea9df23d740efdff761 100644 --- a/src/tanklabgui.jl +++ b/src/tanklabgui.jl @@ -10,6 +10,7 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) maxplotlength = 800 gui = GUI() ptfr = 3.8 #pump to flow ratio, approximate + plotfreeze = -1 """ @@ -35,6 +36,9 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) pOn in togglebuttons(["On", "Off"], label="P"), iOn in togglebuttons(["On", "Off"], label="I"), dOn in togglebuttons(["On", "Off"], label="D"), + load in togglebuttons(["None", "Upper"], label="load disturbance"), + flow in togglebuttons(["None", "Upper"], label="stop outflow "), + freeze in togglebuttons(["On", "Freeze"], label="plots "), #expcsv in button("Export Data"), rbox in textbox("0.5", label="r") @@ -48,7 +52,7 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) rv = parse(Float64, rbox) catch end - if 0.0<rv<1.0 + if 0.0<=rv<=1.0 observe(r).val = rv end end @@ -60,11 +64,11 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) if observe(tankno)[] == "Upper" - tankg = tank_construct(measure(P)..., observe(u)[]*ptfr, 1, observe(r).val) + tankg = tank_construct(measure(P)..., observe(u)[]*ptfr, 1, observe(r).val, + observe(load)[] == "Upper" ? 0.1*ptfr : 0, observe(flow)[] == "Upper") elseif observe(tankno)[] == "Lower" - tankg = tank_construct(measure(P)..., observe(u)[]*ptfr, 2, observe(r).val) - else - tankg = tank_construct(measure(P)..., observe(u)[]*ptfr) + tankg = tank_construct(measure(P)..., observe(u)[]*ptfr, 2, observe(r).val, + observe(load)[] == "Upper" ? 0.1*ptfr : 0, observe(flow)[] == "Upper") end Node(:div, tankg, id="tanks", attributes=tankattr) end @@ -73,7 +77,7 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) w2, graphic2 = @construct for plotdummy in checkbox(false, label="This button does nothing") - dataln = length(gui.data[1]) + dataln = plotfreeze == -1 ? length(gui.data[1]) : plotfreeze if dataln > maxplotlength start = dataln - maxplotlength else @@ -81,12 +85,12 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) end lnv = glnv[1:min(dataln, maxplotlength+1)] p = plot(layout=(2,1), size=(700, 600), xlabel="seconds") - plot!(p[1], lnv, gui.data[1][start:end], label="y", ylim=boundsupper) - plot!(p[1], lnv, gui.data[2][start:end], label="r") - plot!(p[2], lnv, gui.data[3][start:end], label="P", ylim=boundslower) - plot!(p[2], lnv, gui.data[4][start:end], label="I") - plot!(p[2], lnv, gui.data[5][start:end], label="D") - plot!(p[2], lnv, gui.data[6][start:end], label="Tot", color=:black) + plot!(p[1], lnv, gui.data[1][start:dataln], label="y", ylim=boundsupper) + plot!(p[1], lnv, gui.data[2][start:dataln], label="r") + plot!(p[2], lnv, gui.data[3][start:dataln], label="P", ylim=boundslower) + plot!(p[2], lnv, gui.data[4][start:dataln], label="I") + plot!(p[2], lnv, gui.data[5][start:dataln], label="D") + plot!(p[2], lnv, gui.data[6][start:dataln], label="Tot", color=:black) end @async run_process(P, gui, tankpid) @@ -97,6 +101,14 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) end end + on(observe(freeze)) do val + if val=="On" + plotfreeze = -1 + else + plotfreeze = length(gui.data[1]) + end + end + on(observe(iOn)) do val if val=="Off" tankpid.I = 0 @@ -110,7 +122,7 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) add!(gui, w2) layout = make_grid([100], [50, 25, 25]) - settings_element = make_grid(7,1) + settings_element = make_grid(10,1) p_element = make_grid(2, 1) p_element = setindex_(p_element, dom"div[display=inline-block]"(gui.widgets[:pOn]), 1, 1) @@ -131,6 +143,9 @@ function makegui(P, run_process, plottingframerate = 10, guiframerate = 10) settings_element = setindex_(settings_element, p_element, 5, 1) settings_element = setindex_(settings_element, i_element, 6, 1) settings_element = setindex_(settings_element, d_element, 7, 1) + settings_element = setindex_(settings_element, dom"div"(gui.widgets[:load]), 8, 1) + settings_element = setindex_(settings_element, dom"div"(gui.widgets[:flow]), 9, 1) + settings_element = setindex_(settings_element, dom"div"(gui.widgets[:freeze]), 10, 1) layout = setindex_(layout, graphic2, 1, 1) layout = setindex_(layout, Node(:div, graphic1, dummygraphic1, dummygraphic2,