From d1e1da737fac7a1ef82ea0d1894d36b4c133e626 Mon Sep 17 00:00:00 2001 From: Jay Robson Date: Tue, 6 Feb 2024 01:08:44 +1100 Subject: [PATCH] pumps now work properly, even if they are very manual :) --- assets/model/primary_coolant_pump_switch.glb | 3 + assets/model/primary_coolant_pump_switch.stl | 3 + .../model/secondary_coolant_pump_switch.glb | 3 + .../model/secondary_coolant_pump_switch.stl | 3 + assets/scene-baked.glb | 4 +- assets/unbaked/scene.blend | 4 +- assets/unbaked/scene/labels.png | 4 +- assets/unbaked/scene/labels.xcf | Bin 81896 -> 140228 bytes src/coolant/fluid_holder.cpp | 6 +- src/coolant/pump.cpp | 37 +++--- src/coolant/pump.hpp | 7 +- src/coolant/valve.cpp | 2 +- src/graphics/monitor/core.cpp | 8 +- src/graphics/monitor/primary_loop.cpp | 33 +++++- src/graphics/monitor/primary_loop.hpp | 7 ++ src/reactor/coolant/vessel.cpp | 2 +- src/reactor/reactor.cpp | 2 +- src/system.cpp | 4 +- src/{ => util}/constants.hpp | 0 src/util/pid.cpp | 112 ++++++++++++++++++ src/util/pid.hpp | 44 +++++++ src/{ => util}/random.cpp | 0 src/{ => util}/random.hpp | 0 23 files changed, 247 insertions(+), 41 deletions(-) create mode 100644 assets/model/primary_coolant_pump_switch.glb create mode 100644 assets/model/primary_coolant_pump_switch.stl create mode 100644 assets/model/secondary_coolant_pump_switch.glb create mode 100644 assets/model/secondary_coolant_pump_switch.stl rename src/{ => util}/constants.hpp (100%) create mode 100644 src/util/pid.cpp create mode 100644 src/util/pid.hpp rename src/{ => util}/random.cpp (100%) rename src/{ => util}/random.hpp (100%) diff --git a/assets/model/primary_coolant_pump_switch.glb b/assets/model/primary_coolant_pump_switch.glb new file mode 100644 index 0000000..7ce8622 --- /dev/null +++ b/assets/model/primary_coolant_pump_switch.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4344c73249a535c6472aaa177e75ecd94daef875444e9216fa3d03d50a9c8b2b +size 2300 diff --git a/assets/model/primary_coolant_pump_switch.stl b/assets/model/primary_coolant_pump_switch.stl new file mode 100644 index 0000000..f8bead3 --- /dev/null +++ b/assets/model/primary_coolant_pump_switch.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:578b9844f451434d7439918972840abe9734e0e681a6714b4880994f221feda2 +size 1384 diff --git a/assets/model/secondary_coolant_pump_switch.glb b/assets/model/secondary_coolant_pump_switch.glb new file mode 100644 index 0000000..217e781 --- /dev/null +++ b/assets/model/secondary_coolant_pump_switch.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3b78531b28fd2aa3a4187910a9d3e12589ce90bf618f1c6a06ba9dd87289eea4 +size 2304 diff --git a/assets/model/secondary_coolant_pump_switch.stl b/assets/model/secondary_coolant_pump_switch.stl new file mode 100644 index 0000000..bbee054 --- /dev/null +++ b/assets/model/secondary_coolant_pump_switch.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08cb689a2e9589f2cf900dda401a4050c4a7ca0df9dec993fb0b95194cf44152 +size 1384 diff --git a/assets/scene-baked.glb b/assets/scene-baked.glb index 5264c0c..f179956 100644 --- a/assets/scene-baked.glb +++ b/assets/scene-baked.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ed870c17367c0bb8858bb68fbc5277f56e47c3ffa650591b11d703e3052da9f -size 59404508 +oid sha256:28b515def72bcb7c1fb46ca68443b510565e9538032fd9320016953154f902f9 +size 59501212 diff --git a/assets/unbaked/scene.blend b/assets/unbaked/scene.blend index 2334421..cabd2ba 100644 --- a/assets/unbaked/scene.blend +++ b/assets/unbaked/scene.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ba3be1ad135735ed6ac111c2229004e8eb7d2d9442a873a5f49bd4cbc905f40 -size 10146216 +oid sha256:617293315153b7993db7beeaba58d2c30e5fc77e75b1d2447907541070357320 +size 12058488 diff --git a/assets/unbaked/scene/labels.png b/assets/unbaked/scene/labels.png index 7ae9d7b..3e2cb14 100644 --- a/assets/unbaked/scene/labels.png +++ b/assets/unbaked/scene/labels.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22b0bcb35c11d4da7718d85136baadbc5801d9823661e1feecd8851d384ef290 -size 26579 +oid sha256:9387fc6ea27299ea12fcc2b27240e9443c168989d5a642740567a4a4b5680745 +size 48112 diff --git a/assets/unbaked/scene/labels.xcf b/assets/unbaked/scene/labels.xcf index c6d49ea5332690df3998d99c43ebcf1837d162c2..7f87dd0c3cd016da842e8de7d8cfbd2d6d2a47e5 100644 GIT binary patch literal 140228 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 wC)e}z+OO6JwJ}f|1GOo+Clk<`H~;_u delta 4959 zcmYk;aY!C@9LMpy`P6*!iHy0;+g#J>n$NaE@>zRsI=7mU5BY}!TOK(uGVmcQVL~2_ z&W#QBkOPUqc5TooAs;euP0%YN|B&(_A^#Ba$YPO@4;iyE@W{>Xp6`33gZsUH-_P%N zKF@RB@AyrAo4>do>VH<ldM?BrmKJOM}1RA7wGD$7WGcth}?z`rX3yCzPAbp+h@L zl#D+TT&4Qw#%Im0S5BP@=5FxM%Wb#S{?WS+sOMEnDgQi(IqqG=*De29@)JMculFYU z-ka-pE1r}*_Jw$iuX+4UshfjO^^X^A@x<5o{YL31pWJyw4UL8)>YXY}F%FRWs2};w z|L&lXl(CT?@i+Wi4BGqG_JJ z-RM_`)jv<>DWgAKzHwF6wkunD+(G!a`)X_i_?cn$Occ9q847!*_Pt?Mw zVH9;tpn*v=F@-i-X*v#O(8Vlz;%TNj;9v$_%%Ufjg;B#O z>X<+SlW1ZJZPtHTn!rI9J#m+YIvQxAjSjl#iRBvVXrRgZFSiLC%%F=|^u&rVY8XWw z6KG%(O-!L>(@CR)8FVp=p13=V8b(pa1R9t`6H}tK+a^e(gD!gF;~MH{poum*=%Od? z(NIStr={*O32byQgDzDz~0VH9;tpn*v=F%{^q|4N%6jSgne#VmSaG>jTXQAYz! zw9!G=_hEniM?DGlYNHod)!{99>b}n0<{+9U1N#QWBV#y;GdO>LFHy~uYNk{(rFveb zRxjd;$nH^%MW|(urp79$tFRUuuo>I1lXpq1hu|Fc<2B^B#73wma2n@u0he)2Jdlq? zSc?03mmG)_)MFF2Vh46(FZSUT9Kc~5$0?k}Te!r#3O; zPvZr=gxAp;qBDk*ID_-Jh%4g39Ey4{LS2j%ScSFNfX&z@S_eA`dhi_f<24+_5uCtj zoWliN#x*gXk40FT(^BL63F26fP1uSZ*p0o|hgWa_hjARIa29U``tOqX62Ypdhp-S! zuo7c<6dSPx+p!Bz;|08g*L{P%gg!(thLbph^SFpB;-MUhdMH9&j1^dgwb+2o*v9%l z)Jf2T=dd5I;UJFS1Ww}|F5oh*i8c9Hgr%(in*9WEtj8v7#SZMoUhKmwIDo@Aj#D^` zw^;u*O9ZQ8Z3qjo1S>IyN3juGupPVbG+w|gkv~~GdPcnxFR0Tp{R!=)WukV zRalD+*eqIy+Xy1xuo7c<6dSPx+p!Bz;|09r8|)>HTqhVB?c2H` G9{CSorsos@ diff --git a/src/coolant/fluid_holder.cpp b/src/coolant/fluid_holder.cpp index 145aab1..e58454f 100644 --- a/src/coolant/fluid_holder.cpp +++ b/src/coolant/fluid_holder.cpp @@ -1,6 +1,6 @@ #include "fluid_holder.hpp" -#include "../constants.hpp" +#include "../util/constants.hpp" #include "../conversions/temperature.hpp" #include "../reactor/fuel/half_life.hpp" @@ -86,7 +86,7 @@ double fluid_holder::get_pressure() const if(V == 0) { - return NAN; + return 0; } return (n * T * constants::R) / V; @@ -95,7 +95,7 @@ double fluid_holder::get_pressure() const double fluid_holder::get_steam_density() const { double v = get_steam_volume(); - return v > 0 ? steam / v : NAN; + return v > 0 ? steam / v : 0; } void fluid_holder::update(double secs) diff --git a/src/coolant/pump.cpp b/src/coolant/pump.cpp index 8e92414..8291b94 100644 --- a/src/coolant/pump.cpp +++ b/src/coolant/pump.cpp @@ -6,15 +6,20 @@ using namespace sim::coolant; -pump::pump(fluid_holder* src, fluid_holder* dst, double mass, double radius, double l_per_rev, double friction) : +pump::pump(fluid_holder* src, fluid_holder* dst, double mass, double radius, double power, double l_per_rev, double friction) : src(src), dst(dst), mass(mass), radius(radius), l_per_rev(l_per_rev), friction(friction) { - power = 1e8; + this->power = power; } double pump::get_flow() const { - return src->fluid.l_to_g(l_per_rev * get_rpm() / 60); + return l_per_rev * get_rpm() * 60; +} + +double pump::get_flow_mass() const +{ + return src->fluid.l_to_g(get_flow()); } double pump::get_rpm() const @@ -56,40 +61,38 @@ static double calc_work(double j, double mass) void pump::update(double dt) { + idling = false; + if(powered && !idling) { velocity += calc_work(dt * power, mass); } + fluid_holder fh_src(*src); + fluid_holder fh_dst(*dst); + double src_heat = src->get_heat(); double p_diff_1 = dst->get_pressure() - src->get_pressure(); - double src_volume = src->extract_fluid(get_flow() * dt); - double dst_volume = dst->add_fluid(src_volume, src_heat); + double src_volume = fh_src.extract_fluid(get_flow() * dt); + double dst_volume = fh_dst.add_fluid(src_volume, src_heat); - if(dst_volume < src_volume) - { - src->add_fluid(src_volume - dst_volume, src_heat); - } + src->extract_fluid(dst_volume); + dst->add_fluid(dst_volume, src_heat); double p_diff_2 = dst->get_pressure() - src->get_pressure(); double p_diff = (p_diff_1 + p_diff_2) / 2; - double work = p_diff * dst_volume + get_rpm() * 60 * dt * friction; + double work = p_diff * dst_volume * 0.001 + get_rpm() * 60 * dt * friction; velocity -= calc_work(work, mass); if(dst->get_level() > 400 || src->get_level() < 10) { - idling = true; +// idling = true; } else { - idling = false; +// idling = false; } - - std::cout << "RPM: " << get_rpm() << "\t"; - std::cout << "Flow: " << get_flow() << std::endl; - std::cout << "Work Done: " << work << " J\n"; - std::cout << "Src Volume: " << src_volume << "\n"; } diff --git a/src/coolant/pump.hpp b/src/coolant/pump.hpp index 526d8af..30fda18 100644 --- a/src/coolant/pump.hpp +++ b/src/coolant/pump.hpp @@ -21,12 +21,13 @@ class pump public: - bool powered = true; + bool powered = false; bool idling = false; - pump(fluid_holder* src, fluid_holder* dst, double mass, double radius, double l_per_rev, double friction); + pump(fluid_holder* src, fluid_holder* dst, double mass, double radius, double power, double l_per_rev, double friction); - double get_flow() const; // g/s + double get_flow() const; // L/s + double get_flow_mass() const; // g/s double get_rpm() const; // rev/min const char* get_state_string(); diff --git a/src/coolant/valve.cpp b/src/coolant/valve.cpp index ee793ea..53cb9a9 100644 --- a/src/coolant/valve.cpp +++ b/src/coolant/valve.cpp @@ -1,7 +1,7 @@ #include "valve.hpp" #include "../conversions/temperature.hpp" -#include "../constants.hpp" +#include "../util/constants.hpp" #include #include diff --git a/src/graphics/monitor/core.cpp b/src/graphics/monitor/core.cpp index 12054b1..1cbe0a1 100644 --- a/src/graphics/monitor/core.cpp +++ b/src/graphics/monitor/core.cpp @@ -73,16 +73,14 @@ struct core_monitor : public focus::focus_t struct core_joystick : public focus::focus_t { - double ypos = 0; - virtual void on_cursor_pos(double x, double y) { - ypos += y; + sim::system::active.reactor->add_rod_speed(y * 1e-6); } - virtual void update(double dt) + virtual ~core_joystick() { - sim::system::active.reactor->add_rod_speed(ypos * dt * 1e-6); + sim::system::active.reactor->reset_rod_speed(); } virtual void on_mouse_button(int button, int action, int mods) diff --git a/src/graphics/monitor/primary_loop.cpp b/src/graphics/monitor/primary_loop.cpp index 8b36649..961eb8b 100644 --- a/src/graphics/monitor/primary_loop.cpp +++ b/src/graphics/monitor/primary_loop.cpp @@ -54,6 +54,15 @@ primary_loop::primary_loop() } +void primary_loop::toggle_primary_pump() +{ + system& sys = sim::system::active; + bool state; + + sys.primary_pump->powered = state = !sys.primary_pump->powered; + gm_switch_primary.model_matrix = glm::translate(glm::mat4(1), glm::vec3(0, state ? 0.07 : 0, 0)); +} + void primary_loop::init() { mesh1.model_matrix = locations::monitors[3]; @@ -85,8 +94,18 @@ void primary_loop::init() mesh1.bind(); mesh1.set(rmesh, GL_STATIC_DRAW); + rmesh.load_model("../assets/model", "primary_coolant_pump_switch.glb"); + gm_switch_primary.bind(); + gm_switch_primary.set(rmesh, GL_STATIC_DRAW); + + rmesh.load_model("../assets/model", "secondary_coolant_pump_switch.glb"); + gm_switch_secondary.bind(); + gm_switch_secondary.set(rmesh, GL_STATIC_DRAW); + m_joystick_turbine_bypass.load_model("../assets/model", "turbine_valve_bypass_joystick.stl"); m_joystick_turbine_inlet.load_model("../assets/model", "turbine_valve_inlet_joystick.stl"); + m_switch_primary.load_model("../assets/model", "primary_coolant_pump_switch.stl"); + m_switch_secondary.load_model("../assets/model", "secondary_coolant_pump_switch.stl"); } void primary_loop::update() @@ -104,7 +123,7 @@ void primary_loop::update() ss << "\n\n\n"; ss << sys.primary_pump->get_state_string() << "\n"; ss << show( sys.primary_pump->get_rpm() ) << " r/min\n"; - ss << show( sys.primary_pump->get_flow() / 1000 ) << " kg/s\n"; + ss << show( sys.primary_pump->get_flow_mass() / 1000 ) << " kg/s\n"; ss << "\n\n\n"; ss << show( sys.condenser->get_heat() ) << " C\n"; ss << show( sys.condenser->get_steam() ) << " g\n"; @@ -114,11 +133,13 @@ void primary_loop::update() rmesh.load_text(ss.str().c_str(), 0.04); mesh2.bind(); mesh2.set(rmesh, GL_DYNAMIC_DRAW); - + if(m_joystick_turbine_bypass.check_focus()) focus::set(std::make_unique(sys.turbine_bypass_valve.get())); if(m_joystick_turbine_inlet.check_focus()) focus::set(std::make_unique(sys.turbine_inlet_valve.get())); + if(m_switch_primary.check_focus()) + toggle_primary_pump(); } void primary_loop::render() @@ -130,5 +151,13 @@ void primary_loop::render() mesh2.bind(); mesh2.uniform(); mesh2.render(); + + gm_switch_primary.bind(); + gm_switch_primary.uniform(); + gm_switch_primary.render(); + + gm_switch_secondary.bind(); + gm_switch_secondary.uniform(); + gm_switch_secondary.render(); } diff --git a/src/graphics/monitor/primary_loop.hpp b/src/graphics/monitor/primary_loop.hpp index 5982126..eb56eab 100644 --- a/src/graphics/monitor/primary_loop.hpp +++ b/src/graphics/monitor/primary_loop.hpp @@ -9,9 +9,16 @@ namespace sim::graphics::monitor class primary_loop { sim::graphics::glmesh mesh1, mesh2; + + sim::graphics::glmesh gm_switch_primary; + sim::graphics::glmesh gm_switch_secondary; sim::graphics::mesh m_joystick_turbine_bypass; sim::graphics::mesh m_joystick_turbine_inlet; + sim::graphics::mesh m_switch_primary; + sim::graphics::mesh m_switch_secondary; + + void toggle_primary_pump(); public: diff --git a/src/reactor/coolant/vessel.cpp b/src/reactor/coolant/vessel.cpp index 494baf5..a3dcc96 100644 --- a/src/reactor/coolant/vessel.cpp +++ b/src/reactor/coolant/vessel.cpp @@ -1,6 +1,6 @@ #include "vessel.hpp" -#include "../../constants.hpp" +#include "../../util/constants.hpp" #include "../../conversions/temperature.hpp" #include "../fuel/half_life.hpp" diff --git a/src/reactor/reactor.cpp b/src/reactor/reactor.cpp index ced8e84..db5448c 100644 --- a/src/reactor/reactor.cpp +++ b/src/reactor/reactor.cpp @@ -1,6 +1,6 @@ #include "reactor.hpp" -#include "../random.hpp" +#include "../util/random.hpp" #include diff --git a/src/system.cpp b/src/system.cpp index 215a535..0805a3f 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -37,12 +37,12 @@ system::system() vessel = std::make_unique(sim::coolant::WATER, 8, 10, 6e6, 300); reactor = std::make_unique(sim::reactor::builder(19, 19, 1.0 / 4.0, 4, reactor::fuel::fuel_rod(0.5), vessel.get(), layout)); - condenser = std::make_unique(sim::coolant::WATER, 8, 6, 3e6, 0); + condenser = std::make_unique(sim::coolant::WATER, 8, 6, 3e6, 200); turbine = std::make_unique(sim::coolant::WATER, condenser.get(), 6, 3, 2e6); turbine_inlet_valve = std::make_unique(vessel.get(), turbine.get(), 0, 1e-2); turbine_bypass_valve = std::make_unique(vessel.get(), condenser.get(), 0, 1e-2); - primary_pump = std::make_unique(condenser.get(), vessel.get(), 1e6, 1, 1, 0); + primary_pump = std::make_unique(condenser.get(), vessel.get(), 1e6, 1, 1e6, 1, 10); } system::system(system&& o) diff --git a/src/constants.hpp b/src/util/constants.hpp similarity index 100% rename from src/constants.hpp rename to src/util/constants.hpp diff --git a/src/util/pid.cpp b/src/util/pid.cpp new file mode 100644 index 0000000..a5b9ca8 --- /dev/null +++ b/src/util/pid.cpp @@ -0,0 +1,112 @@ +/** + * Copyright 2019 Bradley J. Snyder + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "pid.hpp" + +using namespace std; + +class PIDImpl +{ + public: + PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki ); + ~PIDImpl(); + double calculate( double setpoint, double pv ); + + private: + double _dt; + double _max; + double _min; + double _Kp; + double _Kd; + double _Ki; + double _pre_error; + double _integral; +}; + + +PID::PID( double dt, double max, double min, double Kp, double Kd, double Ki ) +{ + pimpl = new PIDImpl(dt,max,min,Kp,Kd,Ki); +} +double PID::calculate( double setpoint, double pv ) +{ + return pimpl->calculate(setpoint,pv); +} +PID::~PID() +{ + delete pimpl; +} + + +/** + * Implementation + */ +PIDImpl::PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki ) : + _dt(dt), + _max(max), + _min(min), + _Kp(Kp), + _Kd(Kd), + _Ki(Ki), + _pre_error(0), + _integral(0) +{ +} + +double PIDImpl::calculate( double setpoint, double pv ) +{ + + // Calculate error + double error = setpoint - pv; + + // Proportional term + double Pout = _Kp * error; + + // Integral term + _integral += error * _dt; + double Iout = _Ki * _integral; + + // Derivative term + double derivative = (error - _pre_error) / _dt; + double Dout = _Kd * derivative; + + // Calculate total output + double output = Pout + Iout + Dout; + + // Restrict to max/min + if( output > _max ) + output = _max; + else if( output < _min ) + output = _min; + + // Save error to previous error + _pre_error = error; + + return output; +} + +PIDImpl::~PIDImpl() +{ +} + diff --git a/src/util/pid.hpp b/src/util/pid.hpp new file mode 100644 index 0000000..c537f20 --- /dev/null +++ b/src/util/pid.hpp @@ -0,0 +1,44 @@ +/** + * Copyright 2019 Bradley J. Snyder + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +class PIDImpl; +class PID +{ + public: + // Kp - proportional gain + // Ki - Integral gain + // Kd - derivative gain + // dt - loop interval time + // max - maximum value of manipulated variable + // min - minimum value of manipulated variable + PID( double dt, double max, double min, double Kp, double Kd, double Ki ); + + // Returns the manipulated variable given a setpoint and current process value + double calculate( double setpoint, double pv ); + ~PID(); + + private: + PIDImpl *pimpl; +}; + diff --git a/src/random.cpp b/src/util/random.cpp similarity index 100% rename from src/random.cpp rename to src/util/random.cpp diff --git a/src/random.hpp b/src/util/random.hpp similarity index 100% rename from src/random.hpp rename to src/util/random.hpp