Lab-Measurement-Legacy
view release on metacpan or search on metacpan
lib/Lab/Data/Analysis/WaveRunner.pm view on Meta::CPAN
$len = 8;
my (@long) = unpack( '(LL)' . $ord, substr( $wdata, $p, $len ) );
@long = reverse(@long) if $ord eq '<';
# print "ord: $ord\n";
# printf("Double in: MSB 0x%08x LSB %08x\n",@long);
$a->{VALUE} = _double(@long);
}
elsif ( $a->{TYPE} eq 'time_stamp' ) {
$len = 16;
my ( $s1, $s2, $m, $h, $d, $mo, $y, $un )
= unpack( '(LLccccss)' . $ord, substr( $wdata, $p, $len ) );
( $s1, $s2 ) = reverse( $s1, $s2 ) if $ord eq '<';
my $sec = _double( $s1, $s2 );
my $sstr = sprintf( '%.12f', $sec );
$sstr = '0' . $sstr if $sec < 10;
$a->{VALUE} = sprintf(
'%04d-%02d-%02d %02d:%02d:%s',
$y, $mo, $d, $h, $m, $sstr
);
}
elsif ( $a->{TYPE} eq 'unit_definition' ) {
$len = 48;
$a->{VALUE} = _trimNul( substr( $wdata, $p, $len ) );
}
elsif ( $a->{TYPE} eq 'enum' ) {
$len = 2;
my $ne = sprintf(
'%d',
unpack( 'S' . $ord, substr( $wdata, $p, $len ) )
);
$a->{VALUE} = $a->{ENUM}->{$ne};
}
elsif ( $a->{TYPE} eq 'text' ) {
$len = length($wdata);
$a->{VALUE} = _trimNul( substr( $wdata, $p ) );
}
else {
carp( "unknown waveform field type: " . $a->{TYPE} );
return undef;
}
$a->{LENGTH} = $len;
return $a;
}
# IEEE754 single precision (binary32): assumes MSB data ('>')
sub _float {
my $str = shift;
my $s = ( $str >> 31 ) & 0x0001;
my $e = ( $str >> 23 ) & 0x00FF;
my $f = $str & 0x007FFFFF;
my $w = ( 2**( $e - 127 ) ) * ( 1 + ( $f / 0x00800000 ) );
$w = -$w if $s;
return $w;
}
sub double_from_hex { unpack 'd', scalar reverse pack 'H*', $_[0] }
use constant POS_INF => double_from_hex '7FF0000000000000';
use constant NEG_INF => double_from_hex 'FFF0000000000000';
use constant NaN => double_from_hex '7FF8000000000000';
sub _double # assumes MSB data input
{
# my ($bytes) = @_;
# my ($bottom, $top) = unpack ("LL", $bytes);
my ( $top, $bottom ) = @_;
# Reference:
# http://en.wikipedia.org/wiki/Double_precision_floating-point_format
# Eight zero bytes represents 0.0.
if ( $bottom == 0 ) {
if ( $top == 0 ) {
return 0;
}
elsif ( $top == 0x80000000 ) {
return -0;
}
elsif ( $top == 0x7ff00000 ) {
return POS_INF;
}
elsif ( $top == 0xfff00000 ) {
return NEG_INF;
}
}
elsif ( $top == 0x7ff00000 ) {
return NaN;
}
my $sign = $top >> 31;
# print "sgn $sign\n";
my $exponent = ( ( $top >> 20 ) & 0x7FF ) - 1023;
# print "e = $exponent\n";
my $e = ( $top >> 20 ) & 0x7FF;
my $t = $top & 0xFFFFF;
# printf ("--> !%011b%020b \n--> %032b\n", $e, $t, $top);
my $mantissa = ( $bottom + ( $t * ( 2**32 ) ) ) / 2**52 + 1;
# print "mant: $mantissa\n";
my $double = (-1)**$sign * 2**$exponent * $mantissa;
# print "double result: $double\n";
return $double;
}
# IEEE754 double precision (binary64)
#sub _Xdouble {
# my $str = shift;
# my $s = ($str >> 63) & 0x1;
# my $e = ($str >> 52) & 0x7FF;
# my $f = $str & 0x000FFFFFFFFFFFFF ;
# my $w = (2**($e-1023))*(1+$f/0x0010000000000000);
# $w = -$w if $s;
# return $w;
#}
sub _interpolate {
my $h = shift; # hash pointer to {CHAN}->{$ch}
if ( ref($h) ne 'HASH' ) {
carp("bad hash pointer for wfd interpolation");
return undef;
}
my $x = shift;
return undef if $x < $h->{XMIN} || $x > $h->{XMAX};
my $nx = ( $x - $h->{XMIN} ) / $h->{DX};
my $nx0 = int($nx);
my ( $y0, $y1, $ry0, $ry1 );
if ( exists( $h->{Y} ) ) {
$y0 = $h->{Y}->[$nx0];
$y1 = $h->{Y}->[ $nx0 + 1 ];
return $y0 + ( $y1 - $y0 ) * ( $nx - $nx0 );
}
else {
$y0 = $h->{Y0}->[$nx0];
$y1 = $h->{Y0}->[ $nx0 + 1 ];
$ry0 = ( $y1 - $y0 ) * ( $nx - $nx0 );
$y0 = $h->{Y1}->[$nx0];
$y1 = $h->{Y1}->[ $nx0 + 1 ];
$ry1 = ( $y1 - $y0 ) * ( $nx - $nx0 );
return ( $ry0, $ry1 );
}
}
( run in 1.029 second using v1.01-cache-2.11-cpan-39bf76dae61 )