From 97ac4933594cc886d135d0e22ddbe76763bb9d4a Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Tue, 4 Aug 2020 20:32:24 -0700 Subject: Add velocity gain option --- common/rawaccel.hpp | 70 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 474f2aa..1940014 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -76,11 +76,52 @@ namespace rawaccel { /// Tagged union to hold all accel implementations and allow "polymorphism" via a visitor call. using accel_impl_t = tagged_union; + struct velocity_gain_cap { + double hi = 0; + double slope = 0; + double intercept = 0; + bool cap_gain_enabled = false; + + velocity_gain_cap(double speed, accel_impl_t accel) + { + if (speed <= 0) return; + + double speed_second = 1.001 * speed; + double speed_diff = speed_second - speed; + if (speed_diff == 0) return; + cap_gain_enabled = true; + + double out_first = accel.visit([=](auto&& impl) { + double accel_val = impl.accelerate(speed); + return impl.scale(accel_val); + }).x * speed; + double out_second = accel.visit([=](auto&& impl) { + double accel_val = impl.accelerate(speed_second); + return impl.scale(accel_val); + }).x * speed_second; + + hi = speed; + slope = (out_second - out_first) / speed_diff; + intercept = out_first - slope * speed; + } + + inline double operator()(double speed) const { + return slope + intercept / speed; + } + + inline bool should_apply(double speed) const { + return cap_gain_enabled && speed > hi; + } + + velocity_gain_cap() = default; + }; + struct accel_fn_args { accel_args acc_args; int accel_mode = accel_impl_t::id; milliseconds time_min = 0.4; vec2d cap = { 0, 0 }; + double gain_cap = 0; }; /// Struct for holding acceleration application details. @@ -103,17 +144,26 @@ namespace rawaccel { /// The object which sets a min and max for the acceleration scale. vec2 clamp; + bool is_cap_gain = false; + + velocity_gain_cap gain_cap = velocity_gain_cap(); + accel_function(const accel_fn_args& args) { if (args.time_min <= 0) error("min time must be positive"); if (args.acc_args.offset < 0) error("offset must not be negative"); accel.tag = args.accel_mode; - accel.visit([&](auto& impl){ impl = { args.acc_args }; }); + accel.visit([&](auto& impl) { impl = { args.acc_args }; }); time_min = args.time_min; speed_offset = args.acc_args.offset; clamp.x = accel_scale_clamp(args.cap.x); clamp.y = accel_scale_clamp(args.cap.y); + + if (args.gain_cap > 0) { + is_cap_gain = true; + gain_cap = velocity_gain_cap(args.gain_cap, accel); + } } /// @@ -127,10 +177,20 @@ namespace rawaccel { double time_clamped = clampsd(time, time_min, 100); double speed = maxsd(mag / time_clamped - speed_offset, 0); - vec2d scale = accel.visit([=](auto&& impl) { - double accel_val = impl.accelerate(speed); - return impl.scale(accel_val); - }); + vec2d scale; + + if (gain_cap.should_apply(speed)) + { + double gain_cap_scale = gain_cap(speed); + scale = { gain_cap_scale, gain_cap_scale }; + } + else + { + scale = accel.visit([=](auto&& impl) { + double accel_val = impl.accelerate(speed); + return impl.scale(accel_val); + }); + } return { input.x * clamp.x(scale.x), -- cgit v1.2.3 From a6355fd785c6bf6c027f9fcab08bdb416641a40b Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Wed, 5 Aug 2020 01:15:15 -0700 Subject: Fix gain cap for positive offsets --- common/rawaccel.hpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'common') diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 1940014..297621b 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -82,7 +82,7 @@ namespace rawaccel { double intercept = 0; bool cap_gain_enabled = false; - velocity_gain_cap(double speed, accel_impl_t accel) + velocity_gain_cap(double speed, double offset, accel_impl_t accel) { if (speed <= 0) return; @@ -91,12 +91,13 @@ namespace rawaccel { if (speed_diff == 0) return; cap_gain_enabled = true; + // subtract offset for acceleration, like in accel_fn() double out_first = accel.visit([=](auto&& impl) { - double accel_val = impl.accelerate(speed); + double accel_val = impl.accelerate(speed-offset); return impl.scale(accel_val); }).x * speed; double out_second = accel.visit([=](auto&& impl) { - double accel_val = impl.accelerate(speed_second); + double accel_val = impl.accelerate(speed_second-offset); return impl.scale(accel_val); }).x * speed_second; @@ -144,8 +145,6 @@ namespace rawaccel { /// The object which sets a min and max for the acceleration scale. vec2 clamp; - bool is_cap_gain = false; - velocity_gain_cap gain_cap = velocity_gain_cap(); accel_function(const accel_fn_args& args) { @@ -159,11 +158,7 @@ namespace rawaccel { speed_offset = args.acc_args.offset; clamp.x = accel_scale_clamp(args.cap.x); clamp.y = accel_scale_clamp(args.cap.y); - - if (args.gain_cap > 0) { - is_cap_gain = true; - gain_cap = velocity_gain_cap(args.gain_cap, accel); - } + gain_cap = velocity_gain_cap(args.gain_cap, speed_offset, accel); } /// @@ -175,19 +170,20 @@ namespace rawaccel { inline vec2d operator()(const vec2d& input, milliseconds time) const { double mag = sqrtsd(input.x * input.x + input.y * input.y); double time_clamped = clampsd(time, time_min, 100); - double speed = maxsd(mag / time_clamped - speed_offset, 0); - + double raw_speed = mag / time_clamped; + vec2d scale; - if (gain_cap.should_apply(speed)) + // gain_cap needs raw speed for line to work + if (gain_cap.should_apply(raw_speed)) { - double gain_cap_scale = gain_cap(speed); + double gain_cap_scale = gain_cap(raw_speed); scale = { gain_cap_scale, gain_cap_scale }; } else { scale = accel.visit([=](auto&& impl) { - double accel_val = impl.accelerate(speed); + double accel_val = impl.accelerate(maxsd(mag / time_clamped - speed_offset, 0)); return impl.scale(accel_val); }); } -- cgit v1.2.3 From 9d321ad7087bc58332f990fdb13bea3d366ee0a6 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Wed, 5 Aug 2020 01:37:24 -0700 Subject: Further comments --- common/rawaccel.hpp | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 297621b..a2ed801 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -76,22 +76,45 @@ namespace rawaccel { /// Tagged union to hold all accel implementations and allow "polymorphism" via a visitor call. using accel_impl_t = tagged_union; + /// Struct to hold information about applying a gain cap. struct velocity_gain_cap { - double hi = 0; + + // The minimum speed past which gain cap is applied. + double threshold = 0; + + // The gain at the point of cap double slope = 0; + + // The intercept for the line with above slope to give continuous velocity function double intercept = 0; + + // Whether or not velocity gain cap is enabled bool cap_gain_enabled = false; + /// + /// Initializes a velocity gain cap for a certain speed threshold + /// by estimating the slope at the threshold and creating a line + /// with that slope for output velocity calculations. + /// + /// The speed at which velocity gain cap will kick in + /// The offset applied in accel calculations + /// The accel implementation used in the containing accel_fn velocity_gain_cap(double speed, double offset, accel_impl_t accel) { if (speed <= 0) return; + // Estimate gain at cap point by taking line between two input vs output velocity points. + // First input velocity point is at cap; for second pick a velocity a tiny bit larger. double speed_second = 1.001 * speed; double speed_diff = speed_second - speed; + + // Return if by glitch or strange values the difference in points is 0. if (speed_diff == 0) return; + cap_gain_enabled = true; - // subtract offset for acceleration, like in accel_fn() + // Find the corresponding output velocities for the two points. + // Subtract offset for acceleration, like in accel_fn() double out_first = accel.visit([=](auto&& impl) { double accel_val = impl.accelerate(speed-offset); return impl.scale(accel_val); @@ -101,17 +124,30 @@ namespace rawaccel { return impl.scale(accel_val); }).x * speed_second; - hi = speed; + // Calculate slope and intercept from two points. slope = (out_second - out_first) / speed_diff; intercept = out_first - slope * speed; + + threshold = speed; } + /// + /// Applies velocity gain cap to speed. + /// Returns scale value by which to multiply input to place on gain cap line. + /// + /// Speed to be capped + /// Scale multiplier for input inline double operator()(double speed) const { return slope + intercept / speed; } + /// + /// Whether gain cap should be applied to given speed. + /// + /// Speed to check against threshold. + /// Whether gain cap should be applied. inline bool should_apply(double speed) const { - return cap_gain_enabled && speed > hi; + return cap_gain_enabled && speed > threshold; } velocity_gain_cap() = default; @@ -174,7 +210,7 @@ namespace rawaccel { vec2d scale; - // gain_cap needs raw speed for line to work + // gain_cap needs raw speed for velocity line calculation if (gain_cap.should_apply(raw_speed)) { double gain_cap_scale = gain_cap(raw_speed); -- cgit v1.2.3 From 65a74b97c0c9ac8ca10312c0749e33df9e64b3d9 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Tue, 11 Aug 2020 23:06:39 -0700 Subject: Disallow differing x and y weights with gain cap --- common/accel-base.hpp | 2 ++ common/rawaccel.hpp | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/accel-base.hpp b/common/accel-base.hpp index 91510a4..60b7362 100644 --- a/common/accel-base.hpp +++ b/common/accel-base.hpp @@ -24,6 +24,7 @@ namespace rawaccel { double exponent = 2; double midpoint = 0; double power_scale = 1; + double gain_cap = 0; vec2d weight = { 1, 1 }; }; @@ -68,6 +69,7 @@ namespace rawaccel { /// Arguments to verified. void verify(const accel_args& args) const { if (args.accel < 0) bad_arg("accel can not be negative, use a negative weight to compensate"); + if (args.gain_cap > 0 && weight.x != weight.y) bad_arg("weight x and y values must be equal with a gain cap"); } accel_base() = default; diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index fc06731..8dc4825 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -160,7 +160,6 @@ namespace rawaccel { int accel_mode = accel_impl_t::id; milliseconds time_min = 0.4; vec2d cap = { 0, 0 }; - double gain_cap = 0; }; /// Struct for holding acceleration application details. @@ -196,7 +195,7 @@ namespace rawaccel { speed_offset = args.acc_args.offset; clamp.x = accel_scale_clamp(args.cap.x); clamp.y = accel_scale_clamp(args.cap.y); - gain_cap = velocity_gain_cap(args.gain_cap, speed_offset, accel); + gain_cap = velocity_gain_cap(args.acc_args.gain_cap, speed_offset, accel); } /// -- cgit v1.2.3