Range Mapper

The RangeMapper provides a class which allows you to map from a configurable input range to a standardized output range of [-1,1].

API Reference

Header File

Classes

template<typename T>
class RangeMapper

Template class for converting a value from an uncentered [minimum, maximum] range into a centered output range (default [-1,1]). If provided a non-zero deadband, it will convert all values within [center-deadband, center+deadband] to be the configured output_center (default 0).

The RangeMapper can be optionally configured to invert the input, so that it will compute the input w.r.t. the configured min/max of the input range when mapping to the output range - this will mean that a values within the ranges [minimum, minimum+deadband] and [maximum-deadband, maximum] will all map to the output_center and the input center will map to both output_max and output_min depending on the sign of the input.

The RangeMapper can be optionally configured to invert the output, so that after converting from the input range to the output range, it will flip the sign on the output.

Example

    static constexpr float deadband = 12.0f;
    static constexpr float min = 0.0f;
    static constexpr float center = 127.0f;
    static constexpr float max = 255.0f;
    // Default will have output range [-1, 1]
    espp::RangeMapper<float> rm(
        {.center = center, .center_deadband = deadband, .minimum = min, .maximum = max});
    // You can explicitly set output center/range. In this case the output will
    // be in the range [0, 1024]
    espp::RangeMapper<float> rm2({.center = center,
                                  .center_deadband = deadband,
                                  .minimum = min,
                                  .maximum = max,
                                  .output_center = 512,
                                  .output_range = 512});
    // You can also use a non-centered input distribution.
    espp::FloatRangeMapper rm3({.center = center / 2,
                                .center_deadband = deadband,
                                .minimum = min,
                                .maximum = max,
                                .output_center = 512,
                                .output_range = 512});
    // You can even invert the ouput distribution, and add a deadband around the
    // min/max values
    espp::FloatRangeMapper rm4({
        .center = max,                      // test uni-directional mapping
        .center_deadband = deadband / 2.0f, // test different deadband around center / range
        .minimum = min,
        .maximum = max,
        .range_deadband = deadband,
        .invert_output = true,
    });
    // make a vector of float values min - 10 to max + 10 in increments of 5
    std::vector<float> vals;
    static constexpr float increment = deadband / 3.0f;
    static constexpr float oob_range = deadband * 3.0f;
    for (float v = min - oob_range; v <= max + oob_range; v += increment) {
      vals.push_back(v);
    }
    // ensure that very small values around center, max, and min are mapped to
    // 0, 1, and -1 respectively
    vals.push_back(center - 0.0001f);
    vals.push_back(center - 0.00001f);
    vals.push_back(center - 0.000001f);
    vals.push_back(center - std::numeric_limits<float>::epsilon());
    vals.push_back(center + 0.0001f);
    vals.push_back(center + 0.00001f);
    vals.push_back(center + 0.000001f);
    vals.push_back(center + std::numeric_limits<float>::epsilon());
    vals.push_back(max - 0.0001f);
    vals.push_back(max - 0.00001f);
    vals.push_back(max - 0.000001f);
    vals.push_back(max - std::numeric_limits<float>::epsilon());
    vals.push_back(max + 0.0001f);
    vals.push_back(max + 0.00001f);
    vals.push_back(max + 0.000001f);
    vals.push_back(max + std::numeric_limits<float>::epsilon());
    vals.push_back(min - 0.0001f);
    vals.push_back(min - 0.00001f);
    vals.push_back(min - 0.000001f);
    vals.push_back(min - std::numeric_limits<float>::epsilon());
    vals.push_back(min + 0.0001f);
    vals.push_back(min + 0.00001f);
    vals.push_back(min + 0.000001f);
    vals.push_back(min + std::numeric_limits<float>::epsilon());

    std::sort(vals.begin(), vals.end());

    // test the mapping and unmapping
    fmt::print(
        "% value, mapped [0;255] to [-1;1], unmapped [-1;1] to [0;255], mapped [0;255] to "
        "[0;1024], unmapped [0;1024] to [0;255], mapped [0;255] to [1024;0], unmapped [1024;0] to "
        "[0;255], mapped [0;255] to inverted [1;-1], unmapped inverted [1;-1] to [0;255]\n");
    for (const auto &v : vals) {
      fmt::print("{}, {}, {}, {}, {}, {}, {}, {}, {}\n", v, rm.map(v), rm.unmap(rm.map(v)),
                 rm2.map(v), rm2.unmap(rm2.map(v)), rm3.map(v), rm3.unmap(rm3.map(v)), rm4.map(v),
                 rm4.unmap(rm4.map(v)));
    }

