Convert to a signed 8 Bit Value ???

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
gtrdriver
User
Beiträge: 11
Registriert: Donnerstag 28. Februar 2019, 13:52

Hallo zusammen

ich versuche gerade in python2 etwas zu rechnen - bei der Formel die mir vorliegt sieht das wie folgt aus:

Code: Alles auswählen

X=((Signed(K)+256*L/10
Dabei rechnet die App wie folgt:

Code: Alles auswählen

((-1*256)+L/10
usw...


Das ganze ist aus einer Android APP - in der beschreibung steht:
SIGNED(value)
Treats the incoming value as 8bit signed
Kann mir jemand sagen wie ich das in Perl mache ?
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn du das in Perl machen Willst - frag in einem Perl-Forum?

Und bei der Beschreibung deines Problems wirst du noch deutlich zulegen müssen. Deine Formeln da oben haben Klammerfehler und sind nicht äquavilent.

Wie wäre es, wenn du mal etwas weiter ausholst was das für Werte sind, wo die herkommen, was damit passieren soll.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Woher kommt K und warum liest Du das nicht schon als signed 8 Bit Value?
Zum Konvertieren von Bytes in Zahlen kennt Perl unpack.
gtrdriver
User
Beiträge: 11
Registriert: Donnerstag 28. Februar 2019, 13:52

Hi

Sorry. Ich komme.von perl und meine natürlich Python ..... Entschuldigung

K kommt ursprünglich als hex
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich bin skeptisch, dass das wirklich als hex kommt. Aber wenn, das kannst du mit binascii daraus das entsprechende Byte (oder mehrere) machen.

Code: Alles auswählen

>>> import binascii
>>> s = b"41"
>>> binascii.unhexlify(s)
b'A'
Und mit dem struct-Modul weiterverarbeiten. Wie - das zu beantworten reichen deine Informationen immer noch nicht.
gtrdriver
User
Beiträge: 11
Registriert: Donnerstag 28. Februar 2019, 13:52

Hi

ich versuche das nochmals klarer zu machen.

Ich bekomme von einem Seriellen Gerät einen Hex String der per leerzeichen getrennte einzelwerte enthält.

Für die Formel benötige ich 2 Hex Datenfelder - in dem aktuellen Beispiel:

K: "FF"
L: "C7"

Die Formel lautet nun: X=((Signed(k)*256)+L/10

Da soll dann um bei diesem Beispiel zu bleiben 5,7 raus kommen.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

`L/10` wäre -5,7, also für X insgesamt -261,7 oder soll L unsigned sein? Dann sind es -236,1.
Oder hast Du in Wirklichkeit ein signed 16bit-Wert? Also 0xFFC7 -> -0x39 was -57 wären und das durch 10 geteilt -5,7.

Mit Deinen spärliche, verwirrenden und sich widersprechenden Angaben kann man beim besten Willen nicht helfen. Du hast wahrscheinlich die ersten Schritte selbst zusammengeraten, steckst jetzt aber mitten drin in einer Sackgasse, und das alles nur, weil Du am Anfang falsch abgebogen bist.

Also fang endlich von Anfang an zu erklären, was Du hast, woher das kommt, und was Du erreichen willst.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Kommt es für mich nicht.

Code: Alles auswählen

>>> K = b'FF'
>>> L = b'C7'
>>> import struct
>>> import binascii
>>> k = struct.unpack("b", binascii.unhexlify(K))[0]
>>> l = struct.unpack("b", binascii.unhexlify(L))[0]
>>> X=(k*256)+l/10
>>> X
-261.7
Da fehlt natürlich Signed, weil nirgendwo erklärt wird, WAS das tut.
gtrdriver
User
Beiträge: 11
Registriert: Donnerstag 28. Februar 2019, 13:52

Hallo

Guten - fangen wir ganz am Anfang an:

Ich möchte mittels eines Raspberry PI und einem Bluetooth OBD Adapter werte aus einem Fahrzeug auslesen - dazu connectiere ich mittels pyserial den OBD Adapter - sende die PID Abfrage und lese das Ergebnis zeile für Zeile ein.

Das klappt für die meisten werte die nur von hex auf Dec umzurechnen sind ganz gut - hängen tue ich bei diesem Wert.

Also fangen wir mal mit dem an was ich für diesen Wert brauche:

1: Das ist die Zeile (STring) die vom Adapter per Seriell kommt:

Code: Alles auswählen

7EC21 FF C7 0F B8 10 0E 0E
2: ich benötige nur "spalte 2 und 3" also splitte ich die Zeile mit der Suche nach " " und erhalte die einzelnen Elemente:

Für dieses Beispiel dann:

Code: Alles auswählen

DATA[1] = FF

Code: Alles auswählen

DATA[2] = C7
Nun kommen wir zur Formel (die ich mir nicht ausgedacht habe sondern mangels besserer Dokumentation von einer ebenfalls mit dem OBD Adapter funktionierenden abgeschaut habe:

Am besten indem ich hier mal nen Screenshot der App mit exakt diesen Daten bereit stelle:
https://www.dropbox.com/s/k30uny74l9q88 ... hot151.jpg

Ganz oben würde das Ergebnis stehen "5,7" das ist leider abgeschnitten - aber die App zeigt unten den Rechenweg.

Ich hoffe dass ich das Problem jetzt klarer darstellen konnte.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Jein. Besser waere die Beibringung der Dokumentation des Adapters, damit man das Datenformat ergruenden kann. Aber fuer das konkrete Problem macht man das anders in Python:

Code: Alles auswählen

import binascii, struct
s = b"7EC21FFC70FB8100E0E"
h = struct.unpack(">h", binascii.unhexlify(s[5:9]))[0]
x = h / 10
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Du siehst aber schon, dass die Formel auf dem Screenshot eine andere ist, als du hier die ganze Zeit postest?
Also hast du sie dir doch ausgedacht :)
gtrdriver
User
Beiträge: 11
Registriert: Donnerstag 28. Februar 2019, 13:52

Erstmal danke für die Tipps ...
Das mit der Formel tut mir leid - ich hab mich hier vertippt - hätte aber nichts an der Grundproblematik geändert.

Vorweg: Es gibt zwar ne Beschreibung zu dem Adapter aber nicht zu den Return werten da diese von den Fahrzeug herstellern geheim gehalten werden und diese nur durch reverse Engenering von ambitionierten Benutzern herausgefunden wurden ... - Leider ist darüber sehr sehr wenig dokumentiert - aber die Tourque App ist hier recht gut weil es dafür eben fertige Sets gibt ...

Das mit der Formel klappt jetzt die Werte sind Valide ...

Jetzt habe ich noch etwas da ich nicht verstehe - ich suche schon seit 2 Stunden im Netz...

Wieder ein Beispiel:

M= 13 (hex 0D)
N= 240 (hex F0)

Die Formel lautet dann:

Code: Alles auswählen

X=((M<8)+N)/10
Was zum Geier ist "M<8" ???

Wie auf dem vorherigen Screenshot zu sehen läst die App die Gleichung der Reihe nach - der nächste Schritt ist eben dann "M<8" - das schaut dann wie folgt aus:

Code: Alles auswählen

X=(3328+N)/10
Leider ist auf der Doku Seite der App hier nix zu finden https://torque-bhp.com/wiki/Equations
Und auch der Autor des PID Set´s schweigt sich über die Formel aus...

Auch hier habe ich mal nen Screenshot gemacht: https://www.dropbox.com/s/zcyx47aolsdzx ... e.jpg?dl=0
Hier auf dieser Seite kann man die Formeln noch sehen: https://github.com/JejuSoul/OBD-PIDs-fo ... EV_BMS.csv

Es geht um den Parameter Satz "000_Battery DC Voltage"


Ich hoffe ich hab mich nicht vertippt ....
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Schon wieder ein Schreibfehler, `M<<8`, was aber das selbe ist wie M*256.
Sieht so aus, als ob Du diesmal ein unsigned 16Bit-Wert hast:

Code: Alles auswählen

h = struct.unpack(">H", bytes)[0]
x = h / 10
gtrdriver
User
Beiträge: 11
Registriert: Donnerstag 28. Februar 2019, 13:52

Hallo

mist - das kommt davon wenn man die Brille nicht auf hat ... - sorry - mal ganz abgesehen von python - ich würde das aus Mathematischer Sicht gerne verstehen ...

Danke !
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hast du dir mal die Dokumentation von struct angeschaut?
Benutzeravatar
DeaD_EyE
User
Beiträge: 1017
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Antwort steht hier bereits: viewtopic.php?f=1&t=45186#p342848
Das erklärt auch, die Formel. Die 256 stechen ins Auge. Ich lasse meine falsche Interpretation trotzdem mal stehen.

Richtig wäre:
K = High byte
L = Low byte
Endianess = Big Endian

ich hätte als Berechnung eher das erwartet:
K << 8 | L
ist aber das gleiche wie
K * 256 + L

__deets__ hat es richtig interpretiert, es handelt sich nicht um zwei Zahlen, sondern um einen signed short, big endian.
-------------------------------

K ist ein signed byte
L ist ein unsigned byte
Die Bytereihenfolge ist bei bytes belanglos.

Die Funktion zum Berechnen:

Code: Alles auswählen

def calc(hex_string):
    data = hex_string.replace(' ', '')[5:9] # Leerzeichen entfernen, Bereich auswählen
    k, l = struct.unpack('bB', binascii.a2b_hex(data)) # hex-string -> bytes -> integer 
    return (k * 256 + l) / 10
Wenn das dein String ist: "7EC21 FF C7 0F B8 10 0E 0E",
musst du zuerst die Leerzeichen entfernen, sonst wirft binascii.a2b_hex einen ValueError.
Die Funktion a2b_hex wandelt den bearbeiteten hex-string in bytes um.
Die Funktion struct.unpack wird verwendet, um C-Datentypen aus Bytes zu interpretieren.
Zuerst wird ein signed byte erwartet und direkt danach ein unsigned byte.

Der Unterschied ist, dass ein signed byte Werte von -128 bis +127 annehmen kann.
Ein unsigned byte von 0 bis 255.

Das könnte auch als Anhaltspunkt dienen, um die Formel etwas besser zu verstehen.

z.B. ergibt -128 * 256 == -32768 == -2**15
Ich vermute mal, dass der Faktor K einen größeren Wertebereich abbilden soll, die Genauigkeit aber nicht so wichtig ist. L ist nur ein Offset. Der Teiler 10 kommt z.B. vor, wenn es sich um eine logarithmische Einheiten wie z.B. dBV oder nur um das logarithmische Verhältnis dB handelt.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten