Forum: Mikrocontroller und Digitale Elektronik Welche Zwischenwerte verwenden?


von Vincent (vincentschmitt)


Lesenswert?

Hallo, ich habe eine Dampfdrucktabelle mit Stammwerten in definierten 
Abständen

Temp----------Sättigung
10"C  --------    12%
20"C  --------    19%
30°C  --------    ....

Der Zusammenhang ist nicht linear.

Was mache ich, wenn ich Zwischenwerte brauche - z.B. 23°C? Lege ich dann 
einen kubischen Spline zwischen die Werte?

von H. H. (Gast)


Lesenswert?


von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Vincent schrieb:
> Lege ich dann einen kubischen Spline zwischen die Werte?
Wenn die Kurve insgesamt einer 3. Potenz folgt wäre das ok. Für einen 
kleinen µC aber eben auch rechenaufwendig.

> Lege ich dann einen kubischen Spline zwischen die Werte?
Kommt drauf an, welche Abweichung du dir erlauben kannst und natürlich 
auch, wie zuverlässig der Messwert ermittelt worden ist bzw. werden 
kann.

Gerade bei Sachen mit Feuchtemesseung würde ich annehmen, dass du mit 
simpler linearer Interpolation da gut im tolerablen Rahemn landen wirst. 
Denn die Senosren gehenmigen sich da gern mal 5% Toleranz...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Vincent schrieb:
> Der Zusammenhang ist nicht linear.
>
> Was mache ich, wenn ich Zwischenwerte brauche - z.B. 23°C? Lege ich dann
> einen kubischen Spline zwischen die Werte?

Kann man machen.  Man muss allerdings die erste Ableitung an den 
Stützpunkten kennen.

Kubischer Spline für f über einem Invervall [a, b] hat 4 Kontrollpunkte:

(a, f(a)), (b, f(b)) und für die beiden anderen Kontrollpunkte gilt, 
dass deren x-Koordinaten das Intervall im Verhältnis 1:2 bzw. 2:1 teilen 
unanhängig von der darzustellenden Funktion.  Die y-Koordinaten 
ergeben sich dadurch, dass die Punkte auf Tangenten an f liegen:

Der Kontrollpunkt, dessen x-Koordinate näher bei a liegt, liegt auf der 
Tangenten durch (a, f(a)). Der andere Kontrollpunkt liegt dann auf der 
Tangenten durch (b, f(b)).

Auswertung geht zum Beispiel per deCasteljau

https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm

was die nette Eigenschaft hat, dass als Zwischenwerte nur x-Werte in [a, 
b] auftreten und nur y-Werte in [f(a), f(b)].

Dadurch ist die Rechnung frei von internen Überläufen und auch gut für 
Fixed-Point geeignet.

von Wolf17 (wolf17)


Lesenswert?

Sind die gerundeten Tabellenwerte das Ergebnis der genannten 
Clausius-Clapeyron-Gleichung, oder gibt es da noch andere 
Berechnungsformeln?

: Bearbeitet durch User
von Vincent (vincentschmitt)


Lesenswert?

Lothar M. schrieb:
> Gerade bei Sachen mit Feuchtemesseung würde ich annehmen, dass du mit
> simpler linearer Interpolation da gut im tolerablen Rahemn landen wirst.
> Denn die Senosren gehenmigen sich da gern mal 5% Toleranz

ok, das bedeutet dann, dass ich einfach linear zwischen den Punkten mit 
einfachem Dreisatz die Zwischenwerte berechnen kann, da die Genauigkeit 
der Sensoren eh so groß ist.

Danke für die vielen Tipps.

von Rainer W. (rawi)


Lesenswert?

Johann L. schrieb:
> (a, f(a)), (b, f(b)) und für die beiden anderen Kontrollpunkte gilt,
> dass deren x-Koordinaten das Intervall im Verhältnis 1:2 bzw. 2:1 teilen
> unanhängig von der darzustellenden Funktion.

Wo steht das? Was soll ein 2:1 geteiltes Intervall sein?

