Hallo, ich schreibe gerade eine Funktion in der programmier Sprache in c. Die Daten sind in einem Array mit 16 Elementen und die Werte sind INT mit einem Wertebereich von 0 bis 29. Diese Daten werde ca. alle 25ms aktualisiert. Diese Funktion wird ca. alle 4ms bis 6ms aufgerufen. In dieser Funktion sollen die alten Daten sich in x Schritten den neuen Daten nähern. In dieser Funktion ist die Information bekannt, ob neue aktualisierte Daten vorhanden sind. Es ist auch bekannt in wie vielen Schritten sich die alten zu den aktualisierte Werten nähern soll. Wichtig ist das die die INT Zahlen ganze Zahlen bleiben. Ich möchte dies in einem Beispiel beschreiben. Daten[0].Wert bis Daten[15].Wert bekommen neue aktualisierte Daten. Alle 15 Daten sind im Wertebereich von 0 bis 29. Das Beispiel beschreibt die Nährung von dem Array BIN 0 Muss aber für jedes Array bin für sich auch funktionieren. Der alte Wert in Daten[0] war 5. Der aktualisierte Wert in Daten[0] ist 18. Schritte sind 6. Die Funktion wird nun alle 4ms bis 6ms aufgerufen: Meine Idee erstmal die Differenz ausrechen: Die Wäre dann 13. Aber diese Differenz nun durch 6 Schritte zu teilen bedeutet 2 rest 1. Schritt 1: Neuer Wert[0] = Alter Wert[0] + 2; Schritt 2: Neuer Wert[0] = Neuer Wert[0] + 2; Schritt 3: Neuer Wert[0] = Neuer Wert[0] + 2; Schritt 4: Neuer Wert[0] = Neuer Wert[0] + 2; Schritt 5: Neuer Wert[0] = Neuer Wert[0] + 2; Schritt 6: Neuer Wert[0] = Neuer Wert[0] + 2 + 1; Die Nähren von dem alten Wert zu dem neuen Wert soll so gleichmäßig wie möglich erfolgen. Bei diesem Beispiel war die Differenz positive, da die neuen Daten größer waren als die alten. Dies kann aber auch anders sein, dass die neuen Daten kleiner sind wie die alten Daten. Zudem bin ich am überlegen ob eine Differenz größer 1 sein muss, damit eine Nährung an den neuen Wert erfolgt. Dies müsste einstellbar sein. Ich brauche eure Hilfe diesen c Code zu schreiben.
Erinnert mich stark an den Bresenham Algorithmus.
Stefan F. schrieb: > Erinnert mich stark an den Bresenham Algorithmus. Danke für deine Antwort. Ich habe mir den angeschaut, aber was muss ich bei diesen Algorithmus anpassen, damit er meine Anforderung entspricht? Die Anzahl der Schritte sind variabel und nicht fix.
Beim Bresenham geht es doch auch darum, einen Wert zu erreichen während die Schrittweise keine glatten Integer Zahlen sind. Schau dir das Bild an. Stell dir vor dass die Y Achse den Wert darstellt. Du willst von Y1 nach Y2 kommen und das mit einer gewissen Anzahl von Schritten. Die Schritte werden durch die X-Achse repräsentiert, in diesem Fall sind es 18 Schritte. Da die Linie hier recht flach verläuft, wird Y bei jedem Schritt um 0 oder 1 erhöht. Aber das kann in einem anderen Fall auch mehr sein. Der eigentlich Knackpunkt ist, dass die Steigung (die pro Schritt addiert wird) eine Fließkommazahl ist, kein glatter Integer. Das ist ja auch genau dein Problem. Ohne das jetzt im Detail mathematisch auseinander zu nehmen kannst du einfach den C Code aus dem Absatz "Kompakte Variante" verwenden. Den habe ich auch schon mehrmals verwendet. So ganz durchblickt habe ich ihn selbst nicht, aber er funktioniert. Deine Eingabeparameter sind: x0 = 0 x1 = Anzahl der Schritte y0 = Anfangswert (alter wert) y1 = Zielwert Innerhalb der Funktion ist eine while Schleife, die wird genau so oft durchlaufen wie "Anzahl der Schritte". Innerhalb der Schleife wird mit dem Funktionsaufruf von setPixel() der berechnete Y Wert für jeden dieser Schritte ausgegeben. Du müsstest also an dieser Stelle einfach setPixel() durch einen Schreibzugriff auf den Zielspeicher (wo der zu ändernde Wert liegt) ersetzen. statt: setPixel(x0,y0) neu: Daten[0]=y0 Und weil du das mit mehreren Daten machen sollst, erweiterst du die Funktion um einen Parameter der den Index auf das Daten-Array darstellt und ersetzt diese eine Zeile durch: void line(int x0, int y0, int x1, int y1, int index) { ... Daten[index]=y0 // statt setPixel(y0,y0) ... } Danach kannst du die Funktion für alle 16 Elemente aufrufen:
1 | for (int index=0; index<16; index++) { |
2 | line(0, Daten[index], 6, NeueDaten[index], index) |
3 | }
|
Auf deutsch: Für alle 16 Felder im Array, erhöhe den Wert in Daten[index] in 6 Schritten bis zum Zielwert der durch NeueDaten[index] vorgegeben ist. Da du immer mit x0=0 beginnst, kannst du den Algorithmus vermutlich noch ein bisschen optimieren, wenn du magst. Der funktioniert natürlich auch mit 8 Bit Zahlen (int8_t). Falls das nicht die gewünschte Reihenfolge ergibt, musst du dir den Algorithmus halt umschreiben. Das kriege ich jetzt nicht "mal eben schnell" im Kopf hin. Vermutlich musst du dann die temporären Variablen (dy, dy, err, e2) innerhalb der Funktion durch Arrays ersetzten. Oder du schreibst das nochmal ganz neu. Die Grundidee hinter dem Algorithmus ist folgende: Da die Steigung eine Fließkommazahl ist muss sie für jeden Schritt auf Integer abgerundet werden. Soweit war es ja klar. Den Fehler merkt man sich. Im nächsten Schritt wird der neue Fehler mit dem vorherigen addiert. Wenn das >=1 ergibt, dann muss der Wert um +1 mehr erhöht werden. Das ist genau das, was du in deinem Eröffnungsbeitrag im Schritt 6 verdeutlicht hast. Wichtig ist, dass du die vorherigen Fehler aufaddierst bis sie groß genug sind, um die Schrittweite um +1 mehr zu rechtfertigen. Die "Kompakte Variante" auf Wikipedia hat das ganz raffiniert ohne Fließkomma-Arithmetik umgesetzt, was ja gerade auf deinem Mikrocontroller auch hilfreich ist. Deswegen war der Code auch für mich sehr attraktiv, obwohl ich nicht ganz verstanden habe. Aber ich konnte ihn anwenden - immerhin.
Jetzt deine Erklärung dazu hat mir wirklich geholfen. Die war sehr ausführlich! Ich setzte mich gleich dran und Untersuche den Algorithmus. Und binde den in mein Code ein. Vielen Dank dafür.
Kleine Anregung, wie du den Schreibzugriff (anstelle von setPixel) sauberer machen kannst:
1 | // Erhoehe dern Wert bis zum Zielwert in n Schritten.
|
2 | void erhoehe(int* wert, int schritte, int zielwert) |
3 | {
|
4 | // Hatte keine Lust die Variablen umzubenennen.
|
5 | // Der Compiler wird das weg optimieren.
|
6 | x0 = 0; |
7 | y0 = *wert; |
8 | x1 = schritte; |
9 | y1 = zielwert; |
10 | |
11 | // Jetzt kommt der Bresenham aus Wikipedia:
|
12 | int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; |
13 | int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1; |
14 | int err = dx + dy, e2; /* error value e_xy */ |
15 | |
16 | while (1) { |
17 | *wert=y0; // statt setPixel(x0, y0); |
18 | if (x0 == x1 && y0 == y1) break; |
19 | e2 = 2 * err; |
20 | if (e2 > dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */ |
21 | if (e2 < dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */ |
22 | }
|
23 | }
|
Du übergibst anstelle des konkreten Integer Werte einen Zeiger auf den Wert. Dann kann der Schreibzugriff über diesen Zeiger stattfinden.
1 | for (int index=0; index<16; index++) { |
2 | erhoehe( &Daten[index], 6, NeueDaten[index] ); |
3 | }
|
Nochmals vielen Dank für deine Hilfe. Ich konnte dein Beispiel gut übernehmen. Ich musste nur die while Schleife entfernen, da die Funktion zyklisch aufgerufen wird. Weil mit jedem Aufruf ein Schritt gemacht werden muss.
Kevin Hinrichs schrieb: > Ich musste nur die while Schleife entfernen, > da die Funktion zyklisch aufgerufen wird. Das meinte ich mit Umschreiben. Habe mir schon gedacht dass du das selbst hin bekommst nachdem die Grundidee des Algorithmus verstanden hast.
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.