Uživatel:Kychot/emg.pm

Z Wikiverzity
#! /usr/bin/perl -w
# emg.pm = modul: společná část programů pro emg:
# version 0.48  oprava *EXPFILE
# doplněna dokumentace za konec souboru

package emg;		# balík pro emgdb.pl

#use Exporter;
use Exporter ();
@ISA = qw(Exporter);
#@EXPORT_OK = qw($allcddir @database time2isodatetime isodate usec2timestr db_connect invfile expfilehdr);
#@EXPORT = qw($allcddir @database $EXPFILE time2isodatetime isodate usec2timestr timestr2usec
@EXPORT = qw($allcddir $outdir $gdfdir @database time2isodatetime isodate usec2timestr timestr2usec
             db_connect invfile expfilehdr);

# $invstruct $expstruct $isodatetimefmt

use strict;
#use DBI;
#use Symbol;
#qualify ($dbh);
use Date::Format;	# time2str()

my $dbname      = 'emgdb';
my $hostname    = 'localhost';
my $user        = 'emg';
my $password    = 'blablabla';

#$emg::allcddir  = "../../CD/";  # directory of all CD-subdirs
$emg::allcddir  = "../CD/";  # directory of all CD-subdirs
#$emg::allcddir = "/Data60G/huge/EMG/CD/";
$emg::outdir	= "out/";
$emg::gdfdir	= "/Data60G/huge/EMG/DebiandataGDF";


@emg::database = ("DBI:mysql:database=$dbname; host=$hostname", $user, $password);
#$emg::EXPFILE;	# open handle of the file.exp

my $invstruct =	# Ca = délka řetězce + max. délka:
    'Ca15'.	# rodné číslo+poj
    'Ca8'.	# datum narození
    'Ca15'.	# Jméno
    'Ca15'.	# Příjmení
    'Ca8'.	# datum vyšetření
    'C'.	# sex 0=male, 1=female
    'C8'.	# různá čísla, jako věk, výška atd.
    'Ca15'.	# číslo vyšetření a kdovíco (např: MFS konc2)
    'Ca15'.	# odd.: amb.
    'Ca15'.	# dg.: MFS trapez
     #'C6';	# kdovíco na konci
     'C2'.	# 2 byte
     'L';		# 4 byte = unsigned integer
     # CELKEM: 1+15 + 1+8 + 1+15 + 1+15 + 1+8 + 1 + 8 + 1+15 + 1+15 + 1+15 + 6 =
     # 16 + 9 + 16 + 16 + 9 + 1 + 8 + 16 + 16 + 16 + 6 = 6*16+3*9+6 = 96+27+6=129

my $expstruct =
    'S'.	# unsigned short $nchan			počet kanálů
    'S';	# unsigned short $sample_int_us		vzorkovací interval v mikrosekundách
                # dále následuje $nchan krát unsigned short $sensitivity[$ch] v [uV/Div]
                # 1 Div = 409.6 AD-levels, neboť celý rozsah = 10 Div = 2 ** 12 = 4096 levels pro 12-bit A/D
# vzorkování: 20 kHz ... 50 us = 0x0032;  5 kHz ... 200 us = 0x00C8;

sub time2isodatetime {
    my ($time) = @_;
#   time2str($isodatetimefmt, $time);
    time2str("%Y-%m-%dT%H:%M:%S", $time);
}

sub getstr {			# get string from array: length, value
    my ($ar) = @_;		# array reference
    my $len = shift @$ar;	# délka stringu
    substr (shift(@$ar), 0, $len);
}

sub isodate {			# doplní pomlčky
    my ($s) = @_;
    substr($s,0,4).'-'.substr($s,4,2).'-'.substr($s,6,2); 
}

sub usec2timestr {               # převede mikrosekundy na string mm:ss.sssss
    my($us) = @_;
    my $sign = '';
    if($us eq '--') {return $us};	# nedefinovaná hodnota
    if($us < 0) {$sign = '-'; $us = -$us;}
    my $sec = int($us/1000000); $us  -= 1000000*$sec;
    my $min = int($sec/60);     $sec -= 60*$min;
    sprintf ("%s%02d:%02d.%05d", $sign, $min, $sec, $us/10);
}

sub timestr2usec {		# převete string mm:ss.sssss na us
    my($_) = @_;
    if(/(\d+):(\d+(\.d+)?)/){
        1000000 * (60*$1 + $2);
    } else { return undef;}
}

