Krumeltee

-> Elektronik, Mikrocontroller und Retro-Computing <-

Generator für Sinus-Tabellen in C

Posted by krumeltee - 26. Dezember 2012

Ab und zu braucht man eine Sinus-Tabelle in seinem Programm um aufwendigem Berechnen zur Laufzeit zu entgehen. Hierfür habe ich mir mal dieses kleine Tool geschrieben.

Compiliert wird es ganz einfach mit „gcc -lm sintab_generator.c -o sintab_generator“. Die Maths-Library ist die einzige Abhängigkeit hierfür, die aber schon in der glibc bzw. Standard-C-Library mit drin steckt.

„./sintab_generator –help“ listet alle Möglichkeiten auf.
Ein Beispiel für eine 8-Bit Tabelle, nur Positive Zahlen (Signal-Null liegt bei Amplitude/2 und nicht bei 0), Amplitude Max. 255, 128 Werte:
„./sintab_generator -d 16 -A 0xff -l 128 -c“
Diese Tabelle könnte so von einem DA Wandler am AVR ausgegeben werden. Ein Einfacher DA-Wandler wäre z.B. nur ein Portpin+RC-Glied mittels PWM.

/* simple generator for sine tables to include in c code
 *
 * (c) 2012 nils stec
 *
 * license: GPL
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <sys/types.h>
#include <math.h>

#define DT_8            1
#define DT_16           2
#define DT_32           4
#define DT_DOUBLE       16
#define DT_SIGNED       0
#define DT_UNSIGNED     1

void help();
void gen_table(unsigned int len, unsigned int amplitude, int offset, int sign, int datatype, int comment);

int main(int argc, char **argv) {
        int i;

        unsigned int len = 32;
        unsigned int amp = 0;
        int off = 0;
        int sign = DT_SIGNED;
        int datatype = DT_8;
        int comment = 0;

        int itemp;
        unsigned long int ultemp;
        long int ltemp;
        unsigned int calc_temp;

        for(i = 0; i < argc; i++) {
                if(!(strcmp(argv[i], "-u"))) {          // only unsigned values
                        sign = DT_UNSIGNED;
                } else if( (!(strcmp(argv[i], "-h"))) || (!(strcmp(argv[i], "--help"))) ) {
                        help();
                        exit(0);
                } else if(!(strcmp(argv[i], "-c"))) {   // add comment
                        comment = 1;
                } else if(!(strcmp(argv[i], "-o"))) {   // offset DEC
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me an offset!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 10);
                        if(ltemp == 0) {
                                printf("\nzero-offset not allowed!\n\n");
                                exit(1);
                        }
                        off = (int)ltemp;
                } else if(!(strcmp(argv[i], "-a"))) {   // amplitude DEC
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me max. amplitude!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 10);
                        if(ltemp < 2) { 
                                printf("\namplitude negative or too small!\n\n");
                                exit(1);
                        }
                        amp = (unsigned int)ltemp;
                } else if(!(strcmp(argv[i], "-O"))) {   // offset HEX
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me an offset in hex!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 16);
                        if(ltemp == 0) {
                                printf("\nzero-offset not allowed!\n\n");
                                exit(1);
                        }
                        off = (int)ltemp;
                } else if(!(strcmp(argv[i], "-A"))) {   // amplitude HEX
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me max. amplitude in hex!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 16);
                        if(ltemp < 2) {   
                                printf("\namplitude negative or too small!\n\n");
                                exit(1);
                        }
                        amp = (unsigned int)ltemp;
                } else if(!(strcmp(argv[i], "-l"))) {   // length
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me the length!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 10);
                        if(ltemp < 2) {   
                                printf("\ntoo short!\n\n");
                                exit(1);
                        }
                        if((ltemp%2) != 0) {
                                printf("\nlen has to be a power of 2!\n\n");
                                exit(1);
                        }
                        len = (unsigned int)ltemp;
                } else if(!(strcmp(argv[i], "-d"))) {   // datatype
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me a datatype!\n\n");
                                exit(1);
                        }
                        ultemp = strtoul(argv[i+1], NULL, 10);
                        itemp = (int)ultemp;
                        switch(itemp) {
                                case 8:
                                        datatype = DT_8;
                                        break;
                                case 16:
                                        datatype = DT_16;
                                        break;
                                case 32:
                                        datatype = DT_32;
                                        break;
                                default:
                                        if(strcmp(argv[i+1], "double") == 0) {
                                                datatype = DT_DOUBLE;
                                        } else {
                                                printf("\nwrong datatype!\n\n");
                                                help();
                                                exit(1);
                                        }
                                        break;
                        }
                }

        }

        printf("\n");

        switch(datatype) {
                case DT_8:
                        ultemp = 0xff;
                        ltemp = 0xff;
                        break;
                case DT_16:
                        ultemp = 0xffff;
                        ltemp = 0xffff;
                        break;
                case DT_32:
                        ultemp = 0xffffffff;
                        ltemp = 0xffffffff;
                        break;
                case DT_DOUBLE:
                        break;
        }

        if(datatype != DT_DOUBLE) {
                if(off < 0) calc_temp = (unsigned int)off * -1;
                else calc_temp = (unsigned int)off;

                if((calc_temp+amp) > ultemp) {
                        printf("\ndatatype too small to hold your sine!\n\n");
                        exit(-1);
                }
        }
        gen_table(len, amp, off, sign, datatype, comment);
        return 0;
}

void help() {
        printf("c sine table generator 0.01 [(c) 2012, nils stec]\n\n");
        printf("  -d 8/16/32/double      datatypes: int8_t,int16_t,int32_t,double\n");
        printf("  -u                     force unsigned values (signal zero is at max_amplitude/2)\n");
        printf("  -o offset              offset DECIMAL\n");
        printf("  -O offset              offset HEX\n");
        printf("  -a max_amplitude       max amplitude DECIMAL\n");
        printf("  -A max_amplitude       max amplitude HEX\n");
        printf("  -l len                 length\n");
        printf("  -c                     add comment\n");
        return;
}

void gen_table(unsigned int len, unsigned int amplitude, int offset, int sign, int datatype, int comment) {
        double sine;
        int n, i;
        uint32_t table_entry;

        if(sign == DT_UNSIGNED) {                               // if we want unsigned data, we have to pull our sine higher than zero
                while((int)(offset-amplitude)<0) offset++;
        }

        if(comment) {
                printf("/* sine table, ");

                if(datatype != DT_DOUBLE) { 
                        printf("max amplitude %d, ", amplitude);
                        printf("offset %d, ", offset);
                }
                printf("%d entries, size in memory: %dbytes */\n", len, datatype*len);

        }

        if(datatype != DT_DOUBLE) {
                if(sign==DT_UNSIGNED) printf("u");
                switch(datatype) {
                        case DT_8:
                                printf("int8_t sine_table[%d] = {\n", len);
                                break;
                        case DT_16:
                                printf("int16_t sine_table[%d] = {\n", len);
                                break;
                        case DT_32:
                                printf("int32_t sine_table[%d] = {\n", len);
                                break;
                }

        } else printf("double sine_table[%d] = {\n", len);

        n = 0;
        while(n < len) {
                printf("");
                for(i = 0; i < 8; i++) {
                        sine = sin(2.0*M_PI*n/len);
                        switch(datatype) {
                                case DT_DOUBLE:
                                        printf("%f", sine);
                                        break;
                                default:
                                        table_entry = (sine*(double)amplitude)+offset;
                                        printf("%d", table_entry);
                                        break;
                        }
                        n++;
                        if(n < len) printf(", ");
                }
                printf("\n");
        }
        printf("};\n\n");
}

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

 
%d Bloggern gefällt das: