Skip to content
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

Merged
merged 2 commits into from
Feb 9, 2020

Conversation

dok-net
Copy link
Contributor

@dok-net dok-net commented Jan 21, 2020

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 ;-)

@dok-net
Copy link
Contributor Author

dok-net commented Jan 21, 2020

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;
	}
}

@dok-net
Copy link
Contributor Author

dok-net commented Jan 21, 2020

…ion.

Greatly reduces error rate (half, or 0 zero errors, depends on in/out ranges) for round-trip mapping at the same performance.
Copy link
Collaborator

@earlephilhower earlephilhower left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@earlephilhower earlephilhower merged commit 56b90a2 into esp8266:master Feb 9, 2020
const long divisor = in_max - in_min;
const long delta = x - in_min;

return (delta * dividend + (divisor / 2)) / divisor + out_min;
Copy link
Collaborator

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.

@dok-net dok-net deleted the wmath_map branch February 13, 2020 12:21
@dok-net
Copy link
Contributor Author

dok-net commented Sep 30, 2020

This today got merged into Arduino Core for ESP32, espressif/arduino-esp32#3655

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants