<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[192669] trunk/PerformanceTests</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/192669">192669</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-11-19 17:20:48 -0800 (Thu, 19 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Calculate the graphics benchmark test gain adaptively
https://bugs.webkit.org/show_bug.cgi?id=151208

Patch by Said Abou-Hallawa &lt;sabouhallawa@apple.com&gt; on 2015-11-19
Reviewed by Darin Adler.

We need to calculate the gain of the graphics benchmark tests adaptively
and get rid of the gain and limits parameters we have to choose manually
for every test. We are going to use the classic Ziegler–Nichols method for
calculating the gain and integral and derivative times. We are going to
try moving on a cubic curve during the manual stage from y0 to reach ysp.
We also going to use a saturation actuator to ensure the system does not
fluctuate.

* Animometer/resources/extensions.js:
(ResultsTable.prototype._isNoisyMeasurement): Fix a parameter name.
(ResultsTable.prototype._isNoisyTest): Since score is a member of testResults, we need to limit our search to frame rate and complexity.
(ResultsTable.prototype._showTest): Pass the correct parameter to _isNoisyMeasurement().

* Animometer/resources/strings.js: Fix the indentation and name and value of a string.

* Animometer/runner/resources/tests.js: Remove all the manual gains and limits parameters which had to be passed to every test.

* Animometer/tests/resources/main.js:
(BenchmarkState.prototype.currentStage): Fix an enum name.
(Benchmark): Get rid of manual gain and limits.
(Benchmark.prototype.update): Simplify the calculation by having all the times in ms.

