Skip to content

Commit 1527ea6

Browse files
committed
dev
1 parent 4963dd4 commit 1527ea6

File tree

1 file changed

+121
-60
lines changed

1 file changed

+121
-60
lines changed

wfdb/_signals.py

Lines changed: 121 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
434434
# Then continue to process the read values into proper samples
435435
if fmt == '212':
436436

437+
# Clear memory???
438+
437439
# No extra samples/frame. Obtain original uniform numpy array
438440
if tsampsperframe==nsig:
439441

@@ -445,17 +447,56 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
445447
sig = sig[blockfloorsamples:]
446448

447449
# Reshape into multiple channels
448-
sig= sig.reshape(-1, nsig)
450+
sig = sig.reshape(-1, nsig)
449451

450452
# Skew the signal
451453
sig = skewsig(sig, skew, nsig, readlen)
452454

453455
# Extra frames present to be smoothed. Obtain averaged uniform numpy array
454456
elif smoothframes:
455-
pass
457+
458+
# Turn the bytes into actual samples. Flat 1d array. All samples for all frames.
459+
sigflat = bytes2samples(sigbytes, totalprocesssamples, fmt)
460+
461+
# Remove extra leading sample read within the byte block if any
462+
if blockfloorsamples:
463+
sigflat = sigflat[blockfloorsamples:]
464+
465+
# Smoothed signal
466+
sig = np.zeros(int(len(sigflat)/tsampsperframe) , nsig)
467+
468+
# Transfer and average samples
469+
for ch in range(nsig):
470+
if sampsperframe[ch] == 1:
471+
sig[:, ch] = sigflat[sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
472+
else:
473+
for frame in range(sampsperframe[ch]):
474+
sig[:, ch] += sigflat[sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
475+
sig = (sig / sampsperframe)
476+
477+
# Skew the signal
478+
sig = skewsig(sig, skew, nsig, readlen)
479+
456480
# Extra frames present without wanting smoothing. Return all expanded samples.
457481
else:
458-
pass
482+
# Turn the bytes into actual samples. Flat 1d array. All samples for all frames.
483+
sigflat = bytes2samples(sigbytes, totalprocesssamples, fmt)
484+
485+
# Remove extra leading sample read within the byte block if any
486+
if blockfloorsamples:
487+
sigflat = sigflat[blockfloorsamples:]
488+
489+
# Arranged signals
490+
sig = []
491+
492+
# Transfer over samples
493+
for ch in range(nsig):
494+
# Indices of the flat signal that belong to the channel
495+
ch_indices = np.concatenate([np.array(range(sampsperframe[ch])) + tsampsperframe*framenum for framenum in range(int(len(sigflat)/tsampsperframe))])
496+
sig.append(sigflat[ch_indices])
497+
498+
# Skew the signal
499+
sig = skewsig(sig, skew, nsig, readlen, sampsperframe)
459500

460501
elif fmt == '310':
461502
pass
@@ -465,12 +506,16 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
465506
else:
466507
# Adjust for skew, reshape, and consider sampsperframe.
467508

509+
# Adjust for byte offset formats
510+
if fmt == '80':
511+
sigbytes = sigbytes - 128
512+
elif fmt == '160':
513+
sigbytes = sigbytes - 32768
514+
468515
# No extra samples/frame. Obtain original uniform numpy array
469516
if tsampsperframe==nsig:
470517

471-
# Reshape the array into the correct number of channels
472-
# At this point, cannot reshape(readlen, nsig) because there might
473-
# be extra skew samples
518+
# Reshape into multiple channels
474519
sig = sigbytes.reshape(-1, nsig).astype('int')
475520

476521
# Skew the signal
@@ -496,23 +541,25 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
496541
else:
497542
# List of 1d numpy arrays
498543
sig=[]
544+
545+
# Transfer over samples
499546
for ch in range(nsig):
500-
chansig = np.zeros(readlen*sampsperframe[ch], dtype='int')
501-
for frame in range(sampsperframe[ch]):
502-
chansig[frame::sampsperframe[ch]] = sigbytes[skew[ch]*tsampsperframe+sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
547+
# chansig = np.zeros(readlen*sampsperframe[ch], dtype='int')
548+
# for frame in range(sampsperframe[ch]):
549+
# chansig[frame::sampsperframe[ch]] = sigbytes[skew[ch]*tsampsperframe+sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
550+
# sig.append(chansig)
503551

504-
sig.append(chansig)
552+
ch_indices = np.concatenate([np.array(range(sampsperframe[ch])) + tsampsperframe*framenum for framenum in range(int(len(sigflat)/tsampsperframe))])
553+
sig.append(sigbytes[ch_indices])
505554

506-
# Adjust for byte offset formats
507-
if fmt == '80':
508-
sig = sig - 128
509-
elif fmt == '160':
510-
sig = sig - 32768
555+
# Skew the signal
556+
sig = skewsig(sig, skew, nsig, readlen, sampsperframe)
511557

558+
# Integrity check of signal shape after reading
559+
checksigdims(sig, readlen, nsig, sampsperframe)
512560

513561
return sig
514562

515-
516563
def calc_read_params(fmt, siglen, byteoffset, skew, tsampsperframe, sampfrom, sampto):
517564
"""
518565
Calculate parameters used to read and process the dat file
@@ -579,6 +626,44 @@ def calc_read_params(fmt, siglen, byteoffset, skew, tsampsperframe, sampfrom, sa
579626

580627
return (startbyte, nreadsamples, blockfloorsamples, extraflatsamples, nanreplace)
581628

629+
def requiredbytenum(mode, fmt, nsamp):
630+
"""
631+
Determine how many signal bytes are needed to read a file, or now many
632+
should be written to a file, for special formats.
633+
634+
Input arguments:
635+
- mode: 'read' or 'write'
636+
- fmt: format
637+
- nsamp: number of samples
638+
639+
It would be nice if read and write were the same, but fmt 311 for
640+
n_extra == 2 ruins it.
641+
"""
642+
643+
if fmt == '212':
644+
nbytes = math.ceil(nsamp*1.5)
645+
elif fmt in ['310', '311']:
646+
n_extra = nsamp % 3
647+
648+
if n_extra == 2:
649+
if fmt == '310':
650+
nbytes = upround(nsamp * 4/3, 4)
651+
# 311
652+
else:
653+
if mode == 'read':
654+
nbytes = math.ceil(nsamp * 4/3)
655+
# Have to write more bytes for wfdb c to work
656+
else:
657+
nbytes = upround(nsamp * 4/3, 4)
658+
# 0 or 1
659+
else:
660+
nbytes = math.ceil(nsamp * 4/3 )
661+
else:
662+
nbytes = nsamp * bytespersample[fmt]
663+
664+
return int(nbytes)
665+
666+
582667
def getdatbytes(filename, dirname, pbdir, fmt, startbyte, nsamp):
583668
"""
584669
Read bytes from a dat file, either local or remote, into a numpy array.
@@ -658,63 +743,29 @@ def bytes2samples(sigbytes, nsamp, fmt):
658743
sig[sig > 2047] -= 4096
659744
sig[sig > 2047] -= 4096
660745

661-
elif fmt == '310':
746+
elif fmt == '310':
747+
pass
662748

663749
elif fmt == '311':
664-
750+
pass
665751
return sig
666752

667753

668-
669-
def requiredbytenum(mode, fmt, nsamp):
670-
"""
671-
Determine how many signal bytes are needed to read a file, or now many
672-
should be written to a file, for special formats.
673-
674-
Input arguments:
675-
- mode: 'read' or 'write'
676-
- fmt: format
677-
- nsamp: number of samples
678-
679-
It would be nice if read and write were the same, but fmt 311 for
680-
n_extra == 2 ruins it.
681-
"""
682-
683-
if fmt == '212':
684-
nbytes = math.ceil(nsamp*1.5)
685-
elif fmt in ['310', '311']:
686-
n_extra = nsamp % 3
687-
688-
if n_extra == 2:
689-
if fmt == '310':
690-
nbytes = upround(nsamp * 4/3, 4)
691-
# 311
692-
else:
693-
if mode == 'read':
694-
nbytes = math.ceil(nsamp * 4/3)
695-
# Have to write more bytes for wfdb c to work
696-
else:
697-
nbytes = upround(nsamp * 4/3, 4)
698-
# 0 or 1
699-
else:
700-
nbytes = math.ceil(nsamp * 4/3 )
701-
else:
702-
nbytes = nsamp * bytespersample[fmt]
703-
704-
return int(nbytes)
705-
706754
# Skew the signal and shave off extra samples
707-
def skewsig(sig, skew, nsig, readlen):
755+
def skewsig(sig, skew, nsig, readlen, sampsperframe):
708756

709757
if max(skew)>0:
710758

711759
# Expanded frame samples. List of arrays.
712760
if type(sig) == list:
713761
# Shift the channel samples
714-
762+
for ch in range(nsig):
763+
if skew[ch]>0:
764+
sig[ch][:readlen*sampsperframe[ch]] = sig[ch][skew[ch]*sampsperframe[ch]:]
715765

716766
# Shave off the extra signal length at the end
717-
767+
for ch in range(nsig):
768+
sig[ch] = sig[ch][:readlen*sampsperframe[ch]]
718769

719770
# Insert nans where skewed signal overran dat file
720771
for ch in range(nsig):
@@ -737,7 +788,17 @@ def skewsig(sig, skew, nsig, readlen):
737788
return sig
738789

739790

740-
791+
# Integrity check of signal shape after reading
792+
def checksigdims(sig, readlen, nsig, sampsperframe):
793+
if type(sig) == np.ndarray:
794+
if sig.shape != (readlen, nsig):
795+
raise ValueError('Samples were not loaded correctly')
796+
else:
797+
if len(sig) != nsig:
798+
raise ValueError('Samples were not loaded correctly')
799+
for ch in range(nsig):
800+
if len(sig[ch]) != sampsperframe[ch] * readlen
801+
raise ValueError('Samples were not loaded correctly')
741802

742803

743804

0 commit comments

Comments
 (0)