Skip to content

Commit bf49bec

Browse files
committed
clean variables for adc
1 parent 150371e commit bf49bec

File tree

1 file changed

+44
-30
lines changed

1 file changed

+44
-30
lines changed

wfdb/io/_signal.py

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ def wr_dats(self, expanded, write_dir):
4242
self.wr_dat_files(expanded=expanded, write_dir=write_dir)
4343

4444

45-
46-
4745
def check_sig_cohesion(self, write_fields, expanded):
4846
"""
4947
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):
488486

489487
def calc_adc_params(self):
490488
"""
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.
493511
494-
digital - baseline / adc_gain = physical
495-
physical * adc_gain + baseline = digital
496512
"""
497513
adc_gains = []
498514
baselines = []
499515

500516
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.')
502518

503519
# min and max ignoring nans, unless whole channel is nan.
504520
# Should suppress warning message.
505521
minvals = np.nanmin(self.p_signal, axis=0)
506522
maxvals = np.nanmax(self.p_signal, axis=0)
507523

508-
dnans = digi_nan(self.fmt)
509-
510524
for ch in range(np.shape(self.p_signal)[1]):
511525
# Get the minimum and maximum (valid) storage values
512526
dmin, dmax = digi_bounds(self.fmt[ch])
513527
# add 1 because the lowest value is used to store nans
514528
dmin = dmin + 1
515-
dnan = dnans[ch]
516529

517530
pmin = minvals[ch]
518531
pmax = maxvals[ch]
519532

520-
# map values using full digital range.
533+
# Figure out digital samples used to store physical samples
521534

522-
# If the entire signal is nan, just put any.
535+
# If the entire signal is nan, gain/baseline won't be used
523536
if pmin == np.nan:
524537
adc_gain = 1
525538
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.
527540
elif pmin == pmax:
528541
if pmin == 0:
529542
adc_gain = 1
530543
baseline = 1
531544
else:
532-
adc_gain = 1 / pmin
545+
# All digital values are +1 or -1. Keep adc_gain > 0
546+
adc_gain = abs(1 / pmin)
533547
baseline = 0
534-
# Regular varied signal case. Map pmax->dmax, pmin->dmin
548+
# Regular varied signal case.
535549
else:
536550
# 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.
540555
adc_gain = (dmax-dmin) / (pmax-pmin)
541556
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.
543562
if pmin > 0:
544563
baseline = int(np.ceil(baseline))
545564
else:
546565
baseline = int(np.floor(baseline))
547566

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
549568
# 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,
556570
# adc_gain is already correct. Avoid dividing by 0.
557571
if dmin != baseline:
558572
adc_gain = (dmin - baseline) / pmin
559573

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')
563577

564578
adc_gains.append(adc_gain)
565579
baselines.append(baseline)
@@ -1311,7 +1325,7 @@ def est_res(signals):
13111325
res.append(0)
13121326
else:
13131327
nlevels = 1 + (sortedsig[-1]-sortedsig[0])/min_inc
1314-
if nlevels>=res_levels[-1]:
1328+
if nlevels >= res_levels[-1]:
13151329
res.append(32)
13161330
else:
13171331
res.append(np.where(res_levels>=nlevels)[0][0])

0 commit comments

Comments
 (0)