Hilfe für bit-packing bei Bluetooth Stream in Eclipse

  • Antworten:8
egimann101
  • Forum-Beiträge: 5

04.04.2012, 22:32:03 via Website

Hallo liebe android Entwickler
Wir sind in der Schule momentan dabei eine App zur Überwachung der Körpervitalität zu programmieren.
Ich bin mit meiner Aufgabenstellung momentan sehr an die Wand gefahren.

Mein Problem ist Folgendes:
Ich empfange über einen Bluetooth-stream ein Datenpaket welches ausgewertet werden soll.
In diesem Paket sind die Werte für die EKG Messung von einem Zephyr Brustgurt enthalten.
Und jetzt mein eigentliches Problem:
Die Werte sind bit-gepackt um Platz zu sparen was mir jedoch einige Probleme bereitet.
Ich hab das jetzt so weit, dass ich die 63 Samples in ein array
“ byte[] arrayECG = new byte[1024];“
speichere, die Werte sind aber aufgrund der Bitpackerei so ja noch nicht korrekt, sondern eher irgendwelche Zahlen.
Brauche jetzt Hilfe beim Umbau der gepackten Daten auf ein brauchbares Format, oder mache ich schon beim Auslesen was grobe falsch?
Hoffe auf rasche Hilfe.
Lg.

So da noch der Auszug aus dem Code


da der Auszug aus dem debugging bzw.: meine gepackten Werte.


und noch ein auszug aus dem Datenblatt


hoffe sehr, dass mir geholfen werden kann :)

Antworten
Wolfgang S.
  • Forum-Beiträge: 32

05.04.2012, 11:45:09 via Website

Wahnsinn, das ist ja eine Herausforderung :ph34r:

Java kann keine unsigned Bytes (0-255) sondern nur signed Bytes (-128 bis 127) du solltest daher kein byte-Array, sondern besser int verwenden. Lies dir dazu http://www.jguru.com/faq/view.jsp?EID=13647 durch. Benutze am besten von java.io.DataInputStream die Methode readUnsignedByte() um ein byte nach dem anderen auzulesen.

Die Byte-Felder 0 bis 3, 6, 7, 91 und 92 kannst du einfach auslesen, bei den restlichen Feldern musst du die bytes zu einem sinnvollen Wert zusammensetzen:
Zum Beispiel Feld 4 und 5 ergeben das Jahr, wobei Feld 4 (LS Byte) das "niederwertige" Feld angibt und Feld 5 (MS Byte) das höherwertige. Ein Byte sieht binär zB so aus: 1 0 0 1 0 1 0 1. Wollen wir zwei Bytes kombinieren, müssen wir das höherwertige also um 8 stellen nach links schieben (1 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0) und können es dann mit dem niederwertigen kombinieren.
1int field4; //enthält Wert von Feld 4
2int field5; //enthält Wert von Feld 5
3int year = ((field5 & 0xFF) << 8) | field4 & 0xFF
Ich bin mir jetzt nicht sicher, ob du "& 0xFF" wirklich brauchst - probier einfach aus, ob ohne oder mit sinnvolle Werte herauskommen.
siehe dazu auch http://www.petefreitag.com/item/183.cfm

Das gleiche bei Feld 8 bis 11, wobei int hier nicht mehr ausreichen wird und du long verwenden musst
1long milliseconds = ((field11 & 0xFF) << 24) | ((field10 & 0xFF) << 16) | ((field9 & 0xFF) << 8) | field8 & 0xFF;

Das Packing Format ist jetzt ein wenig "tricky", da jeder Teil (Sample) 10 Bit lang ist. Wir wissen aber, dass sich alle 5 Bytes das Pattern wiederholt. Wir packen also jeweils 5 Bytes in eine long-Variable (siehe oben), lesen die 10 rechten Bits aus und machen einen right-shift (mit dem Operator >>) um 10 Stellen und holen uns die nächsten 10 Bit. Und das machen wir für alle 63 Teile (Samples).

Ich hoffe ich hab dir ein wenig weitergeholfen, leider hatte ich bisher weder mit Hardware-Programmierung noch Bit-Shifting zu tun. :grin:

Antworten
egimann101
  • Forum-Beiträge: 5

05.04.2012, 12:04:31 via Website

Ja danke das klingt alles sehr einleuchtend.

Das arrayECG war eigentlich ein int aber beim Debuggen wird mir da leider kein Inhalt angezeigt, deshalb habe ich es noch geändert.
Werde jetzt mal versuchen da meine werte zusammenzubasteln.
Ich brauche eigentlich nur das Feld 12 da alle anderen bereits ausgelesen werden oder wie die ganzen Zeitangaben nicht notwendig sind da die Werte in eine Datenbank kommen und dort einen Zeitstempel verpasst bekommen.
Danke für die schnelle Antwort Wolfgang.

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

05.04.2012, 12:16:44 via Website

Du kannst auch einfach

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Integer.html#toBinaryString%28int%29

nehmen, um die Ints, die du einliest in Binärrepräsentation als String zu visualisieren.
Dann kannst du sogar mit substring Anweisungen die Bitfolgen extrahieren, die du brauchst und dann mit

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Integer.html#parseInt%28java.lang.String,%20int%29

die Bitfolgen wieder zu Zahlen umrechnen

1parseInt("1100110", 2) returns 102

Mit Sicherheit nicht die performanteste Lösung, aber auf jeden Fall deutlich einfacher nachvollziehbar und debuggbar.