Kubische Splines funktionieren unabhängig davon, wie die Kontrollpunkte 
das Intervall teilen.
Allenfalls ist die von dir irgendwie etwas unklar beschriebene 
Anforderung an die Lage der Kontrollpunkte eine Beschränkung durch den 
verwendeten Algorithmus.

: Bearbeitet durch User
von Emil S. (Gast)


Lesenswert?

> ich einfach linear zwischen den Punkten mit
> einfachem Dreisatz die Zwischenwerte berechnen kann,

???Also oben schreibste das der Zusammenhang nicht-linear sei und unten 
lässte dir ne lineare Interpolation aufschwatzen?  -> Wieder ein 
Beispiel für kognitive Dissonanz.

Ausserden nützt eine Interpolationsformal relativ wenig, weil deren Wert 
gerundet werden muss, um nicht eine bessere Genauigkeit als an den 
gegebenen Stützstellen vorzugaukeln.



Vorschlag:
Mach eine LookUpTable bspw.
10°                                  20°
12%   13  14  14 15 15 16 17 18 18   19%

Unter der Annahme das die Temp. der Eingangswert ist, musste diesen erst 
auf den nächsten Wert runden (bspw.: 12.4 -> 12) und dann in die Tabelle 
schauen. Ungültige Eingangswerte werden mit einem Fehlercode quittiert.

Und natürlich solltest Du  mehr Stützstellen generieren, beispielsweise 
durch einen Kalibrierlauf. Oder durch Auswahl einer passenden 
Modell-Kennlinie.

von Rainer W. (rawi)


Lesenswert?

Emil S. schrieb:
> Ausserden nützt eine Interpolationsformal relativ wenig, weil deren Wert
> gerundet werden muss, um nicht eine bessere Genauigkeit als an den
> gegebenen Stützstellen vorzugaukeln.

Die Interpolationsformel mit dem richtige Modell kann auf dem kompletten 
Datensatz basieren und liefert damit bessere Werte, als jeder einzelne 
Messpunkt (Stichwort: Minimierung der Fehlerquadrate). Das Residuum darf 
rauschen.
Da muss nichts gerundet werden. Die Genauigkeit wird von den 
Sensorspezifikationen und den Messfehlern vorgegeben, nicht von der 
Wertetabelle.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rainer W. schrieb:
> Johann L. schrieb:
>> (a, f(a)), (b, f(b)) und für die beiden anderen Kontrollpunkte gilt,
>> dass deren x-Koordinaten das Intervall im Verhältnis 1:2 bzw. 2:1 teilen
>> unanhängig von der darzustellenden Funktion.
>
> Wo steht das?

Ergibt sich mit Papier und Bleistift:

Gegeben sei eine Funktion ƒ → R², ƒ(t) = (x(t), y(t)), die für t in [a, 
b] durch einen kubischen Bézier B anzunähern ist.  Eine Möglichkeit B 
festzulegen sind die Bedingungen:

* B(a) = ƒ(a)
* B(b) = ƒ(b)
* B'(a) || ƒ'(a)
* B'(b) || ƒ'(b)
* B"(a) || ƒ"(a)
* B"(b) || ƒ"(b)

wobei || für "parallel" steht.  Wählt man die Darstellung von B als 
4-Tupel von Kontrollpunkten, dann ergeben sich die Koordinaten der 
Kontrollpunkte als Lösung eines 4×4 linearen Systems. (Die ersten beiden 
Bedingungen ergeben unmittelbar P0 und P3.  Die letzten 4 Bedingungen 
ergeben  P1 und P2).

Möchte man lediglich ƒ → R approximieren, so hat man den Spezialfall 
x(t) = t mit x'=1 und x"=0; und für diesen Spezialfall ergibt sich die 
genannte Folgerung für die x-Koordinaten der Kontrollpunkte.  Zum 
Beispiel gilt P1.x = (2a + b) / 3, was das Intervall [a, b] im 
Verhältnis 1:2 teilt.

