TIA Generierung Dezimalbruch (Zähler / Nenner) (DINT) aus LREAL

NBerger

Level-3
Beiträge
1.373
Reaktionspunkte
386
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo...,
Ich brauche aktuell eine Umrechnung einer LReal Zahl in Zähler und Nenner.

Die Umrechnung wird für die Angabe des Gleichlaufes im Motion-Control gebraucht und muss alle 50-100 ms neu berechnet werden.

Aus der Trigonometrie erhalte ich einen Übersetzungsfaktor in Lreal...

Der Bruch muss möglichst genau sein und über einen großen Bereich funktionieren.

Hat da jemand einen brauchbaren Ansatz?
 
Hallo!

Nur als Gedankenanstoß:
Um diese Inhalte anzuzeigen, benötigen wir die Zustimmung zum Setzen von Drittanbieter-Cookies.
Für weitere Informationen siehe die Seite Verwendung von Cookies.

Gruß von Björn
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe das mal schnell so umgesetzt, also hingepfuscht und es geht auch mit nichtperiodischen Dezimalzahlen:

"Werte".Wert_links := "Werte".Wert_rechts := "Werte".Eingabe;
"Werte".Wert_links_9 := "Werte".Eingabe * 9;
"Werte".Wert_rechts := "Werte".Eingabe * 10;
"Werte".Wert_rechts := "Werte".Wert_rechts - "Werte".Eingabe;
"Werte".Teiler_9 := 9; // hier wollte ich eigentlich weiter kürzen, wenn möglich und "Werte".Teiler_9 wird dazu evtl. gebraucht, aber das Suchen nach math. Funktionen in der TIA-Hilfe habe ich noch nicht geschafft.

So oder so:
Der Zähler ist dann "Werte".Wert_rechts und der Nenner ist 9. Wenn Dir das ohne das Kürzen etwas nützt, ...

Dezimalzahl_in_Bruch.jpg
 
Bei einer Gleitkommazahl in IEE 754 Darstellung lässt sich der Bruch direkt aus den einzelnen Bits von Exponent und Mantisse ableiten.

Ich habs grad mal auf einem Blatt Papier für die 32-Bit Gleitkomma durchprobiert. Bei 64 Bit musst du den Biaswert anpassen.


1. Beispiel: 6.75

Exponent: B#1#10000001 = 129 -> abzügl. Biaswert 127 = 129-127 = 2
Mantisse: B#1#10110...

1 vor die Mantisse weil normalisiert = 1,1011
Komma um Exponent Stellen nach rechts = 110,11
Kleinstes gesetztes Bit hinter dem Komma besitzt die Wertigkeit 2^(-2), dementsprechend Nenner = 4
Gesamtes Bitmuster 11011 = dez 27 ist der Zähler
Gesamt: 27/4


2. Beispiel: 27.5

Exponent: B#1#10000011 = 131 -> abzügl. Biaswert 127 = 131-127 = 4
Mantisse: B#1#101110...

1 vor die Mantisse stellen weil normalisiert = 1,10111
Komma um Exponent Stellen nach rechts = 11011,1
Kleinstes gesetztes Bit hinter dem Komma besitzt die Wertigkeit 2^(-1), dementsprechend Nenner = 2
Gesamtes Bitmuster 110111= dez 55 ist der Zähler
Gesamt: 55/2
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hier mal meine Lösung auf Basis #4...
Code:
  REGION Dezimalbruch generieren
                    [COLOR=#008000]// Synchronfaktor wandeln in Dezimalbruch[/COLOR]
                    #SyncWord := LREAL_TO_LWORD(#SyncFaktor);
                    #Mantisse := LWORD_TO_LINT(SHR(IN := #SyncWord AND 16#F_FFFF_FFFF_FFFF, N := 22)); [COLOR=#008000]// Mantisse filtern und begrenzen auf 32 Bit[/COLOR]
                    #Mantisse.%X30 := true; [COLOR=#008000]// Hidden Bit setzen[/COLOR]
                    
                    #Exponent := LWORD_TO_INT(SHR(IN := SHL(IN := #SyncWord.%W3, N := 1), N := 5)) - 1023; [COLOR=#008000]// Exponent filtern und korrigieren um Offset[/COLOR]
                    
                    IF #Exponent > 30 THEN [COLOR=#008000]// Grenzen des Exponentes überwachen und ggf. korrigieren[/COLOR]
                        #Exponent := 30;
                    ELSIF #Exponent < -30 THEN
                        #Exponent := -30;
                    END_IF;
                    
                    #Einzelbit := 1;
                    IF #Exponent >= 0 THEN
                        #Numerator := LINT_TO_DINT(#Mantisse);
                        #Denominator := SHL(IN := #Einzelbit, N := (INT_TO_ULINT(30 - #Exponent)));
                    ELSE
                        #Numerator := LINT_TO_DINT(SHR(IN := #Mantisse, N := INT_TO_ULINT(- #Exponent)));
                        #Denominator := SHL(IN := #Einzelbit, N := 30);
                    END_IF;
                    
                    IF #SyncWord.%X63 THEN [COLOR=#008000]// +/- Korrigieren im Zähler[/COLOR]
                        #Numerator *= -1;
                    END_IF;
                END_REGION
 
So ist der Bruch aber ungekürzt. Wenn du z.B. in einer Schleife das niederwertigste Bit in der Mantisse suchst und damit rechnest wie oben beschrieben, dann ist er direkt so weit möglich gekürzt.
 
Ja..., gelobt ist was schnell macht.
Warum soll ich den lange ein Bit suchen? Das Motion Control wird deshalb nicht schneller.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das Motion Control wird deshalb nicht schneller.
Interessant. Weil ich Motion Control noch nicht kenne: Wozu braucht man Zähler und Nenner? Ich kann mir zwar etwas vorstellen, wozu, aber wenn beides mit Bewegung zu tun hat, sind dann nicht gekürzte Werte besser?

Oder sollte man gar erweitern, für bessere Auflösung? Bin gespannt.
 
Zuletzt bearbeitet:
Wozu braucht man Zähler und Nenner? Ich kann mir zwar etwas vorstellen, wozu, aber wenn beides mit Bewegung zu tun hat, sind dann nicht gekürzte Werte besser?
Wenn's um GetriebeÜber-/Untersetzungen geht, also um Zahnräder, dann drängen sich ganzzahlige Variablen einfach auf, weil die Anzahl Zähne eines Zahnrades - oh Wunder - ebenfalls ganzzahlig ist - egal, ob man die abgebrochen (=halben) Zähne mitzählt oder nicht. :ROFLMAO:
In Hinblick auf eine möglichst gleichmässige Abnutzung der Zähne wählen die Mechaniker am liebsten teilerfremde Anzahlen Zähne bei ZahnradPaaren.
GleitKommaZahlen sind aber denkbar ungeeignet, um solche Verhältnisse (über viele Umdrehungen hinweg exakt) in Zahlen abzubilden. Kleinste Ungenauigkeiten summieren sich ganz einfach über etliche Umdrehungen.
Wenn mit dem Quotient Zähler/Nenner nach n Umdrehungen neu berechnet wird, tritt die kleine Ungenauigkeit erneut auf, basiert dann aber auf korrekten (ganzzahligen) Anzahl Umdrehungen und ganzzahligen ZähneAnzahlen, statt auf einem ständig anwachsenden Fehler aufzubauen, der dann auftritt, wenn das Verhältnis der EingangsDrehzahl zur AusgangsDrehzahl als GKZ zwar ziemlich genau, aber eben nicht ganz genau dargestellt werden kann.

Gekürzte Werte sind zumindest nicht schlechter. Das Verhältnis Zähler zu Nenner ändert sich schliesslich nicht durch das Kürzen. Unnötig grosse Zahlen durch kleinere zu ersetzen, ist nicht nur angenehmer für das Auge des Betrachters, sondern kann/wird/sollte sich auch auf die Rechenzeit positiv auswirken.

Gruss, Heinileini

PS:
Durch das Erweitern ändert sich ebenfalls nichts am Verhältnis Zähler zu Nenner - nicht einmal die Genauigkeit. Nur die Gefahr ist grösser, dass es bei Berechnungen zu Überläufen kommt.
 
Zuletzt bearbeitet:
Sehr schön, dass ich es mir richtig gedacht hatte. Aber auch vielen Dank für die Mühe der ausführlichen Darstellung.

Viele Grüße.
Björn
 
Zuviel Werbung?
-> Hier kostenlos registrieren
GleitKommaZahlen sind aber denkbar ungeeignet, um solche Verhältnisse (über viele Umdrehungen hinweg exakt) in Zahlen abzubilden. Kleinste Ungenauigkeiten summieren sich ganz einfach über etliche Umdrehungen.
Wie wir aber hier festgestellt haben, entspricht eine Gleitkommazahl einer rationalen Zahl, also einem Bruch aus zwei ganzen Zahlen.
Was er jetzt hier umrechnet könnte die Motion Control Steuerung genau so gut selber rechnen. Denn bei der Umrechnung geht keine Genauigkeit verloren.
 
Wie wir aber hier festgestellt haben, entspricht eine Gleitkommazahl einer rationalen Zahl, also einem Bruch aus zwei ganzen Zahlen.
Du hast Recht, Thomas, dass man eine GKZ eindeutig in Zähler und Nenner eines Bruches "umrechnen" kann.
Ich hatte doch nur geschrieben "GleitKommaZahlen sind aber denkbar ungeeignet, um solche Verhältnisse (über viele Umdrehungen hinweg exakt) in Zahlen abzubilden."
Das betrifft also die umgekehrte Richtung: Umwandlung aus zwei ganzen Zahlen in eine GKZ.
In dieser Richtung lassen sich zahllose Beispiele finden, die sich nicht "genau genug" als GKZ darstellen lassen.
Z.B. wird 1/3 zu 11184811/33554432 (bei 32-Bit-GKZ).
Mein Anliegen war, zu erklären, warum für die Darstellung von GetriebeÜbersetzungen nicht eine GKZ, sondern 2 Ganzzahlen verwendet werden.
Steht man vor der Aufgabe, eine GKZ in Zähler und Nenner umzuwandeln, weil die Schnittstelle dies so verlangt, dann kann man leider die Vorzüge nicht auskosten, weil das Problem schon beim Berechnen der GKZ aufgetreten ist und die Rückwandlung in Zähler und Nenner das nicht reparieren kann.

Gruss, Heinileini
 
Zurück
Oben