|
1 | 1 | import datetime
|
2 |
| -import multiprocessing.dummy |
3 | 2 | import posixpath
|
4 | 3 | import os
|
5 | 4 | import re
|
@@ -2822,6 +2821,9 @@ def wrsamp(
|
2822 | 2821 | sig_name,
|
2823 | 2822 | p_signal=None,
|
2824 | 2823 | d_signal=None,
|
| 2824 | + e_p_signal=None, |
| 2825 | + e_d_signal=None, |
| 2826 | + samps_per_frame=None, |
2825 | 2827 | fmt=None,
|
2826 | 2828 | adc_gain=None,
|
2827 | 2829 | baseline=None,
|
@@ -2860,6 +2862,14 @@ def wrsamp(
|
2860 | 2862 | file(s). The dtype must be an integer type. Either p_signal or d_signal
|
2861 | 2863 | must be set, but not both. In addition, if d_signal is set, fmt, gain
|
2862 | 2864 | and baseline must also all be set.
|
| 2865 | + e_p_signal : ndarray, optional |
| 2866 | + The expanded physical conversion of the signal. Either a 2d numpy |
| 2867 | + array or a list of 1d numpy arrays. |
| 2868 | + e_d_signal : ndarray, optional |
| 2869 | + The expanded digital conversion of the signal. Either a 2d numpy |
| 2870 | + array or a list of 1d numpy arrays. |
| 2871 | + samps_per_frame : int or list of ints, optional |
| 2872 | + The total number of samples per frame. |
2863 | 2873 | fmt : list, optional
|
2864 | 2874 | A list of strings giving the WFDB format of each file used to store each
|
2865 | 2875 | channel. Accepted formats are: '80','212','16','24', and '32'. There are
|
@@ -2911,59 +2921,91 @@ def wrsamp(
|
2911 | 2921 | if "." in record_name:
|
2912 | 2922 | raise Exception("Record name must not contain '.'")
|
2913 | 2923 | # Check input field combinations
|
2914 |
| - if p_signal is not None and d_signal is not None: |
| 2924 | + signal_list = [p_signal, d_signal, e_p_signal, e_d_signal] |
| 2925 | + signals_set = sum(1 for var in signal_list if var is not None) |
| 2926 | + if signals_set != 1: |
2915 | 2927 | raise Exception(
|
2916 |
| - "Must only give one of the inputs: p_signal or d_signal" |
| 2928 | + "Must provide one and only one input signal: p_signal, d_signal, e_p_signal, or e_d_signal" |
2917 | 2929 | )
|
2918 |
| - if d_signal is not None: |
| 2930 | + if d_signal is not None or e_d_signal is not None: |
2919 | 2931 | if fmt is None or adc_gain is None or baseline is None:
|
2920 | 2932 | raise Exception(
|
2921 |
| - "When using d_signal, must also specify 'fmt', 'gain', and 'baseline' fields." |
| 2933 | + "When using d_signal or e_d_signal, must also specify 'fmt', 'gain', and 'baseline' fields" |
2922 | 2934 | )
|
2923 |
| - # Depending on whether d_signal or p_signal was used, set other |
2924 |
| - # required features. |
| 2935 | + |
| 2936 | + # If samps_per_frame is a list, check that it aligns as expected with the channels in the signal |
| 2937 | + if len(samps_per_frame) > 1: |
| 2938 | + # Get properties of the signal being passed |
| 2939 | + non_none_signal = next(signal for signal in signal_list if signal is not None) |
| 2940 | + if isinstance(non_none_signal, np.ndarray): |
| 2941 | + num_sig_channels = non_none_signal.shape[1] |
| 2942 | + channel_samples = [non_none_signal.shape[0]] * non_none_signal.shape[1] |
| 2943 | + elif isinstance(non_none_signal, list): |
| 2944 | + num_sig_channels = len(non_none_signal) |
| 2945 | + channel_samples = [len(channel) for channel in non_none_signal] |
| 2946 | + else: |
| 2947 | + raise TypeError("Unsupported signal format. Must be ndarray or list of lists.") |
| 2948 | + |
| 2949 | + # Check that the number of channels matches the number of samps_per_frame entries |
| 2950 | + if num_sig_channels != len(samps_per_frame): |
| 2951 | + raise Exception( |
| 2952 | + "When passing samps_per_frame as a list, it must have the same number of entries as the signal has channels" |
| 2953 | + ) |
| 2954 | + |
| 2955 | + # Check that the number of frames is the same across all channels |
| 2956 | + frames = [a / b for a, b in zip(channel_samples, samps_per_frame)] |
| 2957 | + if len(set(frames)) > 1: |
| 2958 | + raise Exception( |
| 2959 | + "The number of samples in a channel divided by the corresponding samples_per_frame entry must be uniform" |
| 2960 | + ) |
| 2961 | + |
| 2962 | + # Create the Record object |
| 2963 | + record = Record( |
| 2964 | + record_name=record_name, |
| 2965 | + p_signal=p_signal, |
| 2966 | + d_signal=d_signal, |
| 2967 | + e_p_signal=e_p_signal, |
| 2968 | + e_d_signal=e_d_signal, |
| 2969 | + samps_per_frame=samps_per_frame, |
| 2970 | + fs=fs, |
| 2971 | + fmt=fmt, |
| 2972 | + units=units, |
| 2973 | + sig_name=sig_name, |
| 2974 | + adc_gain=adc_gain, |
| 2975 | + baseline=baseline, |
| 2976 | + comments=comments, |
| 2977 | + base_time=base_time, |
| 2978 | + base_date=base_date, |
| 2979 | + base_datetime=base_datetime, |
| 2980 | + ) |
| 2981 | + |
| 2982 | + # Depending on which signal was used, set other required fields. |
2925 | 2983 | if p_signal is not None:
|
2926 |
| - # Create the Record object |
2927 |
| - record = Record( |
2928 |
| - record_name=record_name, |
2929 |
| - p_signal=p_signal, |
2930 |
| - fs=fs, |
2931 |
| - fmt=fmt, |
2932 |
| - units=units, |
2933 |
| - sig_name=sig_name, |
2934 |
| - adc_gain=adc_gain, |
2935 |
| - baseline=baseline, |
2936 |
| - comments=comments, |
2937 |
| - base_time=base_time, |
2938 |
| - base_date=base_date, |
2939 |
| - base_datetime=base_datetime, |
2940 |
| - ) |
2941 | 2984 | # Compute optimal fields to store the digital signal, carry out adc,
|
2942 | 2985 | # and set the fields.
|
2943 | 2986 | record.set_d_features(do_adc=1)
|
2944 |
| - else: |
2945 |
| - # Create the Record object |
2946 |
| - record = Record( |
2947 |
| - record_name=record_name, |
2948 |
| - d_signal=d_signal, |
2949 |
| - fs=fs, |
2950 |
| - fmt=fmt, |
2951 |
| - units=units, |
2952 |
| - sig_name=sig_name, |
2953 |
| - adc_gain=adc_gain, |
2954 |
| - baseline=baseline, |
2955 |
| - comments=comments, |
2956 |
| - base_time=base_time, |
2957 |
| - base_date=base_date, |
2958 |
| - base_datetime=base_datetime, |
2959 |
| - ) |
| 2987 | + elif d_signal is not None: |
2960 | 2988 | # Use d_signal to set the fields directly
|
2961 | 2989 | record.set_d_features()
|
| 2990 | + elif e_p_signal is not None: |
| 2991 | + # Compute optimal fields to store the digital signal, carry out adc, |
| 2992 | + # and set the fields. |
| 2993 | + record.set_d_features(do_adc=1, expanded=True) |
| 2994 | + elif e_d_signal is not None: |
| 2995 | + # Use e_d_signal to set the fields directly |
| 2996 | + record.set_d_features(expanded=True) |
2962 | 2997 |
|
2963 | 2998 | # Set default values of any missing field dependencies
|
2964 | 2999 | record.set_defaults()
|
| 3000 | + |
| 3001 | + # Determine whether the signal is expanded |
| 3002 | + if (e_d_signal or e_p_signal) is not None: |
| 3003 | + expanded = True |
| 3004 | + else: |
| 3005 | + expanded = False |
| 3006 | + |
2965 | 3007 | # Write the record files - header and associated dat
|
2966 |
| - record.wrsamp(write_dir=write_dir) |
| 3008 | + record.wrsamp(write_dir=write_dir, expanded=expanded) |
2967 | 3009 |
|
2968 | 3010 |
|
2969 | 3011 | def dl_database(
|
|
0 commit comments