Unten als Beispiel in C99, wo sin(x) in [0, π/2] durch einen kubischen 
Spline interpoliert wird.  Die (betragsmäßig) größte Abweichung ergibt 
sich wie erwartet in der Mitte des Intervalls und liegt bei ca. 1%.  Zum 
Vergleich:  Taylor vom Grad 3 um 0 hat in π/2 eine Abweichung von 7.5%.

Die Ausgabe des Programms ist:
1
Approximiere sin in [0.00000, 1.57080]:
2
Alle y Zwischenergebnisse liegen in [+0.00000, +1.00000]
3
  0: (0.00000, 0.00000) @  0.00000%
4
  1: (0.09817, 0.09752) @ -0.05003%
5
  2: (0.19635, 0.19330) @ -0.17915%
6
  3: (0.29452, 0.28672) @ -0.35675%
7
  4: (0.39270, 0.37714) @ -0.55402%
8
  5: (0.49087, 0.46395) @ -0.74485%
9
  6: (0.58905, 0.54650) @ -0.90669%
10
  7: (0.68722, 0.62418) @ -1.02132%
11
  8: (0.78540, 0.69635) @ -1.07572%
12
  9: (0.88357, 0.76238) @ -1.06274%
13
 10: (0.98175, 0.82165) @ -0.98176%
14
 11: (1.07992, 0.87353) @ -0.83937%
15
 12: (1.17810, 0.91738) @ -0.64985%
16
 13: (1.27627, 0.95258) @ -0.43566%
17
 14: (1.37445, 0.97851) @ -0.22783%
18
 15: (1.47262, 0.99452) @ -0.06628%
19
 16: (1.57080, 1.00000) @  0.00000%

C99 Code
1
#include <math.h>
2
#include <stdio.h>
3
4
typedef struct
5
{
6
    double x0, x1, x2, x3;
7
    double y0, y1, y2, y3;
8
} spline_t;
9
10
// Sei g Gerade durch P0 = (x0,y0) mit Steigung m in P0.
11
// Berechne g(x).
12
static inline
13
double gerade (double x0, double y0, double m, double x)
14
{
15
    return y0 + m * (x - x0);
16
}
17
18
// Lineare Interpolation zwischgen a und b.
19
static inline
20
double mix (double a, double b, double t)
21
{
22
    return a + t * (b - a);
23
}
24
25
// Auswertung des Splines an der Stelle x = mix (a, b, t).
26
// Die Auswertung erfolgt nach dem Algorithmus von deCasteljau, was den Vorteil
27
// hat, dass Zwischenergebnisse immer im Intervall liegen, das durch min(y_i)
28
// und max(y_i) begrenzt wird.  Mit 6 Multplikationen und 12 Additionen ist der
29
// Aufwand allerdings höher als der der Auswertung eines kubischen Polynoms
30
// nach Horner mit 3 Multiplikationen und 3 Additionen.
31
// In der Praxis lässt sich der Aufwand um 3 Subtraktionen verringern, indem
32
// nicht nur die y-Koordinaten der Kontrollpunkte gespeichert werden sondern
33
// auch deren Differenzen y1-y0, y2-y1 und y3-y2.
34
double eval (const spline_t *s, double t)
35
{
36
    double y01 = mix (s->y0, s->y1, t);
37
    double y12 = mix (s->y1, s->y2, t);
38
    double y23 = mix (s->y2, s->y3, t);
39
40
    double y012 = mix (y01, y12, t);
41
    double y123 = mix (y12, y23, t);
42
43
    return mix (y012, y123, t);
44
}
45
46
static inline double min (double x, double y) { return x < y ? x : y; }
47
static inline double max (double x, double y) { return x > y ? x : y; }
48
49
typedef double (*func_t)(double);
50
51
// Approximiere f(x) in [a, b] an n+1 Stellen.  df ist die Ableitung von f.
52
void approx (const char *name, func_t f, func_t df, double a, double b, int n)
53
{
54
    double x1 = mix (a, b, 1.0/3.0);
55
    double x2 = mix (a, b, 2.0/3.0);
56
    spline_t spline =
57
    {
58
        // x-Koordinaten der Kontrollpunkte werden nicht gebraucht
59
        // und sind nur zur Vollständigkeit angegeben.
60
        .x0 = a, .x1 = x1, .x2 = x2, .x3 = b,
61
        // y-Koordinaten der Kontrollpunkte.
62
        .y0 = f(a),
63
        .y1 = gerade (a, f(a), df(a), x1),
64
        .y2 = gerade (b, f(b), df(b), x2),
65
        .y3 = f(b)
66
    };
67
68
    printf ("Approximiere %s in [%.5f, %.5f]:\n", name, a, b);
69
    printf ("Alle y Zwischenergebnisse liegen in [%+.5f, %+.5f]\n",
70
            min (min (spline.y0, spline.y1), min (spline.y2, spline.y3)),
71
            max (max (spline.y0, spline.y1), max (spline.y2, spline.y3)));
72
    for (int i = 0; i <= n; ++i)
73
    {
74
        double t = (double) i / n;
75
        double y = eval (&spline, t);
76
        double x = mix (a, b, t);
77
        printf ("% 3d: (%.5f, %.5f) @ % .5f%%\n", i, x, y, 100 * (y - f(x)));
78
    }
79
}
80
81
int main (void)
82
{
83
    double pi2 = acos (0.0); // pi / 2
84
    approx ("sin", sin, cos, 0.0, pi2, 16);
85
86
    // double x = pi2;
87
    // printf ("Taylor: %.5f%%\n", 100 * (x * (1 - x*x/6) - sin (x)));
88
    return 0;
89
}

