diff --git a/CHANGELOG b/CHANGELOG index 97de05b..f95c4e3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +2024-05-03: upversion 2.10.8; update examples and doc [ac44d00] 2024-05-02: more documentation for example programs [fb8e531] 2024-05-01: fix set_cal_out_freq_6022.py; some minor updates [3560cbd] 2024-02-25: add fx2lib lib files [852f574] diff --git a/PyHT6022/LibUsbScope.py b/PyHT6022/LibUsbScope.py index 8ba9968..cd5465d 100644 --- a/PyHT6022/LibUsbScope.py +++ b/PyHT6022/LibUsbScope.py @@ -551,7 +551,7 @@ def read_data(self, data_size=0x400, raw=False, timeout=0): if self.num_channels == 2: chdata = data[::2], data[1::2] else: - chdata = data, '' + chdata = data, b'' if raw: return chdata else: @@ -799,10 +799,12 @@ def set_sample_rate(self, rate_index, timeout=0): :param rate_index: The rate_index. These are the keys for the SAMPLE_RATES dict for the Oscilloscope object. Common rate_index values and actual sample rate per channel: 102 <-> 20 kS/s + 103 <-> 32 kS/s 104 <-> 40 kS/s 105 <-> 50 kS/s 106 <-> 64 kS/s 110 <-> 100 kS/s + 113 <-> 128 kS/s 120 <-> 200 kS/s 140 <-> 400 kS/s 150 <-> 500 kS/s diff --git a/examples/capture_6022.py b/examples/capture_6022.py index b9817e5..ae0e8e7 100755 --- a/examples/capture_6022.py +++ b/examples/capture_6022.py @@ -178,7 +178,7 @@ def pcb( ch1_data, ch2_data ): pcb.av1 /= downsample pcb.av2 /= downsample if pcb.timestep < sample_time: - line = "{:>10.6f}, {:>10.5f}, {:>10.5f}\n".format( pcb.timestep, pcb.av1, pcb.av2 ) + line = f"{pcb.timestep:>10.6f}, {pcb.av1:>10.5f}, {pcb.av2:>10.5f}\n" if german: line=line.replace( ',', ';' ).replace( '.', ',' ) outfile.write( line ) @@ -187,7 +187,7 @@ def pcb( ch1_data, ch2_data ): else: # write out every sample for ch1_value, ch2_value in zip( ch1_scaled, ch2_scaled ): # merge CH1 & CH2 if pcb.timestep < sample_time: - line = "{:>10.6f}, {:>10.5f}, {:>10.5f}\n".format( pcb.timestep, ch1_value, ch2_value ) + line = f"{pcb.timestep:>10.6f}, {ch1_value:>10.5f}, {ch2_value:>10.5f}\n" if german: line=line.replace( ',', ';' ).replace( '.', ',' ) outfile.write( line ) @@ -227,7 +227,7 @@ def pcb( ch1_data, ch2_data ): if downsample: # calculate the effective sample rate sample_rate = sample_rate / 256 / downsample -line = "\rCaptured data for {} second(s) @ {} S/s\n".format( sample_time, sample_rate) +line = f"\rCaptured data for {sample_time} second(s) @ {sample_rate} S/s\n" if german: line=line.replace( ',', ';' ).replace( '.', ',' ) sys.stderr.write( line ) @@ -245,11 +245,11 @@ def pcb( ch1_data, ch2_data ): rms1 = math.sqrt( rms1 ) rms2 = math.sqrt( rms2 ) -line = "CH1: DC = {:8.4f} V, AC = {:8.4f} V, RMS = {:8.4f} V\n".format( dc1, ac1, rms1 ) +line = f"CH1: DC = {dc1:8.4f} V, AC = {ac1:8.4f} V, RMS = {rms1:8.4f} V\n" if german: line=line.replace( ',', ';' ).replace( '.', ',' ) sys.stderr.write( line ) -line = "CH2: DC = {:8.4f} V, AC = {:8.4f} V, RMS = {:8.4f} V\n".format( dc2, ac2, rms2 ) +line = f"CH2: DC = {dc2:8.4f} V, AC = {ac2:8.4f} V, RMS = {rms2:8.4f} V\n" if german: line=line.replace( ',', ';' ).replace( '.', ',' ) sys.stderr.write( line ) diff --git a/examples/scopevis.py b/examples/scopevis.py index d6a7b67..11d0aaa 100755 --- a/examples/scopevis.py +++ b/examples/scopevis.py @@ -6,54 +6,110 @@ import pylab import time import sys +import argparse -def apply_data_smoothing(data, window=1): - new_data = data[:window] - for i, point in enumerate(data[window:-window]): - new_data.append(sum(data[i-window:i+window+1])/(2*window+1)) - new_data.extend(data[-window:]) - return new_data +samplerates = ( 20, 32, 50, 64, 100, 128, 200, 500, 1000, 2000, 4000, 8000, 10000 ) +samplerate_help = "sample rate in kS/s (" +for samplerate in samplerates: + samplerate_help += str( samplerate ) + ", " +samplerate_help += f"default: {samplerates[0]})" +gains = ( 1, 2, 5, 10 ) +gain_help = "channel gain (" +for gain in gains: + gain_help += str( gain ) + ", " +gain_help += f"default: {gains[0]})" -sample_rate_index = 1 -voltage_range = 0x01 -cal_freq = 10 +# construct the argument parser and parse the arguments +ap = argparse.ArgumentParser( + prog='scopevis.py', + description='Capture data from Hantek6022' ) +ap.add_argument( "--ac1", action = "store_true", default = False, help = "AC coupling for CH1" ) +ap.add_argument( "--ac2", action = "store_true", default = False, help = "AC coupling for CH2" ) +ap.add_argument( "-b", "--blocks", type = int, default = 20, help="number of 1K sample blocks, default: 20" ) +ap.add_argument( "--ch1", type = int, default = gains[0], help=f"select gain for ch1 (1, 2, 5, 10, default: {gains[0]})" ) +ap.add_argument( "--ch2", type = int, default = 0, help="sample also ch2 with gain 1, 2, 5, 10" ) +ap.add_argument( "-f", "--frequency", type = int, default = 0, help="set cal out frequency in Hz" ) +ap.add_argument( "-s", "--samplerate", type = int, default = samplerates[0], help=samplerate_help ) -# skip first samples due to unstable xfer -skip = 2 * 0x400 -data_points = skip + 20 * 0x400 +options = ap.parse_args() +argerr = False +if options.ch1 and options.ch1 not in gains: + print( "error, ch1 gain must be one of:", gains ) + argerr = True +if options.ch2 and options.ch2 not in gains: + print( "error, ch2 gain must be one of:", gains ) + argerr = True +if options.samplerate not in samplerates: + print( "error, rate must be one of:", samplerates ) + argerr = True +if argerr: + sys.exit() + +data_points = options.blocks * 1024 + +# skip first 2K samples due to unstable xfer +skip = 2 * 1024 +data_points += skip scope = Oscilloscope() scope.setup() scope.open_handle() -scope.set_sample_rate(sample_rate_index) -scope.set_ch1_voltage_range(voltage_range) -scope.set_ch1_ac_dc( scope.DC ) -scope.set_calibration_frequency( cal_freq ) -time.sleep( 1 ) +# upload correct firmware into device's RAM +if (not scope.is_device_firmware_present): + scope.flash_firmware() + +# calculate and set the sample rate ID from real sample rate value +if options.samplerate < 1e3: + sample_id = int( round( 100 + options.samplerate / 10 ) ) # 20k..500k -> 102..150 +else: + sample_id = int( round( options.samplerate / 1e3 ) ) # 1000k -> 1 + +scope.set_sample_rate( sample_id ) + +if options.ch1: + scope.set_ch1_voltage_range( options.ch1 ) +if options.ac1: + scope.set_ch1_ac_dc( scope.AC ) +else: + scope.set_ch1_ac_dc( scope.DC ) + +if options.ch2: + scope.set_num_channels( 2 ) + scope.set_ch2_voltage_range( options.ch2 ) + if options.ac2: + scope.set_ch2_ac_dc( scope.AC ) + else: + scope.set_ch2_ac_dc( scope.DC ) +else: + scope.set_ch2_voltage_range( 1 ) -ch1_data, _ = scope.read_data(data_points)#,raw=True)#timeout=1) +# read and apply calibration values from EEPROM +calibration = scope.get_calibration_values() -voltage_data = scope.scale_read_data(ch1_data[skip:], voltage_range) -timing_data, _ = scope.convert_sampling_rate_to_measurement_times(data_points-skip, sample_rate_index) +if options.frequency: + scope.set_calibration_frequency( options.frequency ) + +time.sleep( 0.1 ) + + +ch1_data, ch2_data = scope.read_data(data_points)#,raw=True)#timeout=1) + +if options.ch1: + voltage_data1 = scope.scale_read_data(ch1_data[skip:], options.ch1, channel=1 ) +if options.ch2: + voltage_data2 = scope.scale_read_data(ch2_data[skip:], options.ch2, channel=2 ) +timing_data, rate_label = scope.convert_sampling_rate_to_measurement_times(data_points-skip, sample_id) scope.close_handle() -if len(timing_data) != len(voltage_data): - w = sys.stderr.write - w('data lengths differ!\n') - w(str([(s,len(eval(s+'_data')))for s in 'timing voltage'.split()])) - w('\n') - exit(1) - -# store the data -with open('/tmp/scopevis.dat', 'wt') as ouf: - ouf.write('\n'.join('{:8f}'.format(v) for v in voltage_data)) - ouf.write('\n') - -pylab.title('Scope Visualization Example') -pylab.plot(timing_data, voltage_data, color='#009900', label='Raw Trace') -pylab.plot(timing_data, apply_data_smoothing(voltage_data, window=3), color='#0033CC', label='Smoothed Trace') + +pylab.title( f'{options.blocks}K samples @ {rate_label}') +if options.ch1: + pylab.plot(timing_data, voltage_data1, color='#C00000', label='CH1') +if options.ch2: + pylab.plot(timing_data, voltage_data2, color='#0000C0', label='CH2') + pylab.xlabel('Time (s)') pylab.ylabel('Voltage (V)') pylab.grid()