From 5ebb70af7e743196a05352255cd44c83f535d16b Mon Sep 17 00:00:00 2001 From: mariborges22 Date: Wed, 25 Mar 2026 16:20:05 -0300 Subject: [PATCH] feat(tests): add continuity tests for Synchronous mode --- wrapper-tests/SynchronousAccelTests.cs | 79 +++++++++++++++++++++++++- wrapper-tests/wrapper-tests.csproj | 2 +- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/wrapper-tests/SynchronousAccelTests.cs b/wrapper-tests/SynchronousAccelTests.cs index 701db6c7..04c508dd 100644 --- a/wrapper-tests/SynchronousAccelTests.cs +++ b/wrapper-tests/SynchronousAccelTests.cs @@ -70,8 +70,85 @@ public void GivenSpeeds_SynchronousAccelWithNonDefaultSmooth_YieldsCorrectSens() Assert.AreEqual(expectedOutput, output.Item1, expectedOutput * 0.0001); } } + [TestMethod] + public void SynchronousAccel_ThresholdCrossing_IsContinuous() + { + double syncSpeed = 20; + double gamma = 0.5; + double motivity = 1.3; + + // smooth = 0.03125 exactly results in sharpness = 16 + double[] smoothValues = { 0.03126, 0.03125, 0.03124, 0.0 }; + + foreach (double smooth in smoothValues) + { + var profile = new Profile(); + profile.outputDPI = 1000; + profile.argsX.mode = AccelMode.synchronous; + profile.argsX.gain = false; + profile.argsX.syncSpeed = syncSpeed; + profile.argsX.gamma = gamma; + profile.argsX.motivity = motivity; + profile.argsX.smooth = smooth; + + var accel = new ManagedAccel(profile); + var pureSimulator = new UnclampedSynchronousSimulator(syncSpeed, motivity, gamma, smooth); + + for (int input = 1; input < 100; input += 5) + { + Tuple output = accel.Accelerate(input, 0, 1, 10); + + double inputSpeed = (double)input / 10.0; + double expectedOutput = (double)input * pureSimulator.Accelerate(inputSpeed); + + double delta = Math.Abs(output.Item1 - expectedOutput); + double relativeError = delta / expectedOutput; + + Assert.IsTrue(relativeError < 0.001, + $"Discontinuity found at smooth={smooth}, input={input}. " + + $"Driver: {output.Item1}, Pure Math: {expectedOutput}, Error: {relativeError:P}"); + } + } + } + } + + /// + /// A simulator that follows the raw math WITHOUT the sharpness >= 16 optimization. + /// + public class UnclampedSynchronousSimulator + { + public UnclampedSynchronousSimulator(double syncSpeed, double motivity, double gamma, double smooth) + { + SyncSpeed = syncSpeed; + Motivity = motivity; + Gamma = gamma; + Sharpness = smooth <= 0 ? 100 : 0.5 / smooth; + } - } + public double SyncSpeed { get; } + public double Motivity { get; } + public double Gamma { get; } + public double Sharpness { get; } + + public double Accelerate(double inputSpeed) + { + if (inputSpeed == SyncSpeed) return 1.0; + + double logSyncSpeed = Math.Log(SyncSpeed); + double logMotivity = Math.Log(Motivity); + double gammaConst = Gamma / logMotivity; + + double logX = Math.Log(inputSpeed); + double logDiff = logX - logSyncSpeed; + + double logSpace = Math.Abs(gammaConst * logDiff); + double exponent = Math.Pow(Math.Tanh(Math.Pow(logSpace, Sharpness)), 1 / Sharpness); + + exponent *= Math.Sign(logDiff); + + return Math.Exp(exponent * logMotivity); + } + } /// /// Contains definition of how synchronous accel is expected to accelerate inputs diff --git a/wrapper-tests/wrapper-tests.csproj b/wrapper-tests/wrapper-tests.csproj index d3032755..f24956cc 100644 --- a/wrapper-tests/wrapper-tests.csproj +++ b/wrapper-tests/wrapper-tests.csproj @@ -1,4 +1,4 @@ - +