— geändert am 05.04.2012, 13:09:10

Antworten
Wolfgang S.
  • Forum-Beiträge: 32

05.04.2012, 13:24:49 via Website

Interessant wäre dabei, in welchem Intervall die Daten ankommen und wie schnell sie verarbeitet werden sollen. Bit Shifting ist natürlich um einiges schneller.

Antworten
egimann101
  • Forum-Beiträge: 5

05.04.2012, 15:41:05 via Website

Habe mir das Bit Shifting genauer angesehen. und das auslesen des Jahres Funktioniert toll, leider brauche ich das Jahr nicht :)

Das Auslesen des EKG hab ich nicht so ganz verstanden, habe das mal so gemacht:
arrayECG[0] sollte dem ersten Sample entsprechen usw.

long binECG = ((arrayECG[0] & 0xFF) << 48) | ((arrayECG[1] & 0xFF) << 24) | ((arrayECG[2] & 0xFF) <<16) | ((arrayECG[3] & 0xFF) <<8) | arrayECG[4] & 0xFF;

der Wert in binECG ist -100704385?? damit kann ich leider nichts anfangen.

wie machen einen right-shift?
wie gesagt habe mit java noch nicht viel gemacht, brauche also die Anleitung für ganz ganz dumme :)

Antworten
Wolfgang S.
  • Forum-Beiträge: 32

05.04.2012, 17:07:58 via Website

Ein Sample hat einen Umfang von 10 Bit, das Sample sollte also eine Zahl von 0 bis 1023 enthalten.

Schau einmal, ob folgender Code schnell genug ist:

//arrayECG enthält 79 Einträge?
//wir bauen uns einen String, mit byte 0 ganz rechts
StringBuilder ecgBuilder = new StringBuilder();
for(int i = 79; i >= 0; i--) {
// das gibt uns einen string, der unterschiedlich lang sein kann
// wir benötigen nur die letzten 8 Zeichen (ein Byte) und müssen notfalls vorne Nullen hinzufügen
String bs = Integer.toBinaryString(arrayECG[i]);
if (bs.length() > 8) {
bs = bs.substring(bs.length()-8);
} else if (bs.length() < 8) {
while(bs.length() < 8) {
bs = "0" + bs;
}
}
ecgBuilder.append(bs);
}
//wir holen uns alle 63 Samples - immer 10 Bits vom Ende
int[] samples = new int[63];
for(int i = 0; i < 63; i++) {
samples[i] = Integer.parseInt(ecgBuilder.substring(ecgBuilder.length()-10), 2); //wir holen uns die letzten 10 Bit...
ecgBuilder.delete((ecgBuilder.length()-10, ecgBuilder.length()); // ... und löschen sie vom StringBuilder, damit die nächsten 10 Bit ganz rechts stehen
}

Hm, der Bit-Shifting Code wäre kürzer...

— geändert am 05.04.2012, 17:47:12

Antworten
egimann101
  • Forum-Beiträge: 5

06.04.2012, 00:13:36 via Website

unglaublich, aber es funktioniert.!!!!!

habs jz so gemacht:

//arrayECG enthält 80 Einträge
//bauen von einen String, mit byte 0 ganz rechts
StringBuilder ecgBuilder = new StringBuilder();
for(int a1 = 80; a1 >= 0; a1--) {
// das gibt uns einen string, der unterschiedlich lang sein kann
// wir benötigen nur die letzten 8 Zeichen (ein Byte) und müssen notfalls vorne Nullen hinzufügen
String bs = Integer.toBinaryString(arrayECG[a1]);
if (bs.length() > 8) {
bs = bs.substring(bs.length()-8);
} else if (bs.length() < 8) {
while(bs.length() < 8) {
bs = "0" + bs;
}
}
ecgBuilder.append(bs);
}

//wir holen uns alle 63 Samples - immer 10 Bits vom Ende
int[] samples = new int[63];
for(int b = 0; b < 63; b++) {
samples[b] = Integer.parseInt(ecgBuilder.substring(ecgBuilder.length()-10), 2); //wir holen uns die letzten 10 Bit...
ecgBuilder.delete((ecgBuilder.length()-10), ecgBuilder.length()); // ... und löschen sie vom StringBuilder, damit die nächsten 10 Bit ganz rechts stehen

if(b==62)
{

Thread.sleep(300);
// samples hir speichern?

}

}

irgendwo unten haste ne Klammer vergessen ;)

Im Datenblatt steht ja noch, dass sich das Paket alle 252ms ändert daher habe ich noch einen sleep(300) dazugegeben.
werde noch das speichern auf der Datenbank dazugeben und dan hab ich das erledigt.

Eine Frage hab ich aber noch..
Warum hast du geschrieben arrayECG 80 Einträge? da hab ich ja eigentlich nur 63 also für jedes Sample einen.

muss mich echt bedanken!!!!

Antworten
Wolfgang S.
  • Forum-Beiträge: 32

06.04.2012, 09:25:04 via Website

Freut mich, dass es funktioniert :grin:
Ich hatte gerade keine Java-IDE bei der Hand, deshalb hab ich das direkt im Forum "gecoded". Ich dachte, dass die Bytes 12 bis 91 die 63 Samples enthalten. 79 Bytes sind 632 Bits, jedes Sample hat 10 Bit, deshalb gibt es insgesamt 63,2 (also abgerundet 63) Samples. Probier doch mal, 79 Bytes einzulesen :wink:

Antworten