sub db_connect {
    #my $dbh = DBI->connect($dsn, $user, $password, { PrintWarn=>1,RaiseError=>1,AutoCommit=>0 })
    my $dbh = DBI->connect(@emg::database, { PrintWarn=>1,RaiseError=>1,AutoCommit=>0 })
        or die "Chyba připojení k databázi č. $DBI::err: $DBI::errstr\n";
                                                    # uplatní se jen při RaiseError=>0
    $dbh->do("SET NAMES `utf8`");
    $dbh;
}

sub invfile {			# přečte invfile a vrátí strukturu
    my($invfile) = @_;		# jméno souboru *.INV
    $invfile = $emg::allcddir.$invfile;
    my $buf;
    my @inv;
    unless(open INVFILE, $invfile){
        print STDERR "Nemohu otevřít INV soubor $invfile: $!\n";
        return ();
    }
    my $lengthoffile= read INVFILE, $buf, 200;
    print("\n$invfile:\n\tnačteno:\t$lengthoffile B, délka bufferu ". length($buf) . "\n")
        if $lengthoffile != 129;
    @inv = unpack $invstruct, $buf;
    my @fstat = stat(INVFILE);
    my $mtime = time2isodatetime($fstat[9]);
    my %inv = (
         rc	=> getstr(\@inv),	# rodné číslo+poj
         birth	=> getstr(\@inv), 	# datum narození
         name	=> getstr(\@inv), 	# Jméno
         surname=> getstr(\@inv), 	# Příjmení
         invdate=> getstr(\@inv), 	# datum vyšetření
         sex	=> shift @inv,		# sex 0=male, 1=female
         n1	=> shift @inv,		# různá čísla, jako věk, výška atd.
         n2	=> shift @inv,
         n3	=> shift @inv,
         n4	=> shift @inv,
         n5	=> shift @inv,
         n6	=> shift @inv,
         n7	=> shift @inv,
         n8	=> shift @inv,
         invcomm=> getstr(\@inv),	# číslo vyšetření a kdovíco (např: MFS konc2)
         depart	=> getstr(\@inv),	# odd.: amb.
         dg	=> getstr(\@inv),	# dg.: MFS trapez
	 h1	=> shift @inv,		# kdovíco na konci
	 h2	=> shift @inv,
	 #h3	=> shift @inv,
	 #h4	=> shift @inv,
	 #h5	=> shift @inv,
	 #h6	=> shift @inv,
	 t	=> shift @inv,
	 mtime	=> $mtime
    );
    close INVFILE;
    return %inv;
}

sub expfilehdr {		# přečte hlavičku EXP souboru
    local (*EXPFILE) = @_;	# handle otevřeného souboru .EXP
    my $rv;
    $rv = sysread(EXPFILE, my $buf, 4) or die "Nemohu číst z EXPFILE ($rv):$!:\n";
    my ($nchan, $sample_int_us) = my @exphdr = unpack $expstruct, $buf;
    $rv = sysread(EXPFILE, $buf, 2*$nchan) or die "Nemohu dočíst EXPFILE ($rv):$!:\n"; #Citlivosti kan.
    push @exphdr, unpack 'S' x $nchan, $buf;
    @exphdr;
}

1;

__END__

Export file format
------------------
The *.EXP file is binary.
Each item is stored in two bytes (Integer), i.e. 16-bit, lower endian (i.e. lower byte goes first)
The abbreviation nchan = Number of used input (acquired) channels.
NOTE that processing channels are not exported.

Items Usage (i.e. 16-bit numbers from beginning of the file):

Offset:		Explanation:

0:		Number of channels

1:		Sample interval in [μsec/AD], i.e. time between samples. Common for all channels.

2..(1+nchan):	Input sensitivity in [μV/Div] for each channel. 1 Div = 409.6 AD-levels (12bit = 4096 / 10 Div).

(2+nchan+1)..End of file:
		Samples multiplexed (2 channel example):
		Channel1-Sample1 (16-bit signed int)
		Channel2-Sample1
		Channel1-Sample2
		Channel2-Sample2
		etc.

NOTE Values are in the range ±2047, which corresponds to ±5 Div.

Common example: Input sensitivity (i.e. gain) = 10 uV/Div
Then:
* full range -5 Div .. +5 Div corresponds -50 uV .. +50 uV
* 1 AD-level corresponds 100 uV/4096 = 0.0244140625 uV

---

Vzorkování 20 kHz, 4 kanály => 20*2*4 = 160 kB/s = 0.16 MB/s
160 kB/s * 60 s/min = 9.6 MB/min