changeset 0:0714c9003e6c draft

Initial commit
author Radomir Dopieralski <sheep-devel@sheep.art.pl>
date Wed, 21 Dec 2016 22:16:40 +0100
parents
children a56bbe3b03df
files .hgignore Makefile asin.py atan2.py imath.c imath.h main.c
diffstat 7 files changed, 352 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Wed Dec 21 22:16:40 2016 +0100
@@ -0,0 +1,17 @@
+syntax: glob
+*.pyc
+*~
+.*.swp
+*.o
+*.elf
+*.hex
+docs/*
+build/*
+dist/*
+bin/*
+lib/*
+include/*
+local
+*.egg-info
+cache/*
+*.DS_Store
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Wed Dec 21 22:16:40 2016 +0100
@@ -0,0 +1,72 @@
+DEVICE      = atmega328p
+CLOCK      = 16000000
+PROGRAMMER = -c usbasp
+OBJECTS    = main.o imath.o
+
+# for ATTiny85
+# see http://www.engbedded.com/fusecalc/
+#FUSES       = -U lfuse:w:0xe2:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
+#-U lfuse:w:0x62:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m 
+
+
+# Tune the lines below only if you know what you are doing:
+AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE)
+COMPILE = avr-gcc -std=gnu99 -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE)
+
+# symbolic targets:
+all:	main.hex
+
+.c.o:
+	$(COMPILE) -c $< -o $@
+
+.S.o:
+	$(COMPILE) -x assembler-with-cpp -c $< -o $@
+
+.c.s:
+	$(COMPILE) -S $< -o $@
+
+flash:	all
+	$(AVRDUDE) -U flash:w:main.hex:i
+
+fuse:
+	$(AVRDUDE) $(FUSES)
+
+# Xcode uses the Makefile targets "", "clean" and "install"
+install: flash fuse
+
+# if you use a bootloader, change the command below appropriately:
+load: all
+	bootloadHID main.hex
+
+clean:
+	rm -f main.hex main.elf $(OBJECTS)
+
+# file targets:
+main.elf: $(OBJECTS)
+	$(COMPILE) -o main.elf $(OBJECTS)
+
+main.hex: main.elf
+	rm -f main.hex
+	avr-objcopy -j .text -j .data -O ihex main.elf main.hex
+	avr-size --format=avr --mcu=$(DEVICE) main.elf
+# If you have an EEPROM section, you must also create a hex file for the
+# EEPROM and add it to the "flash" target.
+
+# Targets for code debugging and analysis:
+disasm:	main.elf
+	avr-objdump -d main.elf
+
+cpp:
+	$(COMPILE) -E main.c`gg
+
+deps:
+	$(COMPILE) -M main.c pwm.c >> Makefile
+imath.o: imath.c imath.h /usr/lib/gcc/avr/4.9.2/include/stdint.h \
+ /usr/lib/avr/include/stdint.h /usr/lib/avr/include/avr/pgmspace.h \
+ /usr/lib/avr/include/inttypes.h /usr/lib/gcc/avr/4.9.2/include/stddef.h \
+ /usr/lib/avr/include/avr/io.h /usr/lib/avr/include/avr/sfr_defs.h \
+ /usr/lib/avr/include/avr/portpins.h /usr/lib/avr/include/avr/common.h \
+ /usr/lib/avr/include/avr/version.h /usr/lib/avr/include/avr/fuse.h \
+ /usr/lib/avr/include/avr/lock.h
+main.o: main.c imath.h /usr/lib/gcc/avr/4.9.2/include/stdint.h \
+ /usr/lib/avr/include/stdint.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/asin.py	Wed Dec 21 22:16:40 2016 +0100
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import math
+
+def ANGLE(a):
+    return int(a * 10000.0 + 0.5)
+
+ATAN = [
+   ANGLE(45.000), # atan(1/1)
+   ANGLE(26.565), # atan(1/2)
+   ANGLE(14.036), # atan(1/4)
+   ANGLE( 7.125), # atan(1/8)
+   ANGLE( 3.576), # atan(1/16)
+   ANGLE( 1.790), # atan(1/32)
+   ANGLE( 0.895), # atan(1/64)
+   ANGLE( 0.448), # atan(1/128)
+   ANGLE( 0.224), # atan(1/256)
+   ANGLE( 0.112), # atan(1/512)
+   ANGLE( 0.056), # atan(1/1024)
+   ANGLE( 0.028), # atan(1/2048)
+]
+
+scale = 1 << 14
+mx = 0
+my = 0
+nx = 0
+ny = 0
+mv = 0
+nv = 0
+
+def asin(value):
+    global mx, my, nx, ny, mv, nv
+    result = 0
+    x = scale
+    y = 0
+    for i, atan in enumerate(ATAN):
+        if y < value:
+            for j in range(2):
+                tx = x
+                x -= y>>i
+                y += tx>>i
+            result += atan << 1
+        else:
+            for j in range(2):
+                tx = x
+                x += y>>i
+                y -= tx>>i
+            result -= atan << 1
+        mx = max(x, mx)
+        my = max(y, my)
+        nx = min(x, nx)
+        ny = min(y, ny)
+        value += value >> (i << 1)
+        mv = max(value, mv)
+        nv = min(value, nv)
+    return result
+
+
+for y in xrange(-scale, scale, scale >> 5):
+    iasin = float(asin(y))/10000
+    masin = math.degrees(math.asin(float(y)/scale))
+    print "y: %d, isin: %f, masin: %f, diff: %f" % (
+        y,
+        iasin,
+        masin,
+        iasin - masin,
+    )
+print "mx: %d, my: %d, log: %f" % (mx, my, math.log(max(mx, my), 2))
+print "nx: %d, ny: %d, log: %f" % (nx, ny, math.log(-min(nx, ny), 2))
+print "nv: %d, mv: %d" % (nv, mv)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atan2.py	Wed Dec 21 22:16:40 2016 +0100
@@ -0,0 +1,60 @@
+import math
+
+def ANGLE(a):
+    return int(a * 10000.0 + 0.5)
+
+ATAN = [
+   ANGLE(45.000), # atan(1/1)
+   ANGLE(26.565), # atan(1/2)
+   ANGLE(14.036), # atan(1/4)
+   ANGLE( 7.125), # atan(1/8)
+   ANGLE( 3.576), # atan(1/16)
+   ANGLE( 1.790), # atan(1/32)
+   ANGLE( 0.895), # atan(1/64)
+   ANGLE( 0.448), # atan(1/128)
+   ANGLE( 0.224), # atan(1/256)
+   ANGLE( 0.112), # atan(1/512)
+#   ANGLE( 0.056), # atan(1/1024)
+#   ANGLE( 0.028), # atan(1/2048)
+]
+
+scale = 1 << 14
+
+
+def atan2(y, x):
+    result = 0
+    if x == 0 and y == 0:
+        return 0
+    if y < 0:
+        x, y = -x, -y
+        result -= ANGLE(180)
+    if x < 0:
+        x, y = y, -x
+        result += ANGLE(90)
+    while x < scale and y < scale:
+        x <<= 1
+        y <<= 1
+    for i, atan in enumerate(ATAN):
+        if y > x>>i:
+            tx = x
+            x += y>>i
+            y -= tx>>i
+            result += atan
+    result += ATAN[-1] >> 1
+    return result
+
+
+md = 0
+for y in xrange(-100, 100):
+    for x in xrange(-100, 100):
+        iatan = float(atan2(y, x))/10000
+        matan = math.degrees(math.atan2(y, x))
+        print "x: %d, y: %d, iatan: %f, matan: %f, diff: %f" % (
+            x,
+            y,
+            iatan,
+            matan,
+            iatan - matan,
+        )
+        md = max(md, abs(iatan - matan))
+print md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imath.c	Wed Dec 21 22:16:40 2016 +0100
@@ -0,0 +1,115 @@
+#include "imath.h"
+#include <avr/pgmspace.h>
+
+
+#define ANGLE_SCALE 10 // how many units per degree
+#define ANGLE(a)    (int16_t)(((a) * ANGLE_SCALE) + 0.5)
+#define ITERATIONS  10
+#define SCALE       (1<<14)	// how many units per 1
+
+
+static const PROGMEM int16_t ATAN[ITERATIONS] = {
+    ANGLE(45.000),		// atan(1/1)
+    ANGLE(26.565),		// atan(1/2)
+    ANGLE(14.036),		// atan(1/4)
+    ANGLE(7.125),		// atan(1/8)
+    ANGLE(3.576),		// atan(1/16)
+    ANGLE(1.790),		// atan(1/32)
+    ANGLE(0.895),		// atan(1/64)
+    ANGLE(0.448),		// atan(1/128)
+    ANGLE(0.224),		// atan(1/256)
+    ANGLE(0.112),		// atan(1/512)
+ //   ANGLE(0.056),		// atan(1/1024)
+ //   ANGLE(0.028),		// atan(1/2048)
+};
+
+
+/*
+ * Takes two 16-bit signed integers and calculates atan2 for them.
+ * Returns a value from -1800 (for -180°) to 1800 (for 180°).
+ */
+int16_t iatan2(int16_t y, int16_t x) {
+    int16_t result = 0;
+    uint16_t tx, ux, uy;
+    uint8_t i = 0;
+
+    if (x == 0 && y == 0) {
+        return 0;
+    }
+    if (y < 0) {
+        x = -x;
+        uy = -y;
+        result -= ANGLE(180);
+    } else {
+        uy = y;
+    }
+    if (x < 0) {
+        ux = uy;
+        uy = -x;
+        result += ANGLE(90);
+    } else {
+        ux = x;
+    }
+    while (ux < SCALE && uy < SCALE) {
+        ux <<= 1;
+        uy <<= 1;
+    }
+    while (i < ITERATIONS) {
+        if (uy > ux>>i) {
+            tx = ux;
+            ux += uy >> i;
+            uy -= tx >> i;
+            result += pgm_read_word(&ATAN[i]);
+        }
+    }
+    return result + (pgm_read_word(&ATAN[i - 1]) >> 1);
+}
+
+/*
+ * Takes a number between -1<<14 and 1<<14 and returns an angle between
+ * -1800 (for -180°) and 1800 (for 180°).
+ */
+int16_t iasin(int16_t value) {
+    int16_t result = 0;
+    int16_t x = SCALE;
+    int16_t y = 0;
+    int16_t tx;
+
+    for (uint8_t i = 0; i < ITERATIONS; ++i) {
+        for (uint8_t j = 0; j < 2; ++j) {
+            tx = x;
+            if (y < value) {
+                x -= y>>i;
+                y += tx>>i;
+                result += pgm_read_word(&ATAN[i]);
+            } else {
+                x += y>>i;
+                y -= tx>>i;
+                result -= pgm_read_word(&ATAN[i]);
+            }
+        }
+        value += value >> (i << 1);
+    }
+    return value;
+}
+
+/*
+ * Takes a unsigned integer and returns nearest approximation of its square
+ * root.
+ */
+uint16_t isqrt(uint16_t value) { uint16_t result = 0; uint16_t bit = SCALE;
+
+    while (bit > value) {
+        bit >>= 2;
+    }
+    while (bit != 0) {
+        if (value >= result + bit) {
+            value -= result + bit;
+            result = (result >> 1) + bit;
+        } else {
+            result >>= 1;
+        }
+        bit >>= 2;
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imath.h	Wed Dec 21 22:16:40 2016 +0100
@@ -0,0 +1,10 @@
+#ifndef IMATH_H
+#define IMATH_H
+
+#include <stdint.h>
+
+int16_t iatan2(int16_t y, int16_t x);
+int16_t iasin(int16_t value);
+uint16_t isqrt(uint16_t value);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.c	Wed Dec 21 22:16:40 2016 +0100
@@ -0,0 +1,7 @@
+#include "imath.h"
+
+int main() {
+    int16_t a = iatan2(10, 10);
+    int16_t b = iasin(1<<12);
+    volatile int16_t x = isqrt(b);
+}