In der Praxis wird man splint_t extern vorberechnen und als Konstante 
vorhalten.

> Kubische Splines funktionieren unabhängig davon, wie die Kontrollpunkte
> das Intervall teilen.

Die Kontrollpunkte selbst teilen das Intervall nicht, weil sie idR nicht 
auf der x-Achse liegen.  Alle Kontrollpunkte auf die x-Achse zu legen 
gäbe  ziemlich langweilige Funktionen.

> Allenfalls ist die von dir irgendwie etwas unklar beschriebene
> Anforderung an die Lage der Kontrollpunkte eine Beschränkung
> durch den verwendeten Algorithmus.

Es ist keine Anforderung and die Kontrollpunkte bzw. deren 
x-Koordinaten, sondern es ergibt sich diese Eigenschaft mit der 
spezielle Wahl ƒ(t) = (t, y(t)).

Im übrigen teilt x = (ua + vb) / (u + v) mit u ≥ 0, v ≥ 0, a ≤ b das 
Intervall [a, b] im Verhältnis v : u.  Wobei u und v nicht beide Null 
sein dürfen.  Ist umgekehrt x in [a, b] gegeben, dann teilt x das 
Intervall im Verhältnis x-a : b-x.

Beispielsweise teilt 7 das Intervall [5, 11] im Verhältnis 2:4 = 1:2.

: Bearbeitet durch User
von Emil S. (Gast)


Lesenswert?

> Da muss nichts gerundet werden. Die Genauigkeit wird von den
> Sensorspezifikationen und den Messfehlern vorgegeben, nicht von der
> Wertetabelle.

Mal Butter bei die Fische:
Wertpaar 1: 1, 10
Wertpaar 2: 4, 20

Was wäre die korrekte Ausgabe für einen linear Interpolierten Wert bei x 
= 3 ? :

? 16
? 16.6
? 16.7
? 16.66
? 16.67
..


Variante der Aufgabenstellung die beiden Wertepaare sein mit [1, 10.0] 
und [4, 20.0] gegeben.

Es geht halt nicht ohne Runden/Abschneiden auf die zulässige gültiger 
Anzeige-Ziffern,  es sei den das Ausgabegerät ist /dev/null ;-)

> Die Interpolationsformel mit dem richtige Modell kann auf dem kompletten
> Datensatz basieren und liefert damit bessere Werte, als jeder einzelne
> Messpunkt (Stichwort: Minimierung der Fehlerquadrate).

