diff --git a/js/pid_controller.js b/js/pid_controller.js
new file mode 100644
index 00000000..780a43f8
--- /dev/null
+++ b/js/pid_controller.js
@@ -0,0 +1,129 @@
+'use strict';
+
+var classes = classes || {};
+
+classes.PidController = function () {
+
+ var self = {},
+ privateScope = {};
+
+ /**
+ *
+ * @type {number}
+ */
+ privateScope.target = null;
+
+ /**
+ *
+ * @type {{P: null, I: null, D: null}}
+ */
+ privateScope.gains = {
+ P: null,
+ I: null,
+ D: null
+ };
+
+ /**
+ *
+ * @type {number}
+ */
+ privateScope.Iterm = 0;
+
+ /**
+ *
+ * @type {{min: number, max: number}}
+ */
+ privateScope.ItermLimit = {
+ min: -1000,
+ max: 1000
+ };
+
+ /**
+ *
+ * @type {number}
+ */
+ privateScope.previousError = 0;
+
+ /**
+ *
+ * @type {{min: number, max: number, minThreshold: number}}
+ */
+ privateScope.output = {
+ min: null,
+ max: null,
+ minThreshold: null
+ };
+
+ /**
+ *
+ * @param {number} value
+ */
+ self.setTarget = function (value) {
+ privateScope.target = value;
+ };
+
+ /**
+ * @param {number} Pgain
+ * @param {number} Igain
+ * @param {number} Dgain
+ */
+ self.setGains = function (Pgain, Igain, Dgain) {
+ privateScope.gains.P = Pgain;
+ privateScope.gains.I = Igain;
+ privateScope.gains.D = Dgain;
+ };
+
+ /**
+ * Sets min and max value for output
+ * @param {number} min
+ * @param {number} max
+ * @param {number} minThreshold if output is below this value, [min] is returned
+ */
+ self.setOutput = function (min, max, minThreshold) {
+ privateScope.output.min = min;
+ privateScope.output.max = max;
+ privateScope.output.minThreshold = minThreshold;
+ };
+
+ /**
+ * Sets upper and lower limit for Iterm accumulator
+ * @param {number} min
+ * @param {number} max
+ */
+ self.setItermLimit = function (min, max) {
+ privateScope.ItermLimit.min = min;
+ privateScope.ItermLimit.max = max;
+ };
+
+ /**
+ * Executes PID controller based on current value and target
+ * @param {number} current
+ * @returns {number}
+ */
+ self.run = function (current) {
+ var error = current - privateScope.target,
+ Pterm = error * privateScope.gains.P,
+ Dterm = (error - privateScope.previousError) * privateScope.gains.D,
+ output;
+
+ privateScope.previousError = error;
+
+ privateScope.Iterm += error * privateScope.gains.I;
+ if (privateScope.Iterm > privateScope.ItermLimit.max) {
+ privateScope.Iterm = privateScope.ItermLimit.max;
+ } else if (privateScope.Iterm < privateScope.ItermLimit.min) {
+ privateScope.Iterm = privateScope.ItermLimit.min;
+ }
+
+ output = Pterm + privateScope.Iterm + Dterm;
+ if (output < privateScope.output.minThreshold) {
+ output = privateScope.output.min;
+ } else if (output > privateScope.output.max) {
+ output = privateScope.output.max;
+ }
+
+ return output;
+ };
+
+ return self;
+};
\ No newline at end of file
diff --git a/js/serial_queue.js b/js/serial_queue.js
index 15dbd290..19121dd5 100644
--- a/js/serial_queue.js
+++ b/js/serial_queue.js
@@ -19,46 +19,20 @@ helper.mspQueue = (function (serial, MSP) {
privateScope.currentLoad = 0;
- privateScope.loadPid = {
- gains: {
- P: 10,
- I: 4,
- D: 2
- },
- Iterm: 0,
- ItermLimit: 85,
- previousError: 0,
- output: {
- min: 0,
- max: 97,
- minThreshold: 0
- }
- };
+ /**
+ * PID controller used to perform throttling
+ * @type {classes.PidController}
+ */
+ privateScope.loadPidController = new classes.PidController();
+ privateScope.loadPidController.setTarget(privateScope.targetLoad);
+ privateScope.loadPidController.setOutput(0, 97, 0);
+ privateScope.loadPidController.setGains(16, 6, 4);
+ privateScope.loadPidController.setItermLimit(0, 90);
privateScope.dropRatio = 0;
publicScope.computeDropRatio = function () {
- var error = privateScope.currentLoad - privateScope.targetLoad;
-
- var Pterm = error * privateScope.loadPid.gains.P,
- Dterm = (error - privateScope.loadPid.previousError) * privateScope.loadPid.gains.D;
-
- privateScope.loadPid.previousError = error;
-
- privateScope.loadPid.Iterm += error * privateScope.loadPid.gains.I;
- if (privateScope.loadPid.Iterm > privateScope.loadPid.ItermLimit) {
- privateScope.loadPid.Iterm = privateScope.loadPid.ItermLimit;
- } else if (privateScope.loadPid.Iterm < -privateScope.loadPid.ItermLimit) {
- privateScope.loadPid.Iterm = -privateScope.loadPid.ItermLimit;
- }
-
- privateScope.dropRatio = Pterm + privateScope.loadPid.Iterm + Dterm;
- if (privateScope.dropRatio < privateScope.loadPid.output.minThreshold) {
- privateScope.dropRatio = privateScope.loadPid.output.min;
- }
- if (privateScope.dropRatio > privateScope.loadPid.output.max) {
- privateScope.dropRatio = privateScope.loadPid.output.max;
- }
+ privateScope.dropRatio = privateScope.loadPidController.run(publicScope.getLoad());
};
publicScope.getDropRatio = function () {
diff --git a/main.html b/main.html
index 63c6a465..fe2aaa61 100755
--- a/main.html
+++ b/main.html
@@ -52,6 +52,7 @@
+