* Animometer/tests/resources/math.js:
(PIDController): Get rid of the manual gain and limits and the magic numbers for Ti and Td.
(PIDController.prototype._yPosition): Tells whether the test current output is moving towards the set-point or away from it.
(PIDController.prototype._distanceUltimate): Calculates the ultimate distance from y0 after time t using a cubic formula.
(PIDController.prototype._distance): Calculates the distance of y relative to y0.
(PIDController.prototype._gainIncrement): Decides how much the proportional gain should be increased during the manual gain stage.
(PIDController.prototype._updateStage): Updates the stage of the controller based on its current stage and the system output.
(PIDController.prototype._tuneP): Tunes the system before calculating the PID controller gains.
(PIDController.prototype._tunePID): PID tuning function.
(PIDController.prototype._tune):
(PIDController.prototype._saturate):
(PIDController.prototype.tune): Manages calculating the controller parameters. It then returns a PID tuning value.
(PIDController.prototype._sat): Deleted. We may need to return it back but the limits have to be calculated adaptively not manually.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsAnimometerresourcesextensionsjs">trunk/PerformanceTests/Animometer/resources/extensions.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometerresourcesstringsjs">trunk/PerformanceTests/Animometer/resources/strings.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometerrunnerresourcestestsjs">trunk/PerformanceTests/Animometer/runner/resources/tests.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometertestsresourcesmainjs">trunk/PerformanceTests/Animometer/tests/resources/main.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometertestsresourcesmathjs">trunk/PerformanceTests/Animometer/tests/resources/math.js</a></li>
<li><a href="#trunkPerformanceTestsChangeLog">trunk/PerformanceTests/ChangeLog</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkPerformanceTestsAnimometerresourcesextensionsjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/resources/extensions.js (192668 => 192669)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/resources/extensions.js        2015-11-20 01:13:17 UTC (rev 192668)
+++ trunk/PerformanceTests/Animometer/resources/extensions.js        2015-11-20 01:20:48 UTC (rev 192669)
</span><span class="lines">@@ -361,7 +361,7 @@
</span><span class="cx">         button.textContent = Strings.text.results.json + &quot;...&quot;;
</span><span class="cx">     },
</span><span class="cx">     
</span><del>-    _isNoisyMeasurement: function(experiment, data, measurement, options)
</del><ins>+    _isNoisyMeasurement: function(jsonExperiment, data, measurement, options)
</ins><span class="cx">     {
</span><span class="cx">         const percentThreshold = 10;
</span><span class="cx">         const averageThreshold = 2;
</span><span class="lines">@@ -369,7 +369,7 @@
</span><span class="cx">         if (measurement == Strings.json.measurements.percent)
</span><span class="cx">             return data[Strings.json.measurements.percent] &gt;= percentThreshold;
</span><span class="cx">             
</span><del>-        if (experiment == Strings.json.experiments.frameRate &amp;&amp; measurement == Strings.json.measurements.average)
</del><ins>+        if (jsonExperiment == Strings.json.experiments.frameRate &amp;&amp; measurement == Strings.json.measurements.average)
</ins><span class="cx">             return Math.abs(data[Strings.json.measurements.average] - options[&quot;frame-rate&quot;]) &gt;= averageThreshold;
</span><span class="cx"> 
</span><span class="cx">         return false;
</span><span class="lines">@@ -377,10 +377,11 @@
</span><span class="cx"> 
</span><span class="cx">     _isNoisyTest: function(testResults, options)
</span><span class="cx">     {
</span><del>-        for (var experiment in testResults) {
-            var data = testResults[experiment];
</del><ins>+        for (var index = 0; index &lt; 2; ++index) {
+            var jsonExperiment = !index ? Strings.json.experiments.complexity : Strings.json.experiments.frameRate;
+            var data = testResults[jsonExperiment];
</ins><span class="cx">             for (var measurement in data) {
</span><del>-                if (this._isNoisyMeasurement(experiment, data, measurement, options))
</del><ins>+                if (this._isNoisyMeasurement(jsonExperiment, data, measurement, options))
</ins><span class="cx">                     return true;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -422,9 +423,10 @@
</span><span class="cx"> 
</span><span class="cx">             case 2:
</span><span class="cx">             case 3:
</span><del>-                var data = testResults[index == 2 ? Strings.json.experiments.complexity : Strings.json.experiments.frameRate];
</del><ins>+                var jsonExperiment = index == 2 ? Strings.json.experiments.complexity : Strings.json.experiments.frameRate;
+                var data = testResults[jsonExperiment];
</ins><span class="cx">                 for (var measurement in data)
</span><del>-                    this._showFixedNumber(row, data[measurement], 2, this._isNoisyMeasurement(index - 2, data, measurement, options) ? className : &quot;&quot;);
</del><ins>+                    this._showFixedNumber(row, data[measurement], 2, this._isNoisyMeasurement(jsonExperiment, data, measurement, options) ? className : &quot;&quot;);
</ins><span class="cx">                 break;
</span><span class="cx">                 
</span><span class="cx">             case 4:
</span></span></pre></div>
<a id="trunkPerformanceTestsAnimometerresourcesstringsjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/resources/strings.js (192668 => 192669)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/resources/strings.js        2015-11-20 01:13:17 UTC (rev 192668)
+++ trunk/PerformanceTests/Animometer/resources/strings.js        2015-11-20 01:20:48 UTC (rev 192669)
</span><span class="lines">@@ -1,12 +1,12 @@
</span><span class="cx"> var Strings = {
</span><span class="cx">     text: {
</span><del>-       testName: &quot;Test Name&quot;,
-       score: &quot;Score&quot;,
-       samples: &quot;Samples&quot;,
</del><ins>+        testName: &quot;Test Name&quot;,
+        score: &quot;Score&quot;,
+        samples: &quot;Samples&quot;,
</ins><span class="cx"> 
</span><del>-       runningState: {
-           warmingup: &quot;Warming up&quot;,
-           sampling: &quot;Sampling&quot;,
</del><ins>+        runningState: {
+            warming: &quot;Warming&quot;,
+            sampling: &quot;Sampling&quot;,
</ins><span class="cx">             finished: &quot;Finished&quot;
</span><span class="cx">         },
</span><span class="cx"> 
</span><span class="lines">@@ -55,5 +55,4 @@
</span><span class="cx">             samplingTimeOffset: &quot;samplingTimeOffset&quot;
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-
</del><span class="cx"> };
</span></span></pre></div>
<a id="trunkPerformanceTestsAnimometerrunnerresourcestestsjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/runner/resources/tests.js (192668 => 192669)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/runner/resources/tests.js        2015-11-20 01:13:17 UTC (rev 192668)
+++ trunk/PerformanceTests/Animometer/runner/resources/tests.js        2015-11-20 01:20:48 UTC (rev 192669)
</span><span class="lines">@@ -62,27 +62,27 @@
</span><span class="cx"> Suites.push(new Suite(&quot;HTML suite&quot;,
</span><span class="cx">     [
</span><span class="cx">         { 
</span><del>-            url: &quot;bouncing-particles/bouncing-css-shapes.html?gain=1&amp;addLimit=100&amp;removeLimit=5&amp;particleWidth=12&amp;particleHeight=12&amp;shape=circle&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-css-shapes.html?particleWidth=12&amp;particleHeight=12&amp;shape=circle&quot;,
</ins><span class="cx">             name: &quot;CSS bouncing circles&quot;
</span><span class="cx">         },
</span><span class="cx">         { 
</span><del>-            url: &quot;bouncing-particles/bouncing-css-shapes.html?gain=1&amp;addLimit=100&amp;removeLimit=5&amp;particleWidth=40&amp;particleHeight=40&amp;shape=rect&amp;clip=star&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-css-shapes.html?particleWidth=40&amp;particleHeight=40&amp;shape=rect&amp;clip=star&quot;,
</ins><span class="cx">             name: &quot;CSS bouncing clipped rects&quot;
</span><span class="cx">         },
</span><span class="cx">         { 
</span><del>-            url: &quot;bouncing-particles/bouncing-css-shapes.html?gain=1&amp;addLimit=100&amp;removeLimit=5&amp;particleWidth=50&amp;particleHeight=50&amp;shape=circle&amp;fill=gradient&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-css-shapes.html?particleWidth=50&amp;particleHeight=50&amp;shape=circle&amp;fill=gradient&quot;,
</ins><span class="cx">             name: &quot;CSS bouncing gradient circles&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;bouncing-particles/bouncing-css-images.html?gain=0.4&amp;addLimit=5&amp;removeLimit=2&amp;particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.svg&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-css-images.html?particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.svg&quot;,
</ins><span class="cx">             name: &quot;CSS bouncing SVG images&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;bouncing-particles/bouncing-css-images.html?gain=1&amp;addLimit=100&amp;removeLimit=5&amp;particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.png&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-css-images.html?particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.png&quot;,
</ins><span class="cx">             name: &quot;CSS bouncing PNG images&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;text/layering-text.html?gain=4&amp;addLimit=100&amp;removeLimit=100&quot;,
</del><ins>+            url: &quot;text/layering-text.html&quot;,
</ins><span class="cx">             name: &quot;CSS layering text&quot;
</span><span class="cx">         },
</span><span class="cx">     ]
</span><span class="lines">@@ -91,23 +91,23 @@
</span><span class="cx"> Suites.push(new Suite(&quot;Canvas suite&quot;,
</span><span class="cx">     [
</span><span class="cx">         { 
</span><del>-            url: &quot;bouncing-particles/bouncing-canvas-shapes.html?gain=4&amp;addLimit=100&amp;removeLimit=1000&amp;particleWidth=12&amp;particleHeight=12&amp;shape=circle&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-canvas-shapes.html?particleWidth=12&amp;particleHeight=12&amp;shape=circle&quot;,
</ins><span class="cx">             name: &quot;canvas bouncing circles&quot;
</span><span class="cx">         },
</span><span class="cx">         { 
</span><del>-            url: &quot;bouncing-particles/bouncing-canvas-shapes.html?gain=4&amp;addLimit=100&amp;removeLimit=1000&amp;particleWidth=40&amp;particleHeight=40&amp;shape=rect&amp;clip=star&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-canvas-shapes.html?particleWidth=40&amp;particleHeight=40&amp;shape=rect&amp;clip=star&quot;,
</ins><span class="cx">             name: &quot;canvas bouncing clipped rects&quot;
</span><span class="cx">         },
</span><span class="cx">         { 
</span><del>-            url: &quot;bouncing-particles/bouncing-canvas-shapes.html?gain=4&amp;addLimit=100&amp;removeLimit=1000&amp;particleWidth=50&amp;particleHeight=50&amp;shape=circle&amp;fill=gradient&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-canvas-shapes.html?particleWidth=50&amp;particleHeight=50&amp;shape=circle&amp;fill=gradient&quot;,
</ins><span class="cx">             name: &quot;canvas bouncing gradient circles&quot;
</span><span class="cx">         },
</span><span class="cx">         { 
</span><del>-            url: &quot;bouncing-particles/bouncing-canvas-images.html?gain=0.4&amp;addLimit=5&amp;removeLimit=1&amp;particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.svg&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-canvas-images.html?particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.svg&quot;,
</ins><span class="cx">             name: &quot;canvas bouncing SVG images&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;bouncing-particles/bouncing-canvas-images.html?gain=4&amp;addLimit=1000&amp;removeLimit=1000&amp;particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.png&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-canvas-images.html?particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.png&quot;,
</ins><span class="cx">             name: &quot;canvas bouncing PNG images&quot;
</span><span class="cx">         },
</span><span class="cx">     ]
</span><span class="lines">@@ -116,23 +116,23 @@
</span><span class="cx"> Suites.push(new Suite(&quot;SVG suite&quot;,
</span><span class="cx">     [
</span><span class="cx">         {
</span><del>-            url: &quot;bouncing-particles/bouncing-svg-shapes.html?gain=6&amp;addLimit=100&amp;removeLimit=1000&amp;particleWidth=12&amp;particleHeight=12&amp;shape=circle&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-svg-shapes.html?particleWidth=12&amp;particleHeight=12&amp;shape=circle&quot;,
</ins><span class="cx">             name: &quot;SVG bouncing circles&quot;,
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;bouncing-particles/bouncing-svg-shapes.html?gain=0.6&amp;addLimit=10&amp;removeLimit=1&amp;particleWidth=40&amp;particleHeight=40&amp;shape=rect&amp;clip=star&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-svg-shapes.html?particleWidth=40&amp;particleHeight=40&amp;shape=rect&amp;clip=star&quot;,
</ins><span class="cx">             name: &quot;SVG bouncing clipped rects&quot;,
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;bouncing-particles/bouncing-svg-shapes.html?gain=0.8&amp;addLimit=10&amp;removeLimit=4&amp;particleWidth=50&amp;particleHeight=50&amp;shape=circle&amp;fill=gradient&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-svg-shapes.html?particleWidth=50&amp;particleHeight=50&amp;shape=circle&amp;fill=gradient&quot;,
</ins><span class="cx">             name: &quot;SVG bouncing gradient circles&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;bouncing-particles/bouncing-svg-images.html?gain=0.4&amp;addLimit=5&amp;removeLimit=2&amp;particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.svg&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-svg-images.html?particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.svg&quot;,
</ins><span class="cx">             name: &quot;SVG bouncing SVG images&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;bouncing-particles/bouncing-svg-images.html?gain=4&amp;addLimit=100&amp;removeLimit=5&amp;particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.png&quot;,
</del><ins>+            url: &quot;bouncing-particles/bouncing-svg-images.html?particleWidth=80&amp;particleHeight=80&amp;imageSrc=../resources/yin-yang.png&quot;,
</ins><span class="cx">             name: &quot;SVG bouncing PNG images&quot;
</span><span class="cx">         },
</span><span class="cx">     ]
</span><span class="lines">@@ -226,11 +226,11 @@
</span><span class="cx"> Suites.push(new Suite(&quot;Complex examples&quot;,
</span><span class="cx">     [
</span><span class="cx">         {
</span><del>-            url: &quot;examples/canvas-electrons.html?gain=1&amp;addLimit=100&amp;removeLimit=10&quot;,
</del><ins>+            url: &quot;examples/canvas-electrons.html&quot;,
</ins><span class="cx">             name: &quot;canvas electrons&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;examples/canvas-stars.html?gain=4&amp;addLimit=100&amp;removeLimit=5&quot;,
</del><ins>+            url: &quot;examples/canvas-stars.html&quot;,
</ins><span class="cx">             name: &quot;canvas stars&quot;
</span><span class="cx">         },
</span><span class="cx">     ]
</span><span class="lines">@@ -239,15 +239,15 @@
</span><span class="cx"> Suites.push(new Suite(&quot;Test Templates&quot;,
</span><span class="cx">     [
</span><span class="cx">         {
</span><del>-            url: &quot;template/template-css.html?gain=1&amp;addLimit=100&amp;removeLimit=5&quot;,
</del><ins>+            url: &quot;template/template-css.html&quot;,
</ins><span class="cx">             name: &quot;CSS template&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;template/template-canvas.html?gain=1&amp;addLimit=100&amp;removeLimit=1000&quot;,
</del><ins>+            url: &quot;template/template-canvas.html&quot;,
</ins><span class="cx">             name: &quot;canvas template&quot;
</span><span class="cx">         },
</span><span class="cx">         {
</span><del>-            url: &quot;template/template-svg.html?gain=1&amp;addLimit=100&amp;removeLimit=5&amp;&lt;other_paramter&gt;=&lt;value&gt;&quot;,
</del><ins>+            url: &quot;template/template-svg.html&quot;,
</ins><span class="cx">             name: &quot;SVG template&quot;
</span><span class="cx">         },
</span><span class="cx">     ]
</span></span></pre></div>
<a id="trunkPerformanceTestsAnimometertestsresourcesmainjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/tests/resources/main.js (192668 => 192669)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/tests/resources/main.js        2015-11-20 01:13:17 UTC (rev 192668)
+++ trunk/PerformanceTests/Animometer/tests/resources/main.js        2015-11-20 01:20:48 UTC (rev 192669)
</span><span class="lines">@@ -6,11 +6,11 @@
</span><span class="cx"> 
</span><span class="cx"> // The enum values and the messages should be in the same order
</span><span class="cx"> BenchmarkState.stages = {
</span><del>-    WARMING_UP: 0,
</del><ins>+    WARMING: 0,
</ins><span class="cx">     SAMPLING: 1,
</span><span class="cx">     FINISHED: 2,
</span><span class="cx">     messages: [ 
</span><del>-        Strings.text.runningState.warmingup,
</del><ins>+        Strings.text.runningState.warming,
</ins><span class="cx">         Strings.text.runningState.sampling,
</span><span class="cx">         Strings.text.runningState.finished
</span><span class="cx">     ]
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx">     
</span><span class="cx">     currentStage: function()
</span><span class="cx">     {
</span><del>-        for (var stage = BenchmarkState.stages.WARMING_UP; stage &lt; BenchmarkState.stages.FINISHED; ++stage) {
</del><ins>+        for (var stage = BenchmarkState.stages.WARMING; stage &lt; BenchmarkState.stages.FINISHED; ++stage) {
</ins><span class="cx">             if (this._currentTimeOffset &lt; this._timeOffset(stage + 1))
</span><span class="cx">                 return stage;
</span><span class="cx">         }
</span><span class="lines">@@ -136,11 +136,7 @@
</span><span class="cx">     this._recordInterval = 200;    
</span><span class="cx">     this._isSampling = false;
</span><span class="cx"> 
</span><del>-    var gain = parseInt(this._options[&quot;gain&quot;]) || 1;
-    var lowValue = -parseInt(this._options[&quot;addLimit&quot;]) || 1;
-    var highValue = parseInt(this._options[&quot;removeLimit&quot;]) || 1;
-    
-    this._controller = new PIDController(gain, this._options[&quot;frame-rate&quot;], lowValue, highValue);
</del><ins>+    this._controller = new PIDController(this._options[&quot;frame-rate&quot;]);
</ins><span class="cx">     this._sampler = new Sampler(2);
</span><span class="cx">     this._state = new BenchmarkState(this._options[&quot;test-interval&quot;] * 1000);
</span><span class="cx"> }
</span><span class="lines">@@ -177,7 +173,7 @@
</span><span class="cx">         else if (!(this._isSampling &amp;&amp; this._options[&quot;fix-test-complexity&quot;])) {
</span><span class="cx">             // The relationship between frameRate and test complexity is inverse-proportional so we
</span><span class="cx">             // need to use the negative of PIDController.tune() to change the complexity of the test.
</span><del>-            tuneValue = -this._controller.tune(currentFrameRate, timeDelta / 1000);
</del><ins>+            tuneValue = -this._controller.tune(currentTimeOffset, timeDelta, currentFrameRate);
</ins><span class="cx">             tuneValue = tuneValue &gt; 0 ? Math.floor(tuneValue) : Math.ceil(tuneValue);
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkPerformanceTestsAnimometertestsresourcesmathjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/tests/resources/math.js (192668 => 192669)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/tests/resources/math.js        2015-11-20 01:13:17 UTC (rev 192668)
+++ trunk/PerformanceTests/Animometer/tests/resources/math.js        2015-11-20 01:20:48 UTC (rev 192669)
</span><span class="lines">@@ -4,17 +4,17 @@
</span><span class="cx">     {
</span><span class="cx">         return Array(m * n).fill(v);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     zeros: function(m, n)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.init(m, n, 0);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     ones: function(m, n)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.init(m, n, 1);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     identity: function(n)
</span><span class="cx">     {
</span><span class="cx">         var out = new Matrix.zeros(n, n);
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx">             out[i * n + i] = 1;
</span><span class="cx">         return out;
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     str: function(A, n, m)
</span><span class="cx">     {
</span><span class="cx">         var out = (m &gt; 1 &amp;&amp; n &gt; 1 ? &quot;Matrix[&quot; + n + &quot;, &quot; + m : &quot;Vector[&quot; + m * n) + &quot;] = [&quot;;
</span><span class="lines">@@ -33,12 +33,12 @@
</span><span class="cx">         }       
</span><span class="cx">         return out + &quot;]&quot;;
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     pos: function(m, i, j)
</span><span class="cx">     {
</span><span class="cx">         return m * i + j;
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     add: function(A, B, n, m)
</span><span class="cx">     {
</span><span class="cx">         var out = Matrix.zeros(n, m);
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx">             out[i] = A[i] + B[i];
</span><span class="cx">         return out;
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     subtract: function(A, B, n, m)
</span><span class="cx">     {
</span><span class="cx">         var out = Matrix.zeros(n, m);
</span><span class="lines">@@ -54,7 +54,7 @@
</span><span class="cx">             out[i] = A[i] - B[i];
</span><span class="cx">         return out;
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     scale: function(s, A, n, m)
</span><span class="cx">     {
</span><span class="cx">         var out = Matrix.zeros(n, m);
</span><span class="lines">@@ -62,17 +62,17 @@
</span><span class="cx">             out[i] = s * A[i];
</span><span class="cx">         return out;
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     transpose: function(A, n, m)
</span><span class="cx">     {
</span><span class="cx">         var out = Matrix.zeros(m, n);
</span><span class="cx">         for (var i = 0; i &lt; n; ++i) {
</span><span class="cx">             for (var j = 0; j &lt; m; ++j)
</span><span class="cx">                 out[Matrix.pos(n, i, j)] = A[Matrix.pos(m, j, i)];
</span><del>-        }       
</del><ins>+        }
</ins><span class="cx">         return out;
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     multiply: function(A, B, n, m, p)
</span><span class="cx">     {
</span><span class="cx">         var out = Matrix.zeros(n, p);
</span><span class="lines">@@ -93,37 +93,37 @@
</span><span class="cx">     {
</span><span class="cx">         return Matrix.zeros(1, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     ones: function()
</span><span class="cx">     {
</span><span class="cx">         return Matrix.ones(1, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     str: function(v)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.str(v, 1, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     add: function(v, w)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.add(v, w, 1, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     subtract: function(v, w)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.subtract(v, w, 1, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     scale: function(s, v)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.scale(s, v, 1, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     multiplyMatrix3: function(v, A)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.multiply(v, A, 1, 3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     multiplyVector3: function(v, w)
</span><span class="cx">     {
</span><span class="cx">         var out = 0;
</span><span class="lines">@@ -139,114 +139,308 @@
</span><span class="cx">     {
</span><span class="cx">         return Matrix.zeros(3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     identity: function()
</span><span class="cx">     {
</span><span class="cx">         return Matrix.identity(3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     str: function(A)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.str(A, 3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     pos: function(i, j)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.pos(3, i, j);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     add: function(A, B)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.add(A, B, 3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     subtract: function(A, B)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.subtract(A, B, 3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     scale: function(s, A)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.scale(s, A, 3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     transpose: function(A)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.transpose(A, 3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     multiplyMatrix3: function(A, B)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.multiply(A, B, 3, 3, 3);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     multiplyVector3: function(A, v)
</span><span class="cx">     {
</span><span class="cx">         return Matrix.multiply(A, v, 3, 3, 1);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function PIDController(K, ysp, ulow, uhigh)
</del><ins>+function PIDController(ysp)
</ins><span class="cx"> {
</span><span class="cx">     this._ysp = ysp;
</span><ins>+    this._out = 0;
</ins><span class="cx"> 
</span><del>-    this._Td = 5;
-    this._Ti = 15;
-
-    this._Kp = K;
-    this._Kd = K / this._Td;
-    this._Ki = K / this._Ti;
-
</del><ins>+    this._Kp = 0;
+    this._stage = PIDController.stages.WARMING;
+    
</ins><span class="cx">     this._eold = 0;
</span><span class="cx">     this._I = 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// 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.
+PIDController.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.
+PIDController.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.
+}
+
</ins><span class="cx"> PIDController.prototype =
</span><span class="cx"> {
</span><del>-    _sat: function(v, low, high)
</del><ins>+    // Determines whether the current y is
+    //  before ysp =&gt; (below ysp if ysp &gt; y0) || (above ysp if ysp &lt; y0)
+    //  after ysp =&gt; (above ysp if ysp &gt; y0) || (below ysp if ysp &lt; y0)
+    _yPosition: function(y)
</ins><span class="cx">     {
</span><del>-        return v &lt; low ? low : (v &gt; high ? high : v);
</del><ins>+        return (y &lt; this._ysp) == (this._y0 &lt; this._ysp)
+            ? PIDController.yPositions.BEFORE_SETPOINT
+            : PIDController.yPositions.AFTER_SETPOINT;
</ins><span class="cx">     },
</span><del>-    
-    tune: function(y, h)
</del><ins>+
+    // 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)
</ins><span class="cx">     {
</span><del>-        // Current error.
-        var e = this._ysp - y;
</del><ins>+        return (this._ysp - this._y0) * Math.pow(t / 1000, 3);
+    },
</ins><span class="cx"> 
</span><ins>+    // 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 &lt; 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)
+    {
</ins><span class="cx">         // Proportional term.
</span><span class="cx">         var P = this._Kp * e;
</span><del>-        
</del><ins>+
+        // 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;
+
</ins><span class="cx">         // Derivative term is the slope of the curve at the current time.
</span><del>-        var D = this._Kd * (e - this._eold) / h;
</del><ins>+        var D = (this._Kp * this._Td) * (e - this._eold) / h;
</ins><span class="cx"> 
</span><del>-        // Integral term is the area under the curve starting from the begining till the current time.
-        this._I += this._Ki * ((e + this._eold) / 2) * h;
</del><ins>+        // 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 == &quot;undefined&quot;) {
+                // 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);
</ins><span class="cx"> 
</span><del>-        // pid controller value.
-        var v = P + D + this._I;
</del><ins>+        case PIDController.stages.OVERSHOOT:
+            // This is the second stage of the Zieglerâ€Nichols method. It measures the
+            // oscillation period.
+            if (typeof this._t0 == &quot;undefined&quot;) {
+                // t is the time of the begining of the first overshot
+                this._t0 = t;
+                this._Kp /= 2;
+            }
</ins><span class="cx">         
</span><del>-        // Avoid spikes by applying actuator saturation.
-        var u = this._sat(v, this._ulow, this._uhigh);        
</del><ins>+            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 == &quot;undefined&quot;) {
+                // 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 &quot;some overshoot&quot; 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 == &quot;undefined&quot;)
+                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:
+            var out = this._out + u;
+            var min = Math.min(this._min, this._max * 0.70);
+            var max = this._max;
</ins><span class="cx"> 
</span><ins>+            // 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.
</ins><span class="cx">         this._eold = e;
</span><del>-        return u;
</del><ins>+        
+        // Apply back-calculation and tracking to avoid integrator windup
+        return this._saturate(v, e);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> function KalmanEstimator(initX)
</span><span class="cx"> {
</span><del>-    // Initialize state transition matrix
</del><ins>+    // Initialize state transition matrix.
</ins><span class="cx">     this._matA = Matrix3.identity();
</span><span class="cx">     this._matA[Matrix3.pos(0, 2)] = 1;
</span><del>-    
-    // Initialize measurement matrix
</del><ins>+
+    // Initialize measurement matrix.
</ins><span class="cx">     this._vecH = Vector3.zeros();
</span><span class="cx">     this._vecH[0] = 1;
</span><del>-    
</del><ins>+
</ins><span class="cx">     this._matQ = Matrix3.identity();
</span><span class="cx">     this._R = 1000;
</span><del>-    
-    // Initial state conditions
</del><ins>+
+    // Initial state conditions.
</ins><span class="cx">     this._vecX_est = Vector3.zeros();
</span><span class="cx">     this._vecX_est[0] = initX;
</span><span class="cx">     this._matP_est = Matrix3.zeros();
</span><span class="lines">@@ -259,7 +453,7 @@
</span><span class="cx">         // Project the state ahead
</span><span class="cx">         //  X_prd(k) = A * X_est(k-1)
</span><span class="cx">         var vecX_prd = Matrix3.multiplyVector3(this._matA, this._vecX_est);
</span><del>-        
</del><ins>+
</ins><span class="cx">         // Project the error covariance ahead
</span><span class="cx">         //  P_prd(k) = A * P_est(k-1) * A' + Q
</span><span class="cx">         var matP_prd = Matrix3.add(Matrix3.multiplyMatrix3(Matrix3.multiplyMatrix3(this._matA, this._matP_est), Matrix3.transpose(this._matA)), this._matQ);
</span><span class="lines">@@ -271,11 +465,11 @@
</span><span class="cx">         var vecB = Vector3.multiplyMatrix3(this._vecH, Matrix3.transpose(matP_prd));
</span><span class="cx">         var S = Vector3.multiplyVector3(vecB, this._vecH) + this._R;
</span><span class="cx">         var vecGain = Vector3.scale(1/S, vecB);
</span><del>-        
</del><ins>+
</ins><span class="cx">         // Update the estimate via z(k)
</span><span class="cx">         //  X_est(k) = x_prd + K(k) * (z(k) - H * X_prd(k));
</span><span class="cx">         this._vecX_est = Vector3.add(vecX_prd, Vector3.scale(current - Vector3.multiplyVector3(this._vecH, vecX_prd), vecGain));
</span><del>-        
</del><ins>+
</ins><span class="cx">         // Update the error covariance
</span><span class="cx">         //  P_est(k) = P_prd(k) - K(k) * H * P_prd(k);
</span><span class="cx">         this._matP_est = Matrix3.subtract(matP_prd, Matrix3.scale(Vector3.multiplyVector3(vecGain, this._vecH), matP_prd));
</span></span></pre></div>
<a id="trunkPerformanceTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/ChangeLog (192668 => 192669)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/ChangeLog        2015-11-20 01:13:17 UTC (rev 192668)
+++ trunk/PerformanceTests/ChangeLog        2015-11-20 01:20:48 UTC (rev 192669)
</span><span class="lines">@@ -1,3 +1,46 @@
</span><ins>+2015-11-19  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
+
+        Calculate the graphics benchmark test gain adaptively
+        https://bugs.webkit.org/show_bug.cgi?id=151208
+
+        Reviewed by Darin Adler.
+
+        We need to calculate the gain of the graphics benchmark tests adaptively
+        and get rid of the gain and limits parameters we have to choose manually
+        for every test. We are going to use the classic Ziegler–Nichols method for
+        calculating the gain and integral and derivative times. We are going to
+        try moving on a cubic curve during the manual stage from y0 to reach ysp.
+        We also going to use a saturation actuator to ensure the system does not
+        fluctuate.
+
+        * Animometer/resources/extensions.js:
+        (ResultsTable.prototype._isNoisyMeasurement): Fix a parameter name.
+        (ResultsTable.prototype._isNoisyTest): Since score is a member of testResults, we need to limit our search to frame rate and complexity.
+        (ResultsTable.prototype._showTest): Pass the correct parameter to _isNoisyMeasurement(). 
+        
+        * Animometer/resources/strings.js: Fix the indentation and name and value of a string.
+
+        * Animometer/runner/resources/tests.js: Remove all the manual gains and limits parameters which had to be passed to every test.
+        
+        * Animometer/tests/resources/main.js:
+        (BenchmarkState.prototype.currentStage): Fix an enum name.
+        (Benchmark): Get rid of manual gain and limits.
+        (Benchmark.prototype.update): Simplify the calculation by having all the times in ms.
+        
+        * Animometer/tests/resources/math.js:
+        (PIDController): Get rid of the manual gain and limits and the magic numbers for Ti and Td.
+        (PIDController.prototype._yPosition): Tells whether the test current output is moving towards the set-point or away from it.
+        (PIDController.prototype._distanceUltimate): Calculates the ultimate distance from y0 after time t using a cubic formula.
+        (PIDController.prototype._distance): Calculates the distance of y relative to y0.
+        (PIDController.prototype._gainIncrement): Decides how much the proportional gain should be increased during the manual gain stage.
+        (PIDController.prototype._updateStage): Updates the stage of the controller based on its current stage and the system output.
+        (PIDController.prototype._tuneP): Tunes the system before calculating the PID controller gains.
+        (PIDController.prototype._tunePID): PID tuning function.
+        (PIDController.prototype._tune):
+        (PIDController.prototype._saturate):
+        (PIDController.prototype.tune): Manages calculating the controller parameters. It then returns a PID tuning value.
+        (PIDController.prototype._sat): Deleted. We may need to return it back but the limits have to be calculated adaptively not manually. 
+
</ins><span class="cx"> 2015-11-17  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Reorganize the graphics benchmark string table
</span></span></pre>
</div>
</div>

</body>
</html>