Nein, ein Modell ist nur eine Abstraktion, die einige Eigenschaften 
korrekt, aber andere falsch darstellt. Prominentes Beispiel: Drehung 
Merkur-Perihel. Die Astronomen vor Albert (bspw. 1855 Le Verrier) haben 
schon korrekt und lang genug gemessen, aber erst Albert konnte ihnen 
1915 sagen, das der Isaac den kleinen Term, der aus der 
Relativitätstheorie folgt, nicht auf dem Zettel hatte und deshalb das 
der Bahnberechnung tugrundeliegende Modell 'Murks' ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Die (betragsmäßig) größte Abweichung [mit kubischen Splines] ergibt
> sich wie erwartet in der Mitte des Intervalls und liegt bei ca. 1%.
> Zum Vergleich: Taylor vom Grad 3 um 0 hat in π/2 eine Abweichung
> von 7.5%.

Die Köningin der Approximation durch Polynome (oder rationale 
Funktionen) ist naturlich die MiniMax-optimierte Approximation, d.h. 
diese erfüllt nachweislich
und ist in diesem Sinne optimal.

Wermutstropfen ist dabei lediglich, dass solche Approximationen etwas 
aufwändiger zu bestimmen sind, während zur Bestimmung eines kubischen 
Splines Kenntnis von Funktionswert und Ableitung an den Stützstellen 
genügt.

Bevor ich den Code poste, hier wieder eine Approximation von sin in [0, 
π/2] bzw. die Ausgabe des Programms:
1
Approximiere sin in [0.00000, 1.57080]:
2
  0: (0.00000, -0.00137) @ -0.13671%
3
  1: (0.09817, 0.09850) @  0.04823%
4
  2: (0.19635, 0.19636) @  0.12742%
5
  3: (0.29452, 0.29159) @  0.13048%
6
  4: (0.39270, 0.38354) @  0.08522%
7
  5: (0.49087, 0.47156) @  0.01673%
8
  6: (0.58905, 0.55504) @ -0.05341%
9
  7: (0.68722, 0.63331) @ -0.10802%
10
  8: (0.78540, 0.70576) @ -0.13506%
11
  9: (0.88357, 0.77173) @ -0.12837%
12
 10: (0.98175, 0.83059) @ -0.08837%
13
 11: (1.07992, 0.88169) @ -0.02263%
14
 12: (1.17810, 0.92442) @  0.05356%
15
 13: (1.27627, 0.95811) @  0.11675%
16
 14: (1.37445, 0.98213) @  0.13489%
17
 15: (1.47262, 0.99586) @  0.06707%
18
 16: (1.57080, 0.99863) @ -0.13671%
19
Taylor: -7.51678%

Der absolute Fehler liegt bei weniger als 0.14%, was nochmals eine 
deutliche Verbesserung gegenüber dem kubischen Spline bedeutet, der 
einen Fehler von ca. 1% hat.

Kubische Splines sind m.E. hier etwas deplatziert: Sie dienen vor allem 
für optisch ansprechende Darstellungen und einfache Darstellung bzw. 
"Kontrolle" via Kontrollpunkte, sind aber im Sinne des resultierenden 
Approximationsfehlers nicht optimal.

Das Minimax-Polynom hingegen ist optimal, d.h. kein Polynom vom Grade 
höchstens 3 liefert bessere Ergebnisse (im Sinne des absoluten Fehlers, 
genommen über das Zielintervall).

