pow Funktion ohne math.h auf Mikrocontroller in C umsetzen?



  • Nenn doch mal bitte die Umwandlungsformel!



  • Die Formel ist:

    Ausgabe=(Wert*0,00813)^(2,58482)

    Ausgabe sind dann die kg (also sollte z.b. 3,4 oder so werden) die ich haben möchte und Wert steht für die vom Sensorkommende Information (1V = 800 ...).



  • Gut, also nix mit Integer. Das heisst, dass dir der Weg ueber exp und log nicht erspart bleibt. Dazu brauchst du aber nicht math.h bzw. libm.so. Normalerweise gibt es den Quellcode fuer libm.so. Dort kopierst du dir einfach die entsprechenden Stellen heraus. Natuerlich kannst du auch eine optimierte Variante fuer deinen Microcontroller von exp und log programmieren. Die entsprechende Reihenentwicklung ist bei Wikipedia bzw. im Netz zu finden.



  • Ich würde das mit einer Lookup-Table machen.



  • @knivil Danke knivil, ich werde es mal probieren und mich hier nochmal melden wenn es erfolge gab.
    @bashar Da wüsste ich auch erstmal nicht wie ich es aufbaue und dann denke ich ist es auch doch sehr ungenau und was mach ich mit den Werten die nicht abgedeckt sind... .



  • Lineare Interpolation sollte reichen. Die Genauigkeit hängt davon ab, wie viele Stützstellen du hast.



  • Habe mal "nachgerechnet". Wenn du eine Lookup-Tabelle mit 42 Werten nimmst dann liegt der Fehler bei maximal -0.04. Bei 82 Werten bei max. -0.01. Bezieht sich jetzt auf einen Maximalwert von 800.



  • Wie könnte aber so eine Lookup Tabelle aussehen und vor allem verstehe ich noch nicht ganz wie mit Werten die nicht in der Tabelle zu finden sind umgegangen werden kann. Also jetzt auf das Beispiel:
    Ausgabe=(Wert*0,00813)^(2,58482)
    angewendet.
    Wenn ich angenommen (um es erstmal klein zu halten) 5 Werte vorher berechne:

    Wert=300 Ausgabe=10,0201
    Wert=700 Ausgabe=89,542
    Wert=800 Ausgabe=126,452
    Wert=900 Ausgabe=171,453
    Wert=1500 Ausgabe=225,123

    was mache ich wenn jetzt als Wert eine 850 kommt?



  • lineare interpolation



  • Wie gesagt, lineare Interpolation. Du müsstest die beiden nächstgelegenen Stützstellen finden, in dem Fall 800 und 900, und dann den gewichteten Mittelwert bilden. Bei 850 wäre das einfach (126,452 + 171,453)/2. Bei 840 wäre es 0,6*126,452 + 0,4*171,453.

    Wenn deine Stützstellen unregelmäßig angeordnet sind wie in deinem Beispiel, musst du erstmal irgendwie suchen, was die beiden nächstgelegenen Stellen sind, per binärer Suche zum Beispiel. Wenn sie äquidistant liegen, kannst du die Indizes auch einfach ausrechnen.



  • Danke für die Tips, hier scheint jetzt wieder das Problem zu sein, dass ich nicht so große Felder für sagen wir mal mit 100 Werten anlegen kann.
    Mein Code ist folgender:

    int get_value(int x)
    {
    /* NOTE: xs MUST be sorted */
    static const int xs[] = {0, 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600, 3800, 4000, 4200, 4400, 4600, 4800, 5000, 5200, 5400, 5600, 5800, 6000, 6200, 6400, 6600, 6800, 7000, 7200, 7400, 7600, 7800, 8000, 8200, 8400, 8600, 8800, 9000, 9200, 9400, 9600, 9800, 10000};
        static const int ys[] = {18, 18, 18, 19, 20, 21, 22, 24, 27, 30, 33, 38, 42, 48, 54, 60, 68, 76, 85, 95, 105, 116, 128, 141, 155, 170, 185, 202, 219, 237, 257, 277, 298, 321, 344, 369, 394, 421, 448, 477, 507, 538, 570, 603, 638, 674, 710, 749, 788, 828, 870};
    
        /* number of elements in the array */
        static const int count = sizeof(xs)/sizeof(xs[0]);
    
        int i;
        int dx, dy;
    
        if (x < xs[0]) {
            /* x is less than the minimum element
             * handle error here if you want */
            return ys[0]; /* return minimum element */
        }
    
        if (x > xs[count-1]) {
            return ys[count-1]; /* return maximum */
        }
    
        /* find i, such that xs[i] <= x < xs[i+1] */
        for (i = 0; i < count-1; i++) {
            if (xs[i+1] > x) {
                break;
            }
        }
    
        /* interpolate */
        dx = xs[i+1] - xs[i];
        dy = ys[i+1] - ys[i];
        return ys[i] + (x - xs[i]) * dy / dx;
    }
    

    Sobald ich die Felder mit mehr als 4 Werten fülle, kommt folgender Fehler:

    ?ASlink-Error-Could not get 534 consecutive bytes in internal RAM for area DSEG. at 1: warning 119: don't know what to do with file ' '. file extension unsupported make: *** [test.hex] Error 1 make: Target `all' not remade because of errors.

    Also ist scheinbar zuwenig zusammenhängender Speicher vorhanden. Wenn ich die beiden Felder aus der Funktion heraus verschiebe scheint es zu funktionieren. Allerdings scheint am Code etwas falsch zu sein, da jetzt immer ein gleicher Wert ausgegeben wird und nie ein der Spannung entsprechender.



  • "mit mehr als 4 Werten" heißt nichtmal

    static const int xs[] = {1, 2, 3, 4, 5};
    

    würde funktionieren? Das wären ja je nach Wortgröße gerade mal 20 oder 40 Bytes für xs und ys, hast du soviel nicht frei?



  • Naja ich glaube eher das er die daten im r/w bereich ablegt wenns in der funktion ist, anstatt im read-only bereich.
    Wenn ich die beiden xs und ys außerhalb der Funktion anlege, geht es. Aber irgendwas scheint mit der Lookup Tabelle selbst noch nicht zu funktionieren. Kannst du da einen Fehler entdecken?
    Vielen Dank schonmal für deine bisherige Hilfe Bashar und an die anderen.



  • Was stimmt denn nicht? Der Code sieht eigentlich OK aus.

    Naja ich glaube eher das er die daten im r/w bereich ablegt wenns in der funktion ist, anstatt im read-only bereich.

    Komischer Compiler, ich seh gar keinen Grund, bei static const zwischen globalen und funktionslokalen Variablen zu unterscheiden, aber gut zu wissen.



  • Das Problem ist, das diese Funktion aus irgendeinen Grund nicht zu funktionieren scheint. Lasse ich die Funktion weg, werden mir meine Werte in gewohnter Art augegeben. Sobald ich diese Werte der Funktion (siehe oben) übergebe, kommt egal welcher Druck anliegt immer ein konstanter Wert Wert raus.



  • Und welcher? Und was heißt "in gewohnter Art"? Das ist ein bisschen dürftig als Problembeschreibung ...



  • Sorry, mit gewohnter Art meine ich das eben Werte von wie 0, 1600 usw. ausgegeben werden. Also quasi die Werte von xs. Da mein Sensor aber keine konstante Kennlinie aufweist müssten diese Werte eigentlich mit einer Formel (die dann durch lookup Tabelle ersetzt wurde abgelöst wurde) umgerechnet und dann diese Werte ausgegeben werden.



  • Es läuft, danke ich hab den Fehler gefunden. Vielen Dank an alle Antworten von euch. 🙂



  • Könntest du auch schreiben was der Fehler (Lösung) war?
    Damit Andere mit dem selben fehler hier dann auch die Lösung finden.



  • Also den Code den ich hier gepostet habe, der funktioniert einwandfrei. Der Fehler lag in einer anderen Datei die mit dem hier besprochenen Problem nichts zu tun hatte.


Anmelden zum Antworten