Hallo alle, habe ein nicht lineares Signal(5%-Nichtlinearität) von einem Hallsensor. Muss es linearisieren, nach der Berechnung der linearen Regression durch Excel habe ich folgende Gleichung bekommen: Ysoll = 1,2311x + 111. so schreibe ich sie im Prog.: Lin_current_value_x =((val_x*123110L)/10) und es lässt sich rechnen. Problem jetzt, dass obwohl ich dies gemacht habe wird nichts linearisiert! in Anhang findet ihr Ergebnisse vor und nach Linearisierung. Danke im Voraus!
Bei dem Signalverlauf wirst du auch mit einer linearen Regression nicht weit kommen. Der Verlauf ist noch nicht mal annähernd eine Gerade. Eine Parabel (also eine Kurve 2. Grades) passt schon eher, aber wahrscheinlich wird es auf ein Polynom 3. Grades hinauslaufen.
entschuldigt, das was ich dargestellt habe war die Abweichung, so sehen meine U ist und soll:
oder weiß jemand wie ich es durch eine look up Tabelle linearisieren kann? Ich weiß grob daß man den Interval in kleinen Intervale, wo es gleiche Steigung herrscht, teilen muß. und dann werden sie einfach aufgerufen in einem Array. Aber genau um dies zu realisieren brauche ich eine C- Code. Kann jemand vielleicht helfen?
Mit Excel kannst Du Dir das Polynom generieren lassen. Du must die Werte deine Kurve alle in eine Tabelle hacken und eine Kurve daraus generieren. So wie ich das sehe, hast Du genau das schon gemacht. Im Kontextmenu der Grafik (oder war es doch in einem anderen Menu?) dann mal nach Trendlinie schauen. Die wird dann angelegt und die Formel dazu ist genau das Polynom, das Du für Deine Kurve benötigst. Funktioniert prima. Nur genauer beschreiben kann ich es aus dem Kopf gerade nicht.
So ich hab es nochmal ausprobiert. Du must den Grafen mit der Maus markieren (anklicken). Dann dazu das Kontextmenu aufmachen (rechter Mausklick). Dort "Trendlinie hinzufügen" wählen. Da dann "Polynomisch" (Reihenfolge ist der Grad des Polynoms 2 oder 3 sollte passen) und unter Optionen "Gleichung im Diagramm darstellen" anwählen. Danach hast Du alles was Du brauchst.
Hi, Danke für die nette Hilfe! das ist nicht Frage der Erstellung der Gleichung. ich will eigentlich einen c-Code der mir die Sache erledigt. Look- up table zu erstellen ist mein eigentliches Problem: wie erstellen, welche werte zuweisen, woher weiß ich welche werte bei mir passen werden..uzw.
Abderrahim wrote: > Hi, > Danke für die nette Hilfe! > das ist nicht Frage der Erstellung der Gleichung. > ich will eigentlich einen c-Code der mir die Sache > erledigt. > Look- up table zu erstellen ist mein eigentliches Problem: > wie erstellen, welche werte zuweisen, woher weiß ich welche werte bei > mir passen werden..uzw. Lookup Tabelle willst du ja gerade umgehen. Das ist ja der Sinn der linearen Regression: Die ganze Tabellengeschichte bzw. die Daten durch eine Gerade ersetzen, die den gleichen Zusammenhang möglichst gut wiedergibt. In deinem Fall hast du den y Wert von Sensor und möchtest wissen welchem x-Wert der entspricht. Also gehst du mit dem Sensor Wert in die Umkehrung deiner Gleichung rein und erhältst den x-Wert dazu. Natürlich stimmt der nicht exakt mit deinem gemessenen Wert überein. Die Ausgleichsgerade, die du mittels linearer Regr. erhalten hast, ist ja nur eine 'Best Fit' Gerade. Aber dafür hast du einen einfachen Rechengang, der dir aus dem y-Wert einen x-Wert berechnet, ohne dass du viel Platz für irgendwelche Tabellen benötigst.
>In deinem Fall hast du den y Wert von Sensor und möchtest >wissen welchem x-Wert der entspricht. Also gehst du mit >dem Sensor Wert in die Umkehrung deiner Gleichung rein >und erhältst den x-Wert dazu. nein, das ist nicht der Fall. ich möchte eigentlich y-Werte (entsprechen Hallspannung) zu einer Funktion geben, damit ich am Ende einen Winkel genau berechne.
Was willst du genau erreichen? Beschreib doch mal! Ich komme immer mehr zu der Überzeugung, dass du mit dem falschen Werkzeug versuchst ein Problem zu lösen, von dem niemand weiß, was denn das eigentliche Problem ist. Das ist jetzt nicht böse gemeint: Versuche möglichst deutsche Sätze zu verwenden. Aus einem Kauderwelsch wird niemand schlau.
ich möchte eine hochauflösende Positionserfassung mit meinem ratiometrischen Hallsensor(Allegro 1381) erreichen. Direkt von meinem Hallsensor bekomme ich ein analoges Signal. Dieses Signal ist nicht 100% linear. deshalb versuche ich diese Nichtlinearität(momentan 5%) mit einem uC zu verbessern. Ich hoffe ich konnte dir ein klares Bild über mein Ziel geben. Gruß
Also, wie bereits von anderen erwähnt: Die Linearisierung mit Regression ist eigentlich dafür, dass Du Dir eine Lookup-Table sparen kannst. Du implementierst stattdessen die Gleichung x = m*y + t. (x = Winkel, y=Eingabewert) Ne Lookup-Table schaut z,.B so aus: uint8_t lookup[255] { 1, 2, 3, 5, 6, 8, 9 , 10 , ... }; und Verwendet so: x = lookup[y]; Vorteil der ersten Methode ist, dass die klein ist, die zweite ist sehr groß braucht aber kaum Rechenzeit. Eine lineare Regression wird den Fehler größtenteils umverteilen. Die Fehlerfläche wird kleiner, jedoch nicht optimal. Probier mal ne quadratische oder kubische aus. PS www.zunzun.com Hier kannst du mit den einzelenen Ausgleichsrechnungen experimentieren, und der gibt auch noch nette Abschätzungen zu den Fehlern ab. PPS:
PPS [cont] Du hast doch schon Werte aufgenommen. Diese wären doch die Grundlage für die Loouptable, oder?
Ja, ich habe Werte aufgenommen, aber sie zeigen keine gute Linearität. Bild davon siehst du oben. ich sage dir was ich so von der look up Table verstehe, und korrigiere mich bitte wenn ich mich irre: Ich schreiben in einem Array die schlechten Werte(z.B. 71 Wert), die grosse Abweichung verursachen, und werden sie von Werten in einem anderen Array gewechselt: dword Array-soll[],Array-ist[]; for(i=0;i<71;i++) {Array-soll[i]=Array-ist[i];} Gruß
Abderrahim wrote: > Ich schreiben in einem Array die schlechten Werte(z.B. 71 Wert), die > grosse Abweichung verursachen, und werden sie von Werten in einem > anderen Array gewechselt: > Nein. Es gibt 2 Möglichkeiten Möglichkeit 1: Du hast nur 1 Array. Dein schlechter Wert ist Index in dieses Array und aus dem Array kriegst du an dieser Position den guten Wert. Bsp: Deine Werte seien: 10, 20, 30 Jetzt weist du, dass du bei einem Wert von 10 eigentlich 8 haben müsstest. Bei einem Wert von 20 wäre der korrekte Wert 21 und bei 30 sollte eigentlich 29 rauskommen. Das nächste Problem ist, dass du eine Umrechnung von deinen gemessenen Werten zu Array-Indizes brauchst. Du musst also die Werte 10, 20, 30 irgendwie auf 0, 1, 2 umrechnen. Durch scharfes hinschauen erkennst du, dass das genau dann der Fall ist, wenn du vom Wert 10 abziehst und durch 10 dividierst (Man kann das auch mathematisch ableiten :-) Also:
1 | int GoodValues[] = { 8, 21, 29 }; |
2 | |
3 | Value = GoodValues[ ( BadValue - 10 ) / 10 ]; |
Das Problem an dieser Version ist, dass du eine Umrechnungsformel von den schlechten Werten zu den Array Indizes brauchst. Das kann der Fall sein, es kann aber auch sein, dass es keine vernünftige Formel gibt. Möglichkeit 2: Wenn Möglichkeit 1 wegen einer fehlenden vernünftigen Index-Umrechnung ausfällt, kann man immer noch Plan B anwenden. Angenommen deine bekannten Umrechnungswerte sehen so aus Messwert linearisierter Wert -------------------------------------- 10 8 23 24 38 35 Man baut sich eine Struktur, die den schlechten Wert mit dem guten Wert gruppiert
1 | struct Value { |
2 | int Bad; |
3 | int Good; |
4 | };
|
Daraus wird jetzt das Umrechnungsarray generiert
1 | struct Value Table[] = |
2 | {
|
3 | { 10, 8 }, |
4 | { 23, 24 }, |
5 | { 38, 35 } |
6 | };
|
Wie wird jetzt die Umrechnung gemacht? Ganz einfach: Du gehst mit dem gemessenen Wert in das Array und suchst nach der korrekten Zeile.
1 | int Correct( int Value ) |
2 | {
|
3 | int i; |
4 | |
5 | for( i = 0; i < 3; ++i ) |
6 | if( Table[i].Bad == Value ) |
7 | return Table[i].Good; |
8 | |
9 | return 0; |
10 | }
|
Das bisherige funktioniert nur dann, wenn es für jeden möglichen schlechten Messwert eine entsprechende Zeile in der Tabelle gibt. Im Beispiel wäre das: Es können nur die Messwerte 10, 23 und 38 auftreten. Das wird man unter Umständen so nicht haben. Was macht man dann? Nun dann kann man immer noch linear interpolieren. Wenn der korrekte Wert bei 10 8 lautet, und der korrekte Wert bei 23 auf 24 kommt, dann berechnet sich der korrekte Wert für zb 18 zu: y = k * x + d // die allgemeine lineare Gleichung // du musst k und d bestimmen // also wird mal für die bekannten Werte // eingesetzt 8 = k * 10 + d 24 = k * 23 + d // daraus kann man nun k und d bestimmen // erste Gleichung von der 2.ten abziehen 16 = k 23 - k 10 // k herausheben 16 = k * ( 23 - 10 ) // und durchdividieren k = 16 / 13 k = 1.2307 // damit kennen wir k // dieses k in eine der beiden Ursprungs- // gleichungen einsetzen und d bestimmen 8 = 1.2307 * 10 + d 8 = 12.307 + d 8 - 12.307 = d -4.307 = d Die Umrechnungsformel in diesem Abschnitt ( 10 -> 8, 23 -> 24 ) lautet also: y = 1.2307 * x - 4.307 (Zur Kontrolle: für 10: y = 1.2307 * 10 - 4.307 = 8 stimmt für 23: y = 1.2307 * 23 - 4.307 = 23.991 stimmt auch ) Für einen Messwert von 18 ergibt sich also ein korregierter Wert von y = 1.2307 * 18 - 4.307 = 17.8456 Die Strategie sieht dann so aus: Mit deinem gemessenen Wert, suche in der Tabelle nach dem unmittelbar kleinerem Bad-Wert, dem unmittelbar größeren Bad-Wert und interpoliere dazwischen linear. Da die Tabelle nach aufsteigendem Bad-Wert sortiert ist, genügt es, den Eintrag zu finden, der gerade kleiner als der gemessene Wert ist. Der nächst größere ist dann einfach der nächste Index.
1 | int Correct( int Value ) |
2 | {
|
3 | int i; |
4 | int Index = -1; |
5 | double k, d; |
6 | |
7 | for( i = 0; i < 3; ++i ) // 3, weil 3 Tabelleneinträge vorhanden sind |
8 | if( Table[i].Bad < Value ) |
9 | Index = i; |
10 | |
11 | if( Index == -1 ) |
12 | return Table[0].Good; // Messwert kleiner als alle Tabellenwerte |
13 | |
14 | if( Index == 2 ) // Messwert größer als alle Tabellenwerte |
15 | return Table[2].Good; |
16 | |
17 | k = (double)( Table[Index+1].Bad - Table[Index].Bad ) / |
18 | (double)( Table[Index+1].Good - Table[Index].Good ); |
19 | d = Table[Index].Good - Table[Index].Bad * k; |
20 | |
21 | return (int)( Value * k + d + 0.5 ); |
22 | }
|
Ich hoffe mal, dass ich mich jetzt bei der Umsetzung der speziellen Formel von oben in eine allgemeine Form im Programm nicht vertan habe. Du solltest das am Papier nochmal prüfen.
Hallo Karl, herzlischen Dank für die ausführliche Erklärung. Viel Respekt!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.