Hier der Code, diesmal in GNU-C99 so dass M_PI verfügbar ist:
1
#include <math.h>
2
#include <stdio.h>
3
4
// Approximiere sin(x) in [0, pi/2].
5
double approx_sin_0_pi2 (double x)
6
{
7
    // Koeffizienten berechnet mit Remez-Algorithmus
8
    // für sin (x + pi/4) mit |x| <= pi/4.
9
    double a0 = +0.70575621;
10
    double a1 = +0.70601911;
11
    double a2 = -0.33577563;
12
    double a3 = -0.11250597;
13
    x -= M_PI / 4;
14
15
    // fma = float multiply-add: fma (x, y, z) = x * y + z.
16
    double y = a3;
17
    y = fma (y, x, a2);
18
    y = fma (y, x, a1);
19
    y = fma (y, x, a0);
20
    return y;
21
}
22
23
// Approximiere sin(x) in [0, pi/2] an n+1 Stellen.
24
void print_approx_sin (int n, double a, double b)
25
{
26
    printf ("Approximiere sin in [%.5f, %.5f]:\n", a, b);
27
28
    for (int i = 0; i <= n; ++i)
29
    {
30
        double t = (double) i / n;
31
        double x = a + t * (b - a);
32
        double y = approx_sin_0_pi2 (x);
33
        printf ("% 3d: (%.5f, %.5f) @ % .5f%%\n", i, x, y, 100 * (y-sin(x)));
34
    }
35
}
36
37
int main (void)
38
{
39
    double b = M_PI / 2;
40
    print_approx_sin (16, 0.0, b);
41
42
    printf ("Taylor: %.5f%%\n", 100 * (b * (1 - b*b/6) - sin (b)));
43
    return 0;
44
}

Anmerkung: Die Approximante ist zentriert auf das Zielintervall, so dass 
zur Berechnung nur x-Werte mit |x| ≤ (b-a)/2 auftreten statt a ≤ x ≤ b. 
Ziel ist, die auftretenden Zwischenergebnisse betragsmäßig möglichst 
klein zu halten.  Für double spielt das keine Rolle, für Fixed-Point 
aber durchaus schon.

von Rainer W. (rawi)


Lesenswert?

Johann L. schrieb:
> Die Köningin der Approximation durch Polynome (oder rationale
> Funktionen) ist naturlich die MiniMax-optimierte Approximation, d.h.
> diese erfüllt nachweislich

Die Königin der Approximation ist ein mathematisches Modell, dass die 
Physik hinter dem Sensor beschreibt und mit entsprechend wenig 
Parametern auskommt, meist nicht irgendein Polynom.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rainer W. schrieb:
> Johann L. schrieb:
>> Die Köningin der Approximation durch Polynome (oder rationale
>> Funktionen) ist naturlich die MiniMax-optimierte Approximation, d.h.
>> diese erfüllt nachweislich
>
> Die Königin der Approximation ist ein mathematisches Modell, dass die
> Physik hinter dem Sensor beschreibt und mit entsprechend wenig
> Parametern auskommt, meist nicht irgendein Polynom.

Die Dampdruckkurve ist doch gegeben und nur von der entsprechenden 
Flüssigkeit abhängig bzw. deren physikalischen Eigenschaften?

Die Abbildung ƒ: Temperatur → Sättigung ist also hinreichend genau 
bekannt.

Die Frage ist dann: Wie genau ist ƒ zu approximieren, wenn die 
Eingabedaten einen (Mess-)Fehler ΔT aufweisen? Und wie genau sind die 
Ergebnisse?

Wir haben

ƒ(T+ΔT) ≈ f(T) + ΔT·ƒ'(T)

und  |ƒ(x) - g(x)| ≤ M  also ist  ƒ(x) ≈ g(x) ± M  und

ƒ(T+ΔT) ≈ g(T) ± M + ΔT·ƒ'(T)

Bei einer sinnvolle Approximation sind beide Fehler in etwa von gleicher 
Größe(nordnung), also:

M ≈ ΔT·|max ƒ'|

und die Ergebnisse sind dann mit einem Fehler der Größenordnung

ΔSättigung ≈ 2·ΔT·|max ƒ'|

behaftet, wobei hier noch keine Rundungsfehler aufgrund endlicher 
Rechengenauigkeit beücksichtigt sind.

von Rainer W. (rawi)


Lesenswert?

Johann L. schrieb:
> Die Frage ist dann: Wie genau ist ƒ zu approximieren, wenn die
> Eingabedaten einen (Mess-)Fehler ΔT aufweisen? Und wie genau sind die
> Ergebnisse?

