ich habe einen Sensor der nicht ganz linear ist und möchte nun 5 Punkte messen und für diese einen Kalibrierfaktor in einem Array hinterlegen.
Sprich das Messergebnis wird dann mit dem Faktor multipliziert.
Zwischen den einzelnen Kalibrierfaktorpunkten kann davon ausgegangen werden, dass es linear verläuft.
Beispiel:
Array beinhaltet: 0,9 / 1,1 / 1,3 / 1,1 / 0,7 // Nur zur demonstartion dass der Sensur nicht linear ist!
Wenn die Messung zwischen 0V und 1V liegt soll von Faktor 0,9 linear bis Faktor 1,1 multipliziert werden.
Wenn die Messung zwischen 1V und 2V liegt soll von Faktor 1,1 linear bis Faktor 1,3 multipliziert werden.
Wenn die Messung zwischen 1V und 2V liegt soll von Faktor 1,3 linear bis Faktor 1,1 multipliziert werden.
Wie bekomme ich das hin, dass ich nicht fix mit einem Faktor aus dem Array multipliziere sondern auch mit Zwischenwerten zwischen zwei Faktoren?
Also wie im ersten Fall bei 0,5V soll der Faktor 1 sein weil er mittig zwischen 0 und 1V liegt und der Faktor mittig zwischen 0,9 und 1,1 liegt .
Mittig ist natürlich nur ein Besipiel, das soll ja fließend sein.
Hallo,
mit einem einzelnen Faktor wird das nichts werden. Es wurde ja bereits gesagt du könntest fünf Geradengleichung für die 5 Bereiche nutzen. Dann benötigst Du 5 Faktoren und 5 offset Werte.
map geht natürlich auch , dann bekommst Du 5 map Anweisungen.
Um die 5 unterschiedlichen Bereiche trenne zu können kann man mit swich case ein Konstrukt aufbauen swich kann auch Bereiche abdecken. if ... else geht zur Not auch noch, allerdings fang dann mit den großen Werten an
switch(x) {
case 1 ... 5:
y=x*a[1]+b[1];
break;
case 6 ... 10:
y=x*a[2]+b[2];
break;
oder
if ( x > 8)
y=x*a[3]+b[3];
else(x > 5)
y=x*a[2]+b[2];
else(x > 3)
y=x*a[1]+b[1];
Noch eine ganz andere Variante. Du trägst die 5 Werte in eine Excell Tabelle ein und lässt dir eine xy Grafik dazu erstellen. Dazu kannst Du dir dann Trendlinien anzeigen lassen und die Funktion dazu .
Die Trendlinie kann linear oder auch eine höhere Ordnung haben. Es gibt da alles Mögliche Da kannst Du dann ein bisschen spielen was am besten geeignet ist. Die von Excell ausgegeben Gleichung baust Du dann in Deinen Sketch ein. Sie gilt dann mit einem kleinen Fehler für den gesamten Bereich.
in der Spalte A findest Du die Volt Angaben und in B die y Werte (y=Volt*Faktor) Das ergibt dann in dem xy Diagramm die blauen Messpunkte. Die blaue Linie stellt die Trendlinie mit der angegeben Gleichung dar.
eine Funktion 3 Ordnung ergibt genau die Messpunkte mit R2=1
Das mit den XY-Punkten in Excel oder libreOffice kann man auch mit viel mehr Punkten machen. Das kann (muss aber nicht ) einen R²-Wert geben der näher an 1 liegt.
Bei 5 Punkten mittlere Abweichung
Ich stelle hier auch immer gerne die Frage:
Um was geht es im Gesamtprojekt?
Wie genau müssen die Messwerte sein?
Wie lange sind die Sensorleitungen?
das sind ja wirklich sehr viele Information, dass muss ich ja erstmal alles verstehen bzw. auch ausprobieren.
Der Sensor misst eine Leistung über Ringkerne zur Auskopplung, was nur in der Theorie ganz linear ist. Da ist jeder Sensor etwas anders und genau deshalb soll ja kalibiert werden.
Daher ist die Idee bei bestimmten Punkten ein Soll vorzugeben und aus dem Ist dann den Faktor zu brechnen um dann mit den 5 Kalibrierpunkten ein stimmiges Ergebnis zu erhalten.
Es ist keine Laboranwendung, also soll es genauer sein als ohne Kalibrierung aber nicht aufs Millivolt genau.
Nochmals vielen Dank für eure Vorschläge!
Ich werde mir das ansehen, testen und werde nächstes WE mich dazu wieder melden.
Leider gehts bei mir immer nur am Wochenend.
Dann ist die Variante von mir oben die kürzeste.
Du legst für jeden eingemessenen Sensor ein Array an.
Fertig.
Je mehr Messpunkte, desto genauer.
Wenn Du zwischen zwei Messpunkten eine lineare Abweichung hast, ist das vollkommen ausreichend.
Ist nachher in der Anwendung nur ein Sensor oder sind da mehrere angeschlossen?
Der schlimmste Fehler ist es, dafür "Eichung" zu benutzen.
Evtl. moch als Ergänzung: Das Normal sollte (je nach Anwendung) wenigstens 1 Klasse in der Genauigkeit besser sein, als das zu kalibrierende Gerät.
Eichen darf ja nur das Eichamt , insofern ist kalibrieren schon richtig. Man könnte es sicher auch noch als Linearrisieren bezeichnen.
Übrigens wenn man den ersten Bereich auf 0.5 ändert erinnert mich die Kurve 3. Ordnung an eine typische Magnetisierungs Kennlinie.Und das kann bei einem Stromwandler ja auch gut der Fall sein.
Lineare Interpolation bei wenigen Stützpunkten führt unter Umständen zu einem ziemlich eckigen Verlauf, was wiederum dem natürlichen Sensor Verlauf widersprechen könnte. Wenn ich mir die Trendlinie 3 Ordnung ansehe , und da die Stützpunkte durch Gerade verbinden würde gibt's da schon ziemliche Unterschiede.
Das berechnen von irgendwelchen Faktoren ist mir zu umständlich.
Wenn Du 5 Kalibrierpunkte hast, dann sind das die Werte, denen Du GENAU einen entsprechenden Wert aus einer Tabelle zuordnen kannst.
Was mir dabai auffällt, dass Du versuchst mit dem Ergebnis zu rechnen. Ich nehme dafür die Rohdaten des ADC.
constexpr byte readPins[] {A0}; // Hier die PIN eintragen, an denen gemessen wird
constexpr byte sensorZahl {sizeof(readPins) / sizeof(readPins[0])};
unsigned int reading[sensorZahl];
constexpr unsigned int sollWert[] {0, 300, 600, 900, 1023}; // Schnittwerte SOLL 0 und 1024 müssen bleiben
constexpr byte sollNum {sizeof(sollWert) / sizeof(sollWert[0])};
constexpr unsigned int adcWert[sollNum] {0, 310, 550, 920, 1023}; // tatsächlichen Messwerte, die dem sollwert zugeordnet werden
constexpr byte referenceVoltage {5}; // Volt :)
constexpr uint16_t resolution {1024};
//
void setup()
{
Serial.begin(115200);
Serial.println(F("Start..."));
}
//
void loop(void)
{
readSensors ();
rechneSensors();
delay(200);
}
//
void simulation(const byte b)
{
reading[b]++;
if (reading[b] > 1024)
{ reading[b] = 0; }
}
//
void readSensors()
{
for (byte b = 0; b < sensorZahl; b++)
{
// reading[b] = analogRead(readPins[b]);
simulation(b);
}
}
//
void rechneSensors()
{
Serial.print(F("gelesener Wert / zugeordneter Wert / Voltage errechnet: "));
for (byte b = 0; b < sensorZahl; b++)
{
Serial.print(reading[b]);
Serial.print('\t');
Serial.print(calibrate(reading[b]));
Serial.print('\t');
Serial.print(static_cast<float>(calibrate(reading[b]))*referenceVoltage / resolution, 4);
Serial.println(F(" Volt"));
}
}
int calibrate(const uint16_t analogWert)
{
for (byte b = 0; b < sollNum; b++) // Abfrage des gesamten adcarray
{
if (analogWert == adcWert[b]) // Vergleich auf genau den Wert
{
return sollWert[b]; // gebe passenden Arraywert zurueck
}
else if (analogWert < adcWert[b]) // Messwert liegt unter dem nächsten adcWert
{
return map(analogWert, adcWert[b - 1], adcWert[b], sollWert[b - 1], sollWert[b]);
}
}
return -1; // analogWert hat nicht gepasst!
}
Im Array adcWert[sollNum]' musst Du dann Deine realen Messpunkte eintragen und in sollWert[]`die dazu gehörigen Umrechnungswerte.
In readSensors() ist das lesen jetzt simuliert - wenn Du die obere Zeile ein- und die da drunter auskommentierst, kannst mit realen Werten arbeiten.