summaryrefslogtreecommitdiffstats
path: root/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js')
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js268
1 files changed, 268 insertions, 0 deletions
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js
new file mode 100644
index 0000000000..9c2706e2a3
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js
@@ -0,0 +1,268 @@
+SimpleKalmanEstimator = Utilities.createSubclass(Experiment,
+ function(processError, measurementError) {
+ Experiment.call(this, false);
+ var error = .5 * (Math.sqrt(processError * processError + 4 * processError * measurementError) - processError);
+ this._gain = error / (error + measurementError);
+ }, {
+
+ sample: function(newMeasurement)
+ {
+ if (!this._initialized) {
+ this._initialized = true;
+ this.estimate = newMeasurement;
+ return;
+ }
+
+ this.estimate = this.estimate + this._gain * (newMeasurement - this.estimate);
+ },
+
+ reset: function()
+ {
+ Experiment.prototype.reset.call(this);
+ this._initialized = false;
+ this.estimate = 0;
+ }
+});
+
+PIDController = Utilities.createClass(
+ function(ysp)
+ {
+ this._ysp = ysp;
+ this._out = 0;
+
+ this._Kp = 0;
+ this._stage = PIDController.stages.WARMING;
+
+ this._eold = 0;
+ this._I = 0;
+ }, {
+
+ // Determines whether the current y is
+ // before ysp => (below ysp if ysp > y0) || (above ysp if ysp < y0)
+ // after ysp => (above ysp if ysp > y0) || (below ysp if ysp < y0)
+ _yPosition: function(y)
+ {
+ return (y < this._ysp) == (this._y0 < this._ysp)
+ ? PIDController.yPositions.BEFORE_SETPOINT
+ : PIDController.yPositions.AFTER_SETPOINT;
+ },
+
+ // Calculate the ultimate distance from y0 after time t. We want to move very
+ // slowly at the beginning to see how adding few items to the test can affect
+ // its output. The complexity of a single item might be big enough to keep the
+ // proportional gain very small but achieves the desired progress. But if y does
+ // not change significantly after adding few items, that means we need a much
+ // bigger gain. So we need to move over a cubic curve which increases very
+ // slowly with small t values but moves very fast with larger t values.
+ // The basic formula is: y = t^3
+ // Change the formula to reach y=1 after 1000 ms: y = (t/1000)^3
+ // Change the formula to reach y=(ysp - y0) after 1000 ms: y = (ysp - y0) * (t/1000)^3
+ _distanceUltimate: function(t)
+ {
+ return (this._ysp - this._y0) * Math.pow(t / 1000, 3);
+ },
+
+ // Calculates the distance of y relative to y0. It also ensures we do not return
+ // zero by returning a epsilon value in the same direction as ultimate distance.
+ _distance: function(y, du)
+ {
+ const epsilon = 0.0001;
+ var d = y - this._y0;
+ return du < 0 ? Math.min(d, -epsilon) : Math.max(d, epsilon);
+ },
+
+ // Decides how much the proportional gain should be increased during the manual
+ // gain stage. We choose to use the ratio of the ultimate distance to the current
+ // distance as an indication of how much the system is responsive. We want
+ // to keep the increment under control so it does not cause the system instability
+ // So we choose to take the natural logarithm of this ratio.
+ _gainIncrement: function(t, y, e)
+ {
+ var du = this._distanceUltimate(t);
+ var d = this._distance(y, du);
+ return Math.log(du / d) * 0.1;
+ },
+
+ // Update the stage of the controller based on its current stage and the system output
+ _updateStage: function(y)
+ {
+ var yPosition = this._yPosition(y);
+
+ switch (this._stage) {
+ case PIDController.stages.WARMING:
+ if (yPosition == PIDController.yPositions.AFTER_SETPOINT)
+ this._stage = PIDController.stages.OVERSHOOT;
+ break;
+
+ case PIDController.stages.OVERSHOOT:
+ if (yPosition == PIDController.yPositions.BEFORE_SETPOINT)
+ this._stage = PIDController.stages.UNDERSHOOT;
+ break;
+
+ case PIDController.stages.UNDERSHOOT:
+ if (yPosition == PIDController.yPositions.AFTER_SETPOINT)
+ this._stage = PIDController.stages.SATURATE;
+ break;
+ }
+ },
+
+ // Manual tuning is used before calculating the PID controller gains.
+ _tuneP: function(e)
+ {
+ // The output is the proportional term only.
+ return this._Kp * e;
+ },
+
+ // PID tuning function. Kp, Ti and Td were already calculated
+ _tunePID: function(h, y, e)
+ {
+ // Proportional term.
+ var P = this._Kp * e;
+
+ // Integral term is the area under the curve starting from the beginning
+ // till the current time.
+ this._I += (this._Kp / this._Ti) * ((e + this._eold) / 2) * h;
+
+ // Derivative term is the slope of the curve at the current time.
+ var D = (this._Kp * this._Td) * (e - this._eold) / h;
+
+ // The ouput is a PID function.
+ return P + this._I + D;
+ },
+
+ // Apply different strategies for the tuning based on the stage of the controller.
+ _tune: function(t, h, y, e)
+ {
+ switch (this._stage) {
+ case PIDController.stages.WARMING:
+ // This is the first stage of the Zieglerâ€Nichols method. It increments
+ // the proportional gain till the system output passes the set-point value.
+ if (typeof this._y0 == "undefined") {
+ // This is the first time a tuning value is required. We want the test
+ // to add only one item. So we need to return -1 which forces us to
+ // choose the initial value of Kp to be = -1 / e
+ this._y0 = y;
+ this._Kp = -1 / e;
+ } else {
+ // Keep incrementing the Kp as long as we have not reached the
+ // set-point yet
+ this._Kp += this._gainIncrement(t, y, e);
+ }
+
+ return this._tuneP(e);
+
+ case PIDController.stages.OVERSHOOT:
+ // This is the second stage of the Zieglerâ€Nichols method. It measures the
+ // oscillation period.
+ if (typeof this._t0 == "undefined") {
+ // t is the time of the begining of the first overshot
+ this._t0 = t;
+ this._Kp /= 2;
+ }
+
+ return this._tuneP(e);
+
+ case PIDController.stages.UNDERSHOOT:
+ // This is the end of the Zieglerâ€Nichols method. We need to calculate the
+ // integral and derivative periods.
+ if (typeof this._Ti == "undefined") {
+ // t is the time of the end of the first overshot
+ var Tu = t - this._t0;
+
+ // Calculate the system parameters from Kp and Tu assuming
+ // a "some overshoot" control type. See:
+ // https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
+ this._Ti = Tu / 2;
+ this._Td = Tu / 3;
+ this._Kp = 0.33 * this._Kp;
+
+ // Calculate the tracking time.
+ this._Tt = Math.sqrt(this._Ti * this._Td);
+ }
+
+ return this._tunePID(h, y, e);
+
+ case PIDController.stages.SATURATE:
+ return this._tunePID(h, y, e);
+ }
+
+ return 0;
+ },
+
+ // Ensures the system does not fluctuates.
+ _saturate: function(v, e)
+ {
+ var u = v;
+
+ switch (this._stage) {
+ case PIDController.stages.OVERSHOOT:
+ case PIDController.stages.UNDERSHOOT:
+ // Calculate the min-max values of the saturation actuator.
+ if (typeof this._min == "undefined")
+ this._min = this._max = this._out;
+ else {
+ this._min = Math.min(this._min, this._out);
+ this._max = Math.max(this._max, this._out);
+ }
+ break;
+
+ case PIDController.stages.SATURATE:
+ const limitPercentage = 0.90;
+ var min = this._min > 0 ? Math.min(this._min, this._max * limitPercentage) : this._min;
+ var max = this._max < 0 ? Math.max(this._max, this._min * limitPercentage) : this._max;
+ var out = this._out + u;
+
+ // Clip the controller output to the min-max values
+ out = Math.max(Math.min(max, out), min);
+ u = out - this._out;
+
+ // Apply the back-calculation and tracking
+ if (u != v)
+ u += (this._Kp * this._Tt / this._Ti) * e;
+ break;
+ }
+
+ this._out += u;
+ return u;
+ },
+
+ // Called from the benchmark to tune its test. It uses Ziegler-Nichols method
+ // to calculate the controller parameters. It then returns a PID tuning value.
+ tune: function(t, h, y)
+ {
+ this._updateStage(y);
+
+ // Current error.
+ var e = this._ysp - y;
+ var v = this._tune(t, h, y, e);
+
+ // Save e for the next call.
+ this._eold = e;
+
+ // Apply back-calculation and tracking to avoid integrator windup
+ return this._saturate(v, e);
+ }
+});
+
+Utilities.extendObject(PIDController, {
+ // This enum will be used to tell whether the system output (or the controller input)
+ // is moving towards the set-point or away from it.
+ yPositions: {
+ BEFORE_SETPOINT: 0,
+ AFTER_SETPOINT: 1
+ },
+
+ // The Ziegler-Nichols method for is used tuning the PID controller. The workflow of
+ // the tuning is split into four stages. The first two stages determine the values
+ // of the PID controller gains. During these two stages we return the proportional
+ // term only. The third stage is used to determine the min-max values of the
+ // saturation actuator. In the last stage back-calculation and tracking are applied
+ // to avoid integrator windup. During the last two stages, we return a PID control
+ // value.
+ stages: {
+ WARMING: 0, // Increase the value of the Kp until the system output reaches ysp.
+ OVERSHOOT: 1, // Measure the oscillation period and the overshoot value
+ UNDERSHOOT: 2, // Return PID value and measure the undershoot value
+ SATURATE: 3 // Return PID value and apply back-calculation and tracking.
+ }
+});