Welche Messfehler?
Der TO hat eine Tabelle, die (hoffentlich) auf hinreichend bekannten 
Stoffeigenschaften und einem zum Prozess passenden physikalischen Modell 
basiert. Daher ist davon auszugehen, dass die Fehler im Rahmen der 
Darstellungsgenauigkeit der Werte statistisch verteilt sind. Durch 
Approximation mit Minimierung der Fehlerquadrate bekommt man die 
Modellwerte also wieder erheblich genauer raus, als die Einzelwerte der 
Tabelle suggerieren.

von Emil S. (Gast)


Lesenswert?

> Welche Messfehler?
> Der TO hat eine Tabelle,

Man kann aber auch davon ausgehen, das der TO hat, was er zeigt.

Und er zeigt lediglich zwei Wertepaare und die Aussage, das der 
Zusammenhang nichtlinear ist.

Und da es sich um physikalisch messbare Größen handelt (Temperatur) sind 
diese wohl experimentell und nicht aus einem mathematischen Modell 
ermittelt worden.

von Rainer W. (rawi)


Lesenswert?

Emil S. schrieb:
> Man kann aber auch davon ausgehen, das der TO hat, was er zeigt.

Ich gehe davon aus, dass er deutlich mehr also dies zwei Wertepaar hat. 
Woher weiß er sonst, dass die Werte sich nichtlinear verhalten. Zeigen 
tut er diese Tabelle bisher nicht. Bei einer Dampfdrucktabelle würde ich 
außerdem eher Angaben von Temperatur und Druck erwarten.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Vielleicht klärt Vincent ersma darüber auf, ob es um eine Approximation 
geht oder um eine Interpolation.

von Joe L. (joelisa)


Lesenswert?

Pragmatische Lösung (da ich mir fast sicher bin, dass der TO mit dem 
gezeigten Formelwerk überfordert ist - und angesichts der Tatsache, dass 
die Sensorik eh mit Fehlern um die 5% daher kommt), würde ich good'old 
Excel bemühen und per Curve Fitting weitere Stütz-Werte erzeugen, wie 
z.B. in https://engineerexcel.com/nonlinear-curve-fitting-in-excel/ 
gezeigt.

Für den uC, also um die erzeugte Tabelle von Stütz-Werten 'anzuwenden', 
ergibt sich dann optimierter Code (Division wird vermieden), wenn man 
sich in der Anzahl der Stützstellen auf (2^n)+1, also  ..., 9, 17, 33, 
65, ... beschränkt.

Folgenden c-Code habe ich vor Urzeiten bei einem Projekt eingesetzt um 
die an einem NTC gemessenen Werte (adc_value) in eine Temperatur-Skala 
umzuwandeln.
1
int NTC_table[17] = {
2
  4982, 3866, 2930, 2409,
3
  2040, 1748, 1499, 1277,
4
  1071, 873, 677, 476,
5
  261, 19, -278, -710,
6
  -1454
7
};
8
9
10
/*
11
* Mit p1 und p2 werden die Stützpunkte direkt vor und nach dem
12
* ADC Wert ermittelt. Zwischen beiden Stützpunkten wird linear
13
* interpoliert. Der Code ist sehr klein und schnell.
14
* Es wird lediglich eine Ganzzahl-Multiplikation verwendet.
15
* Die Division kann vom Compiler durch eine Schiebeoperation
16
* ersetzt werden.
17
*
18
* \param    adc_value  Das gewandelte ADC Ergebnis - 10-bit
19
* \return              Die Temperatur in 0.0625 °C
20
*
21
*/
22
23
24
int NTC_ADC2Temperature(unsigned int adc_value){
25
 
26
  int p1, p2;
27
  unsigned int delta;
28
29
  /* Stützpunkt vor und nach dem ADC Wert ermitteln. */
30
  p1 = NTC_table[ (adc_value >> 4)  ];
31
  p2 = NTC_table[ (adc_value >> 4)+1];
32
 
33
  /* Zwischen beiden Punkten linear interpolieren. */
34
35
  delta =  (p1-p2) * (adc_value & 0x000F);
36
  return p1 - (delta >> 4);
37
};

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.