Skip to content

Commit a53e082

Browse files
authored
Merge pull request #613 from twpol/feature/smoothed-data-tests
fix: Use properly FPS-independent smoothing function
2 parents 992c4f7 + ad210fd commit a53e082

File tree

3 files changed

+60
-7
lines changed

3 files changed

+60
-7
lines changed

Source/ORTS.Common/SmoothedData.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,24 @@ namespace ORTS.Common
2424
{
2525
public class SmoothedData
2626
{
27-
public readonly float SmoothPeriodS = 3;
27+
const float DefaultSmoothPeriodS = 3;
28+
29+
public readonly float SmoothPeriodS;
30+
31+
protected float rate = 0;
2832
protected float value = float.NaN;
2933
protected float smoothedValue = float.NaN;
3034

3135
public SmoothedData()
36+
: this(DefaultSmoothPeriodS)
3237
{
3338
}
3439

3540
public SmoothedData(float smoothPeriodS)
36-
: this()
3741
{
3842
SmoothPeriodS = smoothPeriodS;
43+
// Convert the input assuming 60 FPS (arbitary)
44+
rate = (float)(-60 * Math.Log(1 - 1 / (60 * SmoothPeriodS)));
3945
}
4046

4147
public void Update(float periodS, float newValue)
@@ -53,13 +59,12 @@ public void Update(float periodS, float newValue)
5359

5460
protected void SmoothValue(ref float smoothedValue, float periodS, float newValue)
5561
{
56-
var rate = SmoothPeriodS / periodS;
57-
if (float.IsNaN(smoothedValue) || float.IsInfinity(smoothedValue))
58-
smoothedValue = newValue;
59-
else if (rate < 1)
62+
// This formula and the calculation of `rate` are FPS-independent; see https://www.gamedeveloper.com/programming/improved-lerp-smoothing- for more details
63+
var ratio = (float)Math.Exp(-rate * periodS);
64+
if (float.IsNaN(smoothedValue) || float.IsInfinity(smoothedValue) || ratio < 0.5)
6065
smoothedValue = newValue;
6166
else
62-
smoothedValue = (smoothedValue * (rate - 1) + newValue) / rate;
67+
smoothedValue = smoothedValue * ratio + newValue * (1 - ratio);
6368
}
6469

6570
public void ForceSmoothValue(float forcedValue)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// COPYRIGHT 2022 by the Open Rails project.
2+
//
3+
// This file is part of Open Rails.
4+
//
5+
// Open Rails is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// Open Rails is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU General Public License
16+
// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
17+
18+
using System.Linq;
19+
using Xunit;
20+
21+
namespace Tests.Orts.Common
22+
{
23+
public static class SmoothedData
24+
{
25+
[Theory]
26+
// FPS-like tests
27+
[InlineData(5, 3, 0.353)]
28+
[InlineData(10, 3, 0.353)]
29+
[InlineData(30, 3, 0.353)]
30+
[InlineData(60, 3, 0.353)]
31+
[InlineData(120, 3, 0.353)]
32+
// Physics-like tests
33+
[InlineData(60, 1, 0.000)] // Exhaust particles
34+
[InlineData(60, 2, 0.066)] // Smoke colour
35+
[InlineData(60, 45, 8.007)] // Field rate
36+
[InlineData(60, 150, 9.355)] // Burn rate
37+
[InlineData(60, 240, 9.592)] // Boiler heat
38+
public static void SmoothedFPS(int fps, float smoothPeriodS, float expected)
39+
{
40+
var period = (float)(1d / fps);
41+
var smoothed = new ORTS.Common.SmoothedData(smoothPeriodS);
42+
smoothed.Update(0, 10);
43+
foreach (var i in Enumerable.Range(0, 10 * fps)) smoothed.Update(period, 0);
44+
Assert.Equal(expected, smoothed.SmoothedValue, 3);
45+
}
46+
}
47+
}

Source/Tests/Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
<Compile Include="DynamicPrecisionEqualityComparer.cs" />
6666
<Compile Include="Orts.Parsers.Msts\StfReader.cs" />
6767
<Compile Include="Orts.Common\Conversions.cs" />
68+
<Compile Include="Orts.Common\SmoothedData.cs" />
6869
<Compile Include="Orts.Parsers.OR\TimetableReaderTests.cs" />
6970
<Compile Include="Properties\AssemblyInfo.cs" />
7071
<Compile Include="TestFile.cs" />

0 commit comments

Comments
 (0)