mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Linearisierung klappt nicht


Autor: Abderrahim (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Pad Semos (padesmos)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
entschuldigt, das was ich dargestellt habe war die Abweichung,
so sehen meine U ist und soll:

Autor: Pad Semos (padesmos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Abderrahim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Abderrahim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Abderrahim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß

Autor: blog.coldtobi.de (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:

Autor: blog.coldtobi.de (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PPS [cont]
Du hast doch schon Werte aufgenommen. Diese wären doch die Grundlage für 
die Loouptable, oder?

Autor: Abderrahim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
  int GoodValues[] = { 8, 21, 29 };

  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
struct Value {
  int Bad;
  int Good;
};

Daraus wird jetzt das Umrechnungsarray generiert
struct Value Table[] = 
  {
    { 10,   8 },
    { 23,  24 },
    { 38,  35 }
  };

Wie wird jetzt die Umrechnung gemacht? Ganz einfach: Du gehst
mit dem gemessenen Wert in das Array und suchst nach der korrekten
Zeile.
int Correct( int Value )
{
  int i;

  for( i = 0; i < 3; ++i )
    if( Table[i].Bad == Value )
      return Table[i].Good;

  return 0;
}

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.
int Correct( int Value )
{
  int i;
  int Index = -1;
  double k, d;

  for( i = 0; i < 3; ++i )   // 3, weil 3 Tabelleneinträge vorhanden sind
    if( Table[i].Bad < Value )
      Index = i;

  if( Index == -1 )
    return Table[0].Good;   // Messwert kleiner als alle Tabellenwerte

  if( Index == 2 )          // Messwert größer als alle Tabellenwerte
    return Table[2].Good;

  k = (double)( Table[Index+1].Bad - Table[Index].Bad ) /
      (double)( Table[Index+1].Good - Table[Index].Good );
  d = Table[Index].Good - Table[Index].Bad * k;

  return (int)( Value * k + d + 0.5 );
}

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.

Autor: Abderrahim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl,
herzlischen Dank für die ausführliche Erklärung.
Viel Respekt!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.