Dr.Fuzzy Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 Παίδες όποιος μπορεί ας βοηθήσει. Παρακάτω είναι ένας κώδικας που μετατρέπει 4 bytes που παίρνονται από την σειριακή, σε float. Τα δεδομένα τα στέλνει το Matlab σε τύπο float32 και το board (Microblaze soft processor υλοποιημένος σε FPGA) τα λαμβάνει και τα κάνει reconstruct. Μόνο που η μετατροπή είναι πολύ αργή. Anyone? > /* int2float : convert received float to actual float */ float int2float(int n,int *intp,float *floatp) { unsigned int intValue; int i; int aux_s, aux_e, aux_f; float FloatValue2; for(i=0;i<n;i++){ intValue=*(intp+i); if(intValue==0 || intValue==0x80000000){ *(floatp+i)=0; continue; } else{ /* Separate the bytes like the IEEE-754 standard */ /* SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF */ aux_s = (2147483648 & intValue ) / 2147483648; //Signal aux_e = (2139095040 & intValue ) / 8388608; //Exponent aux_f = (8388607 & intValue ); //Fraction //Convert to float IEEE-754 *(floatp+i) = (1 - 2*aux_s) * pow(2,aux_e - 127) * (aux_f / pow(2,23) + 1); } } }
bxenos Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 βιαστικά (και όχι πολυ νυφάλια) βλέποντας τον κώδικα... > aux_s = (2147483648 & intValue ) / 2147483648; //Signal aux_e = (2139095040 & intValue ) / 8388608; //Exponent aux_f = (8388607 & intValue ); //Fraction //Convert to float IEEE-754 *(floatp+i) = (1 - 2*aux_s) * pow(2,aux_e - 127) * (aux_f / pow(2,23) + 1); οι διαιρέσεις και τα pow είναι πάναργa για τέτοια λειτουργία. Βάλε αντί για >pow(2,aux_e - 127) * (aux_f / pow(2,23) το > [b](1<<(aux_e - 127))[/b] * [b](aux_f / (1<<23))[/b] για τις διαιρέσεις δεν μπορώ να σκεφτώ κάτι τώρα... Οι δυνάμεις όμως είναι ηλίου φαεινότερο
Dr.Fuzzy Δημοσ. 25 Μαΐου 2009 Μέλος Δημοσ. 25 Μαΐου 2009 ΑΚΥΡΟ! Τελικά δεν δουλεύει σωστά ούτε αυτό. Κάπου αλλού είναι το πρόβλημα. Ίσως κάποιο άλλο casting. Ideas? ---------- Το μήνυμα προστέθηκε στις 02:30 ---------- Ευχαριστώ πολύ. Ο κώδικας σου δουλεύει τραγικά πιο γρήγορα μόνο που ήθελε ένα casting. Δηλαδή: *(floatp+i) = (1 - 2*aux_s) * (float)(1<<(aux_e - 127)) * ((aux_f / (float)(1<<23)+1)); Αυτό βγάζει σωστά αποτελέσματα. Ότι άλλο σκεφτείς, ευπρόσδεκτο.
bxenos Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 > float int2float(int n,int *intp,float *floatp) { unsigned int intValue; int i; int aux_s, aux_e, aux_f; float FloatValue2; for(i=0;i<n;i++){ intValue=*(intp+i); if(intValue==0 || intValue==0x80000000){ *(floatp+i)=0; continue; } else{ /* Separate the bytes like the IEEE-754 standard */ /* SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF */ aux_s = (1<<31) & intValue ) //Signal aux_e = (0x7F100000 & intValue ) >> 23; //Exponent aux_f = (0X007FFFFF & intValue ); //Fraction //Convert to float IEEE-754 //*(floatp+i) = εδω θελει περεταιρω βελτιστοποιηση... αλλά πάρε την απλή έκδοση *(floatp+i) = (1.0 - (aux_s<<1)) * (1<<(aux_e - 127)) * (((float)aux_f) / (1<<23)+1); } } } ο floatp σε τι μορφή θέλει τον αριθμό; θα μπορεσουμε να καταργήσουμε τελειως τις πραξεις κινητης υποδιαστολής με την πληροφορία αυτη ---------- Το μήνυμα προστέθηκε στις 02:42 ---------- φυσικά υπάρχει και το πιό απλό: > union { float f; unsigned u; struct { /* Separate the bytes like the IEEE-754 standard */ /* SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF */ unsigned aux_s:1; unsigned aux_e:8; unsigned auf_x:23; } bitfields; } βέβαια ανάλογα με το endianess του μικροεπεξεργαστη σου μπορεί να χρειαστεί να γίνει: > union { float f; unsigned u; struct { /* Separate the bytes like the IEEE-754 standard */ /* SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF */ unsigned auf_x:23; unsigned aux_e:8; unsigned aux_s:1; } bitfields; }; αν δεν καταλαβες πως να χρησιμοποιησεις το παραπάνω, εδω ειμαστε. υποθέτω ο int έχει 32bits, αλλιώς ο κωδικας που έγραψες αρχικά είναι λάθος. Λάθος είναι και η χρήση int αντί για unsigned λόγω της ειδικης χρησης του προσήμου του int κατα τις πράξεις.
Dr.Fuzzy Δημοσ. 25 Μαΐου 2009 Μέλος Δημοσ. 25 Μαΐου 2009 Ο floatp θέλει float. Ουσιαστικά είναι ένας πίνακας. Βασικά ο κώδικας παίρνει ένα πίνακα με τις ακέραιες τιμές (intp), το πλήθος των στοιχείων του πίνακα (n) και έναν allocated float πίνακα (floatp), loopάρει πάνω απ' όλες τις τιμές και μετατρέπει τα ints σε floats. Το endianess δεν είναι πρόβλημα. Ο προηγούμενος κώδικας που είχα δώσει δουλεύει σωστά αλλά αργά.
bxenos Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 το εισερχόμενο δηλαδή είναι SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF και το εξερχόμενο, τι πρέπει να είναι; (μην μου πεις IEEE και τετοια, δεν εχω όρεξη να ψάχνω - βάλε link αν εχεις ή γράψε κάποια σημειωση) ---------- Το μήνυμα προστέθηκε στις 02:53 ---------- > typedef union { float f; unsigned u; struct { /* Separate the bytes like the IEEE-754 standard */ /* SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF */ unsigned aux_s:1; unsigned aux_e:8; unsigned auf_x:23; } bitfields; } xtra; float translate(unsigned u){ xtra x; x.u = u; // return (1.0 - (x.bitfields.aux_s<<1)) * // ((float)(1<<(x.bitfields.aux_e - 127))) * // (((float)x.bitfields.aux_f) / (1<<23)+1.0); // τωρα τα x.bitfields.aux* είναι ενημερωμένα, πρπει να μου πείς τι μορφή έχει // το bitfield του float που θέλεις για να τα βάλουμε στην θέση τους // (αλήθεια, τι διαφορά έχει το matlab απο τον επεξεργαστη; // δεν κάνει απλά ένα *((float *)&IntValue); } Να τονίσω λίγο αυτό το κομάτι γιατι θέλει προσοχή: αλήθεια, τι διαφορά έχει το matlab απο τον επεξεργαστη; δεν κάνει απλά ένα > #define translate(u) * ( (float *)&(u) )
Dr.Fuzzy Δημοσ. 25 Μαΐου 2009 Μέλος Δημοσ. 25 Μαΐου 2009 Βασικά κοίτα πιο είναι το πρόβλημα. Έχω έναν float στο Matlab και τον στέλνω στη σειριακή. Το Matlab στέλνει τα 32bits, τα παίρνω με το board και τ' αποθηκεύω σε έναν 32bit int. Θέλω όμως να τα μετατρέψω σε float μέσα στο board, μόνο που το encoding είναι IEEE-754 ! Δηλαδή το standard format για τους single precision. Αυτή λοιπόν η μ@λ@κί@ θέλει μετατροπή ώστε να γίνει float πάνω στο board. Λινκ για το IEEE 754: http://en.wikipedia.org/wiki/IEEE_754-1985 ----- Η μορφή που στέλνει το Matlab είναι SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF. Ο προηγούμενος κώδικας που έδωσες χτυπάει. Επίσης, θα ήθελα να διατηρηθεί το definition της συνάρτησης με τα pointers γιατί κάνει batch convert.
bxenos Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 Αν κατάλαβα καλά έχει την ίδια μορφή αλλα έχει ερθει σε integer, αρα θέλεις μονο αυτό > #define translate(u) * ( (float *)&(u) ) οπότε > float int2float(int n,int *intp,float *floatp) { int i; for(i=0;i<n;i++) floatp[i] = translate(intp[i]); }
Dr.Fuzzy Δημοσ. 25 Μαΐου 2009 Μέλος Δημοσ. 25 Μαΐου 2009 Ένα απλό casting από int σε float δεν δουλεύει. Εγώ το αποθηκεύω σε int αλλά επειδή είναι encoded στο 745 θέλει μετατροπή. Δες εδώ.
bxenos Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 το pc σου στένει τα δεδομένα σε http://www.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF (SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF) μορφή. Ο μικροεπεξεργαστης σου σε τι μορφη τα θέλει; Το link σου απλά αναλύει πως εχουν αποθηκευτεί τα bits απο έναν αριθμό που δίνεις εσύ. Και εγώ έχω αναλύσει παλιότερα αυτό ------------add on------ εδω http://www.xilinx.com/publications/magazines/emb_03/xc_pdf/p30-33_3emb-fpu.pdf βλέπω ότι και ο microblaze 4.0 το ίδιο format χρησιμοποιεί, αρα μόνο στο casting πρέπει να βασιστείς. Υπάρχει ενδεχόμενο το endianess να είναι διαφορετικό, αν μπορείς κάνε post την binary αναπαράσταση ενός αριθμού float απο το matlab (π.χ. 1,2345) και τον ίδιο αριθμό σε binary αναπαράσταση στο Microblaze.
Evgenios1 Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 Βασικά κοίτα πιο είναι το πρόβλημα. Έχω έναν float στο Matlab και τον στέλνω στη σειριακή. Το Matlab στέλνει τα 32bits, τα παίρνω με το board και τ' αποθηκεύω σε έναν 32bit int. Μπορει και να πεταξω κοστανα . Γιατι το κανεις int ? Εφοσον περνεις εναν buffer απο bits γιατι δε το κανεις απευθειας float με bit shifting. Μεγαλες δυναμεις εχεις για εναν microcontroller, ποσα MHz ειναι, 20,30?
bxenos Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 Λοιπόν ο τρόπος μετατροπής αυτός θεωρώ ότι δεν ειναι ενδεδειγμένος (λογω ταχύτητας) και θα πρεπει να δεις το endianess του FPGA σου, διότι όπως είπα με τον ίδιο τρόπο βρήκα να αποθηκευονται οι αριθμοι float και στα pc και στο microblaze 4.0. Βρήκα και το λάθος στην απομάκρυνση των pow() [το ένα απο αυτά δεν μπορεί να φύγει και εξηγώ σε σχόλιο γιατι στην fpga3()]. παράδειγμα κωδικα: > #include <stdio.h> #include <math.h> #include <assert.h> typedef unsigned u; #pragma pack(1) typedef union { float f; u d; struct _bitfields_tag { /* Separate the bytes like the IEEE-754 standard */ /* SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF */ u aux_f:23; u aux_e:8; u aux_s:1; } bitfields; } xga; #pragma pack() void show_bits(u a){ u i;int j; for(i=0x80000000,j=0;i;i>>=1,j++){ if(j && (j%8==0)) putchar(' '); putchar(a & i ? '1' : '0'); } putchar('\n'); } float fpga(u intValue){ int aux_s,aux_e,aux_f; float x; printf("\nfpga:use of pow() functions\n"); /* Separate the bytes like the IEEE-754 standard */ /* SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF */ aux_s = (2147483648l & intValue ) / 2147483648l; //Signal aux_e = (2139095040l & intValue ) / 8388608l; //Exponent aux_f = (8388607l & intValue ); //Fraction printf("aux_s:");show_bits(aux_s); printf("aux_e:");show_bits(aux_e); printf("aux_f:");show_bits(aux_f); x = //Convert to float IEEE-754 (1.0 - 2.0*((float)aux_s)) * pow(2.0,aux_e - 127) * (((float)aux_f) / pow(2,23) + 1.0); printf("result (%f)=",x);show_bits(*(u*)&x); return x; } float fpga2(u intValue){ xga x; float t; x.d = intValue; printf("\nfpga2:use of bitfields union members\n"); printf("aux_s:");show_bits(x.bitfields.aux_s); printf("aux_e:");show_bits(x.bitfields.aux_e); printf("aux_f:");show_bits(x.bitfields.aux_f); /* Separate the bytes like the IEEE-754 standard */ /* SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF */ t = //Convert to float IEEE-754 (1.0 - 2.0*x.bitfields.aux_s) * pow(2.0,x.bitfields.aux_e - 127) * (((float)x.bitfields.aux_f) / pow(2,23) + 1.0); printf("result (%f)=",t);show_bits(*(u*)&t); return t; } float fpga3(u intValue){ xga x; float t; x.d = intValue; printf("\nfpga3:use of bitfields union members and reduce pow()\n"); t = //Convert to float IEEE-754 (1.0 - (float)(x.bitfields.aux_s<<1)) //(1.0 - 2.0*x.bitfields.aux_s) * pow(2,x.bitfields.aux_e - 127) //εδω δεν μπορουμε να βγαλουμε το pow γιατι εχουμε πρόβλημα σε aux_e>127+32 * ((float)x.bitfields.aux_f / (1<<23) + 1.0); //(((float)aux_f) / pow(2,23) + 1.0); printf("result (%f)=",t);show_bits(*(u*)&t); return t; } int main(void){ float a = 1.2345; assert(sizeof(u)==sizeof(float)); assert(sizeof(u)==4); show_bits(*(u*)&a); fpga(*(u*)&a); fpga2(*(u*)&a); fpga3(*(u*)&a); return 0; } και αποτελέσματα απο κονσόλα: > x.c Microsoft (R) 32-Bit Incremental Linker Version 5.00.7022 Copyright (C) Microsoft Corp 1992-1997. All rights reserved. /out:x.exe x.obj 00111111 10011110 00000100 00011001 fpga:use of pow() functions aux_s:00000000 00000000 00000000 00000000 aux_e:00000000 00000000 00000000 01111111 aux_f:00000000 00011110 00000100 00011001 result (1.234500)=00111111 10011110 00000100 00011001 fpga2:use of bitfields union members aux_s:00000000 00000000 00000000 00000000 aux_e:00000000 00000000 00000000 01111111 aux_f:00000000 00011110 00000100 00011001 result (1.234500)=00111111 10011110 00000100 00011001 fpga3:use of bitfields union members and reduce pow() result (1.234500)=00111111 10011110 00000100 00011001
Dr.Fuzzy Δημοσ. 25 Μαΐου 2009 Μέλος Δημοσ. 25 Μαΐου 2009 Βασικά με έβαλες σε σκέψεις (ξανά) για το conversion. Στην αρχή και εγώ θα έλεγα ότι το απλό cast int->float θα έπρεπε να δουλεύει. Όμως δεν φαίνεται να συμβαίνει κάτι τέτοιο. Παράδειγμα: Στέλνω από τον matlab το -148129 (fwrite(obj,-148129,'float32'); ). Ο int που κάνω reconstruct στο board είναι 0xc810a840. Αν κάνω cast σε float μου δίνει 0xc810a880. Τώρα, στην πρώτη περίπτωση η decimal τιμή που μου εμφανίζει ο debugger είναι -938432448 και στη δεύτερη -938432384. Αν πας στο link που είχα δώσει για το conversion (εδώ) και βάλεις τις δυο hex τιμές ( 0xc810a840 - 0xc810a880) θα σου βγάλει -148129 ! Οπότε, απ' ότι καταλαβαίνω το απλό cast int to float δεν φαίνεται να δουλεύει (αν και θα έπρεπε - μάλλον). Να σημειώσω ότι ένα αντίστοιχο cast στο matlab απλά κάνει την int τιμή σε float, ενώ αν κάνεις cast float to int κάνει round τον float στην κοντινότερη int τιμή μέσα στη δυναμική περιοχή.
bxenos Δημοσ. 25 Μαΐου 2009 Δημοσ. 25 Μαΐου 2009 Τα νούμερα θα τα ελένξω και μάλον θα βγεί άκρη. Θα ήθελα όμως να μου γράψεις και την εντολή που έκανες cast τον int σε float στο FPGA. To cast που έχω προαναφέρει δεν είναι απλά float f = (float)intValue
Dr.Fuzzy Δημοσ. 25 Μαΐου 2009 Μέλος Δημοσ. 25 Μαΐου 2009 Το cast το κάνω στον debugger. Έχω βάλει watch και είτε γράφω (float) *var είτε το πάω μέσω μενού (έχει εντολή cast to type...) μου βγάζει το ίδιο αποτέλεσμα.
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.