@@ -42,8 +42,6 @@ def wr_dats(self, expanded, write_dir):
42
42
self .wr_dat_files (expanded = expanded , write_dir = write_dir )
43
43
44
44
45
-
46
-
47
45
def check_sig_cohesion (self , write_fields , expanded ):
48
46
"""
49
47
Check the cohesion of the d_signal/e_d_signal field with the other
@@ -488,78 +486,94 @@ def dac(self, expanded=False, return_res=64, inplace=False):
488
486
489
487
def calc_adc_params (self ):
490
488
"""
491
- Compute appropriate adc_gain and baseline parameters given the
492
- physical signal and the fmts.
489
+ Compute appropriate adc_gain and baseline parameters for adc
490
+ conversion, given the physical signal and the fmts.
491
+
492
+ Returns
493
+ -------
494
+ adc_gains : list
495
+ List of calculated `adc_gain` values for each channel.
496
+ baselines : list
497
+ List of calculated `baseline` values for each channel.
498
+
499
+ Notes
500
+ -----
501
+ This is the mapping equation:
502
+ `digital - baseline / adc_gain = physical`
503
+ `physical * adc_gain + baseline = digital`
504
+
505
+ The original WFDB library stores `baseline` as int32.
506
+ Constrain abs(adc_gain) <= 2**31 == 2147483648
507
+
508
+ This function does carefully deal with overflow for calculated
509
+ int32 `baseline` values, but does not consider over/underflow
510
+ for calculated float `adc_gain` values.
493
511
494
- digital - baseline / adc_gain = physical
495
- physical * adc_gain + baseline = digital
496
512
"""
497
513
adc_gains = []
498
514
baselines = []
499
515
500
516
if np .where (np .isinf (self .p_signal ))[0 ].size :
501
- raise ValueError ('Signal contains inf. Cannot convert .' )
517
+ raise ValueError ('Signal contains inf. Cannot perform adc .' )
502
518
503
519
# min and max ignoring nans, unless whole channel is nan.
504
520
# Should suppress warning message.
505
521
minvals = np .nanmin (self .p_signal , axis = 0 )
506
522
maxvals = np .nanmax (self .p_signal , axis = 0 )
507
523
508
- dnans = digi_nan (self .fmt )
509
-
510
524
for ch in range (np .shape (self .p_signal )[1 ]):
511
525
# Get the minimum and maximum (valid) storage values
512
526
dmin , dmax = digi_bounds (self .fmt [ch ])
513
527
# add 1 because the lowest value is used to store nans
514
528
dmin = dmin + 1
515
- dnan = dnans [ch ]
516
529
517
530
pmin = minvals [ch ]
518
531
pmax = maxvals [ch ]
519
532
520
- # map values using full digital range.
533
+ # Figure out digital samples used to store physical samples
521
534
522
- # If the entire signal is nan, just put any.
535
+ # If the entire signal is nan, gain/baseline won't be used
523
536
if pmin == np .nan :
524
537
adc_gain = 1
525
538
baseline = 1
526
- # If the signal is just one value, store all values as 1 .
539
+ # If the signal is just one value, store one digital value .
527
540
elif pmin == pmax :
528
541
if pmin == 0 :
529
542
adc_gain = 1
530
543
baseline = 1
531
544
else :
532
- adc_gain = 1 / pmin
545
+ # All digital values are +1 or -1. Keep adc_gain > 0
546
+ adc_gain = abs (1 / pmin )
533
547
baseline = 0
534
- # Regular varied signal case. Map pmax->dmax, pmin->dmin
548
+ # Regular varied signal case.
535
549
else :
536
550
# The equation is: p = (d - b) / g
537
- # pmax maps to dmax, and pmin maps to dmin. Gradient
538
- # will be close to delta(d) / delta(p), since intercept
539
- # baseline has to be an integer.
551
+ # Approximately, pmax maps to dmax, and pmin maps to
552
+ # dmin. Gradient will be equal to, or close to
553
+ # delta(d) / delta(p), since intercept baseline has
554
+ # to be an integer.
540
555
adc_gain = (dmax - dmin ) / (pmax - pmin )
541
556
baseline = dmin - adc_gain * pmin
542
- # The baseline needs to be an integer
557
+ # Make adjustments for baseline to be an integer
558
+
559
+ # This up/down round logic of baseline is to ensure
560
+ # there is no overshoot of dmax. Now pmax will map
561
+ # to dmax or dmax-1 which is also fine.
543
562
if pmin > 0 :
544
563
baseline = int (np .ceil (baseline ))
545
564
else :
546
565
baseline = int (np .floor (baseline ))
547
566
548
- # We set the gain to map pmin to dmin, and p=0 to
567
+ # Set the gain to map pmin to dmin, and p= =0 to
549
568
# baseline.
550
-
551
- # This up/down round logic of baseline is to ensure
552
- # there is no overshoot of dmax. Now pmax will map to
553
- # dmax or dmax-1 which is also fine.
554
-
555
- # In case where pmin == 0 and dmin == baseline,
569
+ # In the case where pmin == 0 and dmin == baseline,
556
570
# adc_gain is already correct. Avoid dividing by 0.
557
571
if dmin != baseline :
558
572
adc_gain = (dmin - baseline ) / pmin
559
573
560
- # WFDB library limits.. .
561
- if abs (adc_gain ) > 2147483648 or abs ( baseline )> 2147483648 :
562
- raise Exception ('adc_gain and baseline must have magnitudes < 2147483648' )
574
+ # Safety check for WFDB library limit .
575
+ if abs (baseline )> 2147483648 :
576
+ raise Exception ('baseline must have magnitude < 2147483648' )
563
577
564
578
adc_gains .append (adc_gain )
565
579
baselines .append (baseline )
@@ -1311,7 +1325,7 @@ def est_res(signals):
1311
1325
res .append (0 )
1312
1326
else :
1313
1327
nlevels = 1 + (sortedsig [- 1 ]- sortedsig [0 ])/ min_inc
1314
- if nlevels >= res_levels [- 1 ]:
1328
+ if nlevels >= res_levels [- 1 ]:
1315
1329
res .append (32 )
1316
1330
else :
1317
1331
res .append (np .where (res_levels >= nlevels )[0 ][0 ])
0 commit comments