#!/usr/bin/env python # # file: $NEDC_NFC/util/python/nedc_pyprint_signal/nedc_pyprint_signal.py # # revision history: # 20210820 (JJ): fixed for loop that iterates over requested channels # 20210820 (JJ): fixed numeric arguments passed as strings # 20200611 (JP): first version # # This is a Python version of the C++ utility nedc_print_signal. #------------------------------------------------------------------------------ # import system modules # import numpy as np import os import sys # import nedc_modules # import nedc_cmdl_parser as ncp import nedc_debug_tools as ndt import nedc_edf_tools as net import nedc_file_tools as nft #------------------------------------------------------------------------------ # # global variables are listed here # #------------------------------------------------------------------------------ # set the filename using basename # __FILE__ = os.path.basename(__file__) # define the location of the help files # HELP_FILE = \ "$NEDC_NFC/util/python/nedc_pyprint_signal/nedc_pyprint_signal.help" USAGE_FILE = \ "$NEDC_NFC/util/python/nedc_pyprint_signal/nedc_pyprint_signal.usage" # define default argument values # ARG_MAXAM = "--max_amplitude" ARG_ABRV_MAXAM = "-m" ARG_NUMCH = "--num_channels" ARG_NSAMP = "--num_samples" ARG_ABRV_NSAMP = "-n" ARG_STRCH = "--start_channel" ARG_STRSA = "--start_sample" ARG_ABRV_STRSA = "-s" # define default argument values # DEF_MAX_AMPLITUDE = float(10.0) DEF_NUM_CHANNELS = int(-1) DEF_NUM_SAMPLES = int(10) DEF_START_CHANNEL = int(0); DEF_START_SAMPLE = int(0); #------------------------------------------------------------------------------ # # functions are listed here # #------------------------------------------------------------------------------ # declare a global debug object so we can use it in functions # dbgl = ndt.Dbgl() # function: nedc_pyprint_signal # # arguments: # fname: filename to be printed # max_amplitude: amplitude threshold to trigger warning # start_channel: the first channel to be printed # num_channels: the number of channels to be printed # start_sample: the first sample to be printed # num_samples: the number of samples per channel to be printed # fp: file pointer (normally stdout) # # return: a boolean value indicating status # # This method loads a signal and prints it. # def nedc_pyprint_signal(fname, max_ampl, start_channel, num_channels, start_sample, num_samples, fp = sys.stdout): # declare local variables # edf = net.Edf() # read the signal: get both the scaled and unscaled versions # if dbgl > ndt.BRIEF: fp.write("%s (line: %s) %s: opening (%s)\n" % (__FILE__, ndt.__LINE__, ndt.__NAME__, fname)) # read the unscaled Edf signal # (h, sig_unscaled) = edf.read_edf(fname, False, True) if sig_unscaled == None: fp.write("Error: %s (line: %s) %s: reading (%s) - unscaled\n" % (__FILE__, ndt.__LINE__, ndt.__NAME__, fname)) return False # read the scaled Edf signal # (h, sig_scaled) = edf.read_edf(fname, True, True) if sig_scaled == None: fp.write("Error: %s (line: %s) %s: reading (%s) - scaled\n" % (__FILE__, ndt.__LINE__, ndt.__NAME__, fname)) return False if dbgl > ndt.NONE: fp.write("%s (line: %s) %s: num_channels_total = %ld\n" % (__FILE__, ndt.__LINE__, ndt.__NAME__, len(sig_unscaled))) # compute the maximum unscaled value on a channel: a diagnostic # nchans = len(sig_unscaled) max_mag = np.zeros(nchans) flags = np.full(nchans, False, dtype = bool) # for i, key in enumerate(sig_unscaled): # find the maximum magnitude on a channel: # it is silly that this is so hard to do in numpy. we have # to do two passes over the signal # nsamps = sig_unscaled[key].size max_mag[i] = max(sig_unscaled[key].max(), abs(sig_unscaled[key].min())) # set a flag if it is lower than max_amplitude # if max_mag[i] < max_ampl: flags[i] = True; if dbgl > ndt.BRIEF: fp.write("%s (line: %s) %s: done analyzing the signal\n" % (__FILE__, ndt.__LINE__, ndt.__NAME__)) # display some diagnostic information # fp.write(" number of channels = %ld\n" % (nchans)) for i in range(0, nchans): if flags[i] == True: fp.write("\t %s %ld %s (%f < %f)\n" % ("**> warning: channel", i, "has a low amplitude", max_mag[i], max_ampl)) # determine the first and last channels to be printed: # we have to check the requested limits to the actual amount of data # (first_channel, last_channel) = net.set_limits(start_channel, num_channels, len(sig_scaled)) if dbgl > ndt.BRIEF: fp.write("%s (line: %s) %s: channel range = [%3ld, %3ld]\n" % (__FILE__, ndt.__LINE__, ndt.__NAME__, first_channel, last_channel)) fp.write("\t\t[start: %3ld, num_channels = %3ld, total: %3ld]\n" % (start_channel, num_channels, len(sig_scaled))) # loop over all channels # for n in range(first_channel, last_channel): # display the channel information # fp.write(" channel %3ld:\n" % (n)) # set the limts for samples # (first_sample, last_sample) = net.set_limits(start_sample, num_samples, sig_scaled[key].size) if dbgl > ndt.BRIEF: fp.write("%s (line: %s) %s: frame range = [%3ld, %3ld]\n" % (__FILE__, ndt.__LINE__, ndt.__NAME__, first_sample, last_sample)) fp.write("\t\t\t\t[%s %3ld, %s %3ld, %s %3ld]\n" % ("start:", start_sample, "num_samples = ", num_samples, "total:", len(sig_scaled[key]))) # loop over all samples # for i in range(first_sample, last_sample): fp.write("\t\t sig[%5ld][%5ld] = (s: %12.4f) (u: %8d)\n" % (n, i, sig_scaled[key][i], int(sig_unscaled[key][i]))) # separate files by a blank line # fp.write(nft.DELIM_NEWLINE) # clean up an Edf object # edf.cleanup(); # display debugging information # if dbgl > ndt.BRIEF: fp.write("%s (line: %s) %s: done in nedc_pyprint_signal\n" % (__FILE__, ndt.__LINE__, ndt.__NAME__)) # exit gracefully # return True # function: main # def main(argv): # declare local variables # dbgl = ndt.Dbgl() edf = net.Edf() # create a command line parser # cmdl = ncp.Cmdl(USAGE_FILE, HELP_FILE) cmdl.add_argument("files", type = str, nargs = '*') cmdl.add_argument(ARG_ABRV_MAXAM, ARG_MAXAM, type = float) cmdl.add_argument(ARG_NUMCH, type = int) cmdl.add_argument(ARG_ABRV_NSAMP, ARG_NSAMP, type = int) cmdl.add_argument(ARG_STRCH, type = int) cmdl.add_argument(ARG_ABRV_STRSA, ARG_STRSA, type = int) # parse the command line # args = cmdl.parse_args() # check the number of arguments # if len(args.files) == int(0): cmdl.print_usage('stdout') # get the parameter values # if args.max_amplitude is None: args.max_amplitude = DEF_MAX_AMPLITUDE if args.num_channels is None: args.num_channels = DEF_NUM_CHANNELS if args.num_samples is None: args.num_samples = DEF_NUM_SAMPLES if args.start_channel is None: args.start_channel = DEF_START_CHANNEL if args.start_sample is None: args.start_sample = DEF_START_SAMPLE if dbgl > ndt.NONE: print("command line arguments:") print(" max amplitude = %f" % (args.max_amplitude)) print(" num_channels = %d" % (args.num_channels)) print(" num_samples = %d" % (args.num_samples)) print(" start channel = %d" % (args.start_channel)) print(" start sample = %d" % (args.start_sample)) print(nft.STRING_EMPTY) # display an informational message # print("beginning argument processing...") # main processing loop: loop over all input filenames # num_files_att = int(0) num_files_proc = int(0) for fname in args.files: # expand the filename (checking for environment variables) # ffile = nft.get_fullpath(fname) # check if the file exists # if os.path.exists(ffile) is False: print("Error: %s (line: %s) %s: file does not exist (%s)" % (__FILE__, ndt.__LINE__, ndt.__NAME__, ifile)) sys.exit(os.EX_SOFTWARE) # case (1): an edf file # if (edf.is_edf(fname)): # display informational message # num_files_att += int(1) print("%3ld: %s" % (num_files_att, fname)) if nedc_pyprint_signal(fname, args.max_amplitude, args.start_channel, args.num_channels, args.start_sample, args.num_samples, sys.stdout) == True: num_files_proc += int(1) # case (2): a list # else: # display debug information # if dbgl > ndt.NONE: print("%s (line: %s) %s: opening list (%s)" % (__FILE__, ndt.__LINE__, ndt.__NAME__, fname)) # fetch the list # files = nft.get_flist(ffile) if files is None: print("Error: %s (line: %s) %s: error opening (%s)" % (__FILE__, ndt.__LINE__, ndt.__NAME__, fname)) sys.exit(os.EX_SOFTWARE) else: # loop over all files in the list # for edf_fname in files: # expand the filename (checking for environment variables) # ffile = nft.get_fullpath(edf_fname) # check if the file exists # if os.path.exists(ffile) is False: print("Error: %s (line: %s) %s: %s (%s)" % (__FILE__, ndt.__LINE__, ndt.__NAME__, "file does not exist", edf_fname)) sys.exit(os.EX_SOFTWARE) # display information # num_files_att += int(1) print("%3ld: %s" % (num_files_att, edf_fname)) if nedc_pyprint_signal(ffile, args.max_amplitude, args.start_channel, args.num_channels, args.start_sample, args.num_samples, sys.stdout) == True: num_files_proc += int(1); else: print("Error: %s (line: %s) %s: %s (%s)" % (__FILE__, ndt.__LINE__, ndt.__NAME__, "error opening file", edf_fname)) sys.exit(os.EX_SOFTWARE) # display the results # print("processed %ld out of %ld files successfully" % (num_files_proc, num_files_att)) # exit gracefully # return True # begin gracefully # if __name__ == '__main__': main(sys.argv[0:]) # # end of file