def test_statistics_get(self): #fh = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data_recording_01.jls') fh = self.create_sinusoid_file(2000000, 400000) r = DataReader().open(fh) t_start, t_stop = 0.066780, 0.069004 k_start, k_stop = r.normalize_time_arguments(t_start, t_stop, units='seconds') ranges = [ (0, 1000), # trivial, direct (0, 20000), # trivial, single reduction (100000, 101000), # offset, direct (100000, 120000), # offset, ex (99000, 120000), (100000, 121000), (99000, 121000), (k_start, k_stop), ] for k_start, k_stop in ranges: # print(f'range {k_start}:{k_stop}') s1 = r.statistics_get(k_start, k_stop, units='samples') _, _, data = r.raw(k_start, k_stop) i_mean = np.mean(data[:, 0]) np.testing.assert_allclose( s1['signals']['current']['statistics']['μ'], i_mean, rtol=0.0005) r.close()
def test_single_sample(self): fh = self.create_sinusoid_file(2000000, 400000) r = DataReader().open(fh) s1 = r.statistics_get(20, 20, units='samples') i_mean = r.raw(20, 21)[2][0, 0] np.testing.assert_allclose(s1['signals']['current']['statistics']['μ'], i_mean, rtol=0.0005)
def test_cache_test(self): sample_rate = 2000000 sample_count = sample_rate * 2 fh = self.create_sinusoid_file(sample_rate, sample_count) r = DataReader().open(fh) for step_size in [1111, 2000, 11111, 20000]: # print(f'step_size = {step_size}') for i in range(0, sample_count - step_size, step_size): r.raw_processor.reset() s1 = r.statistics_get(i, i + step_size, units='samples') _, _, data = r.raw(i, i + step_size) i_mean = np.mean(data[:, 0]) np.testing.assert_allclose( s1['signals']['current']['statistics']['μ'], i_mean, rtol=0.0005) r.close()
def on_cmd(args): r = DataReader().open(args.filename) print(r.summary_string()) start = args.start stop = args.stop if stop < 0: stop = r.sample_id_range[1] + 1 + stop if args.export is not None: i, v = r.get_calibrated(start, stop, units='samples') data = np.hstack((i.reshape((-1, 1)), (v.reshape((-1, 1))))) if args.export.endswith('npy'): np.save(args.export, data) else: np.savetxt(args.export, data, fmt='%.5g', delimiter=',') if args.plot_reduction: import matplotlib.pyplot as plt y = r.get_reduction(start, stop) x = np.arange(len(y)) * (r.config['samples_per_reduction'] / r.config['sampling_frequency']) f = plt.figure() fields = r.config['reduction_fields'] for axis, name in enumerate(fields): ax = f.add_subplot(len(fields), 1, axis + 1) ax.plot(x, y[:, axis, 0], color='blue') ax.plot(x, y[:, axis, 2], color='red') ax.plot(x, y[:, axis, 3], color='red') ax.set_ylabel(name) plt.show() plt.close(f) if args.plot: import matplotlib.pyplot as plt i, v = r.get_calibrated(start, stop) x = np.arange(len(i)) * (1.0 / r.config['sampling_frequency']) f = plt.figure() ax_i = f.add_subplot(2, 1, 1) ax_i.plot(x, i) ax_i.set_ylabel('Current (A)') ax_i.grid(True) ax_v = f.add_subplot(2, 1, 2, sharex=ax_i) ax_v.plot(x, v) ax_v.set_ylabel('Voltage (V)') ax_v.grid(True) ax_v.set_xlabel('Time (s)') plt.show() plt.close(f) if args.plot_raw: import matplotlib.pyplot as plt if stop - start > 2000000: print('Time range too long, cannot --plot-raw') else: plot_idx_total = len(args.plot_raw) link_axis = None plot_idx = 1 d_raw, d_bits, d_cal = r.raw(start=start, stop=stop) i_raw = np.right_shift(d_raw[:, 0], 2) v_raw = np.right_shift(d_raw[:, 1], 2) x = np.arange(len(i_raw)) * (1.0 / r.config['sampling_frequency']) i_sel = np.bitwise_and(d_bits, 0x000F) f = plt.figure() f.suptitle('Joulescope Raw Data') for c in args.plot_raw: if c == 'i': ax = f.add_subplot(plot_idx_total, 1, plot_idx, sharex=link_axis) ax.plot(x, i_raw) ax.set_ylabel('Current (LSBs)') elif c == 'v': ax = f.add_subplot(plot_idx_total, 1, plot_idx, sharex=link_axis) ax.plot(x, v_raw) ax.set_ylabel('Voltage (LSBs)') elif c == 'r': ax = f.add_subplot(plot_idx_total, 1, plot_idx, sharex=link_axis) ax.plot(x, i_sel) ax.set_ylabel('Current Range') else: raise ValueError('unsupported plot: %s' % c) ax.grid(True) if link_axis is None: link_axis = ax plot_idx += 1 # plt.tight_layout() ax.set_xlabel('Time (s)') plt.show() plt.close(f) r.close() return 0
class RecordingViewerDevice: """A user-interface-compatible device that displays previous recorded data :param filename: The filename path to the pre-recorded data. """ def __init__(self, filename): self._filename = filename self.reader = None self.ui_action = None self.view = None # type: DataViewApi self.x_range = [0.0, 1.0] self.span = None self.x = None self.samples_per = 1 self._cache = None def __str__(self): return os.path.basename(self._filename) def __len__(self): if self.span is None: return 0 return self.span.length @property def sampling_frequency(self): if self.reader is None: return None return self.reader.sampling_frequency @property def calibration(self): if self.reader is None: return None return self.reader.calibration def open(self): self.view = self self.reader = DataReader().open(self._filename) f = self.reader.sampling_frequency r = self.reader.sample_id_range x_lim = [x / f for x in r] self.span = span.Span(x_lim, 1 / f, 100) self.x_range, self.samples_per, self.x = self.span.conform_discrete( x_lim) self._cache = None # invalidate log.info('RecordingViewerDevice.open: %s => %s, %s', r, self.x_range, self.samples_per) def close(self): if self.reader is not None: self.reader.close() self.reader = None if self.on_close is not None: self.on_close() self.view = None def on_x_change(self, cmd, kwargs): x_range = self.x_range if cmd == 'resize': # {pixels: int} length = kwargs['pixels'] if length is not None and length != self.span.length: log.info('resize %s', length) self.span.length = length self._cache = None # invalidate x_range, self.samples_per, self.x = self.span.conform_discrete( x_range) elif cmd == 'span_absolute': # {range: (start: float, stop: float)}] x_range, self.samples_per, self.x = self.span.conform_discrete( kwargs.get('range')) elif cmd == 'span_relative': # {pivot: float, gain: float}] x_range, self.samples_per, self.x = self.span.conform_discrete( x_range, gain=kwargs.get('gain'), pivot=kwargs.get('pivot')) elif cmd == 'span_pan': delta = kwargs.get('delta', 0.0) x_range = [x_range[0] + delta, x_range[-1] + delta] x_range, self.samples_per, self.x = self.span.conform_discrete( x_range) elif cmd == 'refresh': self._cache = None # invalidate return else: log.warning('on_x_change(%s) unsupported', cmd) return if self.x_range != x_range: self._cache = None # invalidate self.x_range = x_range log.info( 'cmd=%s, changed=%s, length=%s, span=%s, range=%s, samples_per=%s', cmd, self._cache is None, len(self), self.x_range, self.x_range[1] - self.x_range[0], self.samples_per) def update(self): if self._cache is not None: return False, self._cache f = self.reader.sampling_frequency log.info('update: x_range=%r', self.x_range) start, stop = [int(x * f) for x in self.x_range] log.info('update: x_range=%r => (%s, %s)', self.x_range, start, stop) data = self.reader.get(start, stop, self.samples_per) t_start = start / self.reader.sampling_frequency t_stop = stop / self.reader.sampling_frequency x = np.linspace(t_start, t_stop, len(data), dtype=np.float64) try: log.info('update: len=%d, x_range=>(%s, %s)', len(data), x[0], x[-1]) except: print(x.shape) self._cache = (x, data) return True, self._cache def time_to_sample_id(self, t): if self.reader is None: return None return self.reader.time_to_sample_id(t) def statistics_get(self, t1, t2): """Get the statistics for the collected sample data over a time range. :param t1: The starting time in seconds relative to the streaming start time. :param t2: The ending time in seconds. :return: The statistics data structure. """ if self.reader is None: return None return self.reader.statistics_get(t1, t2) def raw_get(self, start=None, stop=None): if self.reader is None: return None return self.reader.raw(start=start, stop=stop) def samples_get(self, start=None, stop=None): if self.reader is None: return None i, v = self.reader.get_calibrated(start=start, stop=stop) return { 'current': { 'value': i, 'units': 'A', }, 'voltage': { 'value': v, 'units': 'V', } }