-
Notifications
You must be signed in to change notification settings - Fork 13.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix WMath's map() implementation for inverse/round-trip mapping #7027
Conversation
Here's the sketch for testing correctness and timing: uint32_t expired;
uint32_t iterations;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println("check map");
expired = 0;
iterations = 0;
}
constexpr int imin = 0;
constexpr int imax = 180;
constexpr int omin = 1000;
constexpr int omax = 2000;
int i = 0;
int fails = 0;
void loop()
{
++iterations;
i = (i + 1) % (imax + 1);
#if defined(ESP8266) || defined(ESP32)
cli();
volatile auto start = ESP.getCycleCount();
#else
// Set Timer 1 to normal mode at F_CPU.
TCCR1A = 0;
TCCR1B = 1;
cli();
volatile uint16_t start = TCNT1;
#endif
volatile auto o = map(i, imin, imax, omin, omax);
#if defined(ESP8266) || defined(ESP32)
sei();
volatile auto cycles = ESP.getCycleCount() - start;
#else
sei();
volatile uint16_t finish = TCNT1;
uint16_t cycles = finish - start;
#endif
expired += cycles;
if (i != map(o, omin, omax, imin, imax))
{
++fails;
}
if (iterations > 100000)
{
Serial.print("Cycles per map(...) = "); Serial.print(expired / iterations);
Serial.print(", fails = "); Serial.print(fails);
Serial.println();
expired = 0;
iterations = 0;
fails = 0;
}
} |
…ion. Greatly reduces error rate (half, or 0 zero errors, depends on in/out ranges) for round-trip mapping at the same performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
const long divisor = in_max - in_min; | ||
const long delta = x - in_min; | ||
|
||
return (delta * dividend + (divisor / 2)) / divisor + out_min; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't handle divisor == 0.
This today got merged into Arduino Core for ESP32, espressif/arduino-esp32#3655 |
Inspired by Servo.cpp's
improved_map
, this superseded that code, and has better performance (identical to prior WMath implementation).I expect this is better used to replace the core implementation, then drop "improved_map" from Servo.cpp, than keep it local and have a map() function that may be compatible but works horribly ;-)