Note

When inverting the input range, you are introducing a discontinuity between the input distribution and the output distribution at the input center. Noise around the input’s center value will create oscillations in the output which will jump between output maximum and output minimum. Therefore it is advised to use invert_input sparignly, and to set the values robustly.

Public Functions

inline RangeMapper()

Initialize the range mapper with no config.

inline explicit RangeMapper(const Config &config)

Initialize the RangeMapper.

Parameters:

config – Configuration describing the input distribution.

inline void configure(const Config &config)

Update the input / output distribution with the new configuration.

Note

The output range will be passed through std::abs() to ensure it is positive.

Note

The output range must be non-zero. If it is zero, the configuration will be ignored.

Parameters:

config – New configuration to use.

inline T get_center() const

Return the configured center of the input distribution.

Returns:

Center of the input distribution for this range mapper.

inline T get_center_deadband() const

Return the configured deadband around the center of the input distribution.

Returns:

Deadband around the center of the input distribution for this range mapper.

inline T get_minimum() const

Return the configured minimum of the input distribution.

Returns:

Minimum of the input distribution for this range mapper.

inline T get_maximum() const

Return the configured maximum of the input distribution.

Returns:

Maximum of the input distribution for this range mapper.

inline T get_range() const

Return the configured range of the input distribution.

Note

Always positive.

Returns:

Range of the input distribution for this range mapper.

inline T get_range_deadband() const

Return the configured deadband around the min/max of the input distribution.

Returns:

Deadband around the min/max of the input distribution for this range mapper.

inline T get_output_center() const

Return the configured center of the output distribution.

Returns:

Center of the output distribution for this range mapper.

inline T get_output_range() const

Return the configured range of the output distribution.

Note

Always positive.

Returns:

Range of the output distribution for this range mapper.

inline T get_output_min() const

Return the configured minimum of the output distribution.

Returns:

Minimum of the output distribution for this range mapper.

inline T get_output_max() const

Return the configured maximum of the output distribution.

Returns:

Maximum of the output distribution for this range mapper.

inline void set_center_deadband(T deadband)

Set the deadband around the center of the input distribution.

Note

The deadband must be non-negative.

Note

The deadband is applied around the center value of the input distribution.

Parameters:

deadband – The deadband to use around the center of the input distribution.

inline void set_range_deadband(T deadband)

Set the deadband around the min/max of the input distribution.

Note

The deadband must be non-negative.

Note

The deadband is applied around the min/max values of the input distribution.

Parameters:

deadband – The deadband to use around the min/max of the input distribution.

inline T map(const T &v) const

Map a value v from the input distribution into the configured output range (centered, default [-1,1]).

Parameters:

v – Value from the (possibly uncentered and possibly inverted - defined by the previously configured Config) input distribution

Returns:

Value within the centered output distribution.

inline T unmap(const T &v) const

Unmap a value v from the configured output range (centered, default [-1,1]) back into the input distribution.

Parameters:

T&v – Value from the centered output distribution.

Returns:

Value within the input distribution.

struct Config

Configuration for the input uncentered range with optional values for the centered output range, default values of 0 output center and 1 output range provide a default output range between [-1, 1].

Public Members

T center

Center value for the input range.

T center_deadband = 0

Deadband amount around (+-) the center for which output will be 0.

T minimum

Minimum value for the input range.

T maximum

Maximum value for the input range.

T range_deadband = 0

Deadband amount around the minimum and maximum for which output will be min/max output.

T output_center = 0

The center for the output. Default 0.

T output_range = 1

The range (+/-) from the center for the output. Default 1.

Note

Will be passed through std::abs() to ensure it is positive.

bool invert_output = false

Whether to invert the output (default false).

Note

If true will flip the sign of the output after converting from the input distribution.