user2829
user2829

Reputation: 461

Perl pack and unpack functions

I am trying to unpack a variable containing a string received from a spectrum analyzer:

#42404?û¢-+Ä¢-VÄ¢-oÆ¢-8æ¢-bÉ¢-ôÿ¢-+Ä¢-?Ö¢-sÉ¢-ÜÖ¢-¦ö¢-=Æ¢-8æ¢-uô¢-=Æ¢-\Å¢-uô¢-?ü¢-}¦¢-=Æ¢-)...

The format is real 32 which uses four bytes to store each value. The number #42404 represents 4 extra bytes present and 2404/4 = 601 points collected. The data starts after #42404. Now when I receive this into a string variable,

$lp = ibqry($ud,":TRAC:DATA? TRACE1;*WAI;");

I am not sure how to convert this into an array of numbers :(... Should I use something like the followin?

@dec = unpack("d", $lp);

I know this is not working, because I am not getting the right values and the number of data points for sure is not 601...

Upvotes: 2

Views: 3219

Answers (2)

Ilmari Karonen
Ilmari Karonen

Reputation: 50338

If the first 4 encodes the number of remaining digits (2404) before the floats, then something like this might work:

my @dec = unpack "x a/x f>*", $lp;

The x skips the leading #, the a/x reads one digit and skips that many characters after it, and the f>* parses the remaining string as a sequence of 32-bit big-endian floats. (If the output looks weird, try using f<* instead.)

Upvotes: 1

Schwern
Schwern

Reputation: 164919

First, you have to strip the #42404 off and hope none of the following binary data happens to be an ASCII number.

$lp =~ s{^#\d+}{};

I'm not sure what format "Real 32" is, but I'm going to guess that it's a single precision floating point which is 32 bits long. Looking at the pack docs. d is "double precision float", that's 64 bits. So I'd try f which is "single precision".

@dec = unpack("f*", $lp);

Whether your data is big or little endian is a problem. d and f use your computer's native endianness. You may have to force endianness using the > and < modifiers.

@dec = unpack("f*>", $lp);  # big endian
@dec = unpack("f*<", $lp);  # little endian

Upvotes: 5

Related Questions