Add current time to JLS files recorded with Python and Joulescope package

Hi all!

In my team, we are trying to automate power consumption measurements of battery powered embedded device with Joulescope JS110 and Python.

Short problem description
I do not know how to add recording start time to .jls file.

Detailed problem description
Problem occurs when I want to open JLS file (that was recorded with example.py script) with my other script (JLSReader.py) and read UTC timestamp of given sample.
This is the output that I have got:

Sources:
  source_id=0, source.name='global_annotation_source'
  source_id=1, source.name='JS110-003901'

Signals:
  signal_id=0, signal.name='global_annotation_signal', signal.signal_type=1, signal.sample_rate=0
  signal_id=1, signal.name='current', signal.signal_type=0, signal.sample_rate=2000000
  signal_id=2, signal.name='voltage', signal.signal_type=0, signal.sample_rate=2000000

Data for Signal ID 1: [-4.09781933e-08 -1.67638063e-08  2.14204192e-08  1.76951289e-08
 -1.95577741e-08 -5.30853868e-08 -1.11758709e-08  2.98023224e-08
  6.51925802e-09 -4.37721610e-08 -4.09781933e-08  0.00000000e+00
  3.25962901e-08  2.42143869e-08 -2.88709998e-08 -5.86733222e-08
 -2.32830644e-08  1.76951289e-08  1.49011612e-08 -1.67638063e-08
 -5.86733222e-08 -3.81842256e-08  0.00000000e+00  1.49011612e-08
 -4.65661287e-09 -2.60770321e-08 -2.32830644e-08  1.21071935e-08
  6.51925802e-09 -1.39698386e-08  0.00000000e+00  1.21071935e-08
  2.98023224e-08  1.49011612e-08 -2.88709998e-08 -3.53902578e-08
 -1.86264515e-09  3.25962901e-08 -1.86264515e-09 -4.09781933e-08
 -4.37721610e-08 -1.86264515e-09  1.76951289e-08 -1.86264515e-09
 -2.32830644e-08  1.76951289e-08  5.12227416e-08  4.84287739e-08
  6.51925802e-09 -2.32830644e-08 -1.11758709e-08  2.98023224e-08
  3.63215804e-08  1.49011612e-08 -1.95577741e-08 -2.32830644e-08
  1.21071935e-08  1.76951289e-08 -1.95577741e-08 -3.53902578e-08
 -1.39698386e-08  1.76951289e-08  0.00000000e+00 -5.30853868e-08
 -7.07805157e-08 -2.32830644e-08  4.47034836e-08  3.25962901e-08
 -1.86264515e-09 -1.39698386e-08 -1.11758709e-08  2.98023224e-08
  1.21071935e-08 -3.16649675e-08 -3.53902578e-08 -1.39698386e-08
  0.00000000e+00  9.31322575e-09  6.51925802e-09 -1.11758709e-08
 -8.38190317e-09  1.76951289e-08  1.76951289e-08  6.51925802e-09
 -1.67638063e-08 -1.95577741e-08  1.21071935e-08  2.42143869e-08
 -4.65661287e-09 -2.32830644e-08 -4.65661287e-09  2.98023224e-08
  2.70083547e-08 -1.39698386e-08 -4.09781933e-08 -2.88709998e-08
  2.79396772e-09  3.63215804e-08  2.14204192e-08 -1.39698386e-08]

fsr_stats=array([[-4.65661287e-09,  2.96954166e-08, -4.09781933e-08,
         2.14204192e-08],
       [-1.35041773e-08,  3.40792806e-08, -5.30853868e-08,
         2.98023224e-08],
       [-1.95577741e-08,  2.65059051e-08, -4.37721610e-08,
         6.51925802e-09],
       ...,
       [-1.83936208e-08,  3.43906966e-08, -5.58793545e-08,
         1.76951289e-08],
       [-2.46800482e-08,  1.45377833e-08, -4.37721610e-08,
        -8.38190317e-09],
       [-2.51457095e-08,  1.38346602e-08, -4.37721610e-08,
        -1.11758709e-08]])
signal.signal_type=0
Traceback (most recent call last):
  File "######\JLSReader.py", line 32, in <module>
    jls_ts = reader.sample_id_to_timestamp(1, sample_id)
  File "pyjls/binding.pyx", line 812, in pyjls.binding.Reader.sample_id_to_timestamp
  File "pyjls/binding.pyx", line 269, in pyjls.binding._handle_rc
RuntimeError: sample_id_to_timestamp UNAVAILABLE[20]: The requested resource is currently unavailable.

Process finished with exit code 1

To investigate it I have run the same script with JLS file that was recorded using official Joulescope GUI and the output looked like this:

Sources:
  source_id=0, source.name='global_annotation_source'
  source_id=1, source.name='JS110-003901'

Signals:
  signal_id=0, signal.name='global_annotation_signal', signal.signal_type=1, signal.sample_rate=0
  signal_id=1, signal.name='voltage', signal.signal_type=0, signal.sample_rate=2000000
  signal_id=2, signal.name='power', signal.signal_type=0, signal.sample_rate=2000000
  signal_id=3, signal.name='current', signal.signal_type=0, signal.sample_rate=2000000
  signal_id=4, signal.name='current_range', signal.signal_type=0, signal.sample_rate=2000000
  signal_id=5, signal.name='gpi[0]', signal.signal_type=0, signal.sample_rate=2000000
  signal_id=6, signal.name='gpi[1]', signal.signal_type=0, signal.sample_rate=2000000

Data for Signal ID 1: [4.8694386 4.871708  4.8785157 4.8762465 4.871708  4.8694386 4.871708
 4.880785  4.8762465 4.871708  4.8671694 4.8694386 4.873977  4.873977
 4.8671694 4.8671694 4.8671694 4.8762465 4.873977  4.8671694 4.8671694
 4.8671694 4.8785157 4.880785  4.8762465 4.871708  4.873977  4.8785157
 4.880785  4.8785157 4.8762465 4.873977  4.8785157 4.880785  4.880785
 4.873977  4.871708  4.8785157 4.8762465 4.8785157 4.8694386 4.8671694
 4.8762465 4.873977  4.8762465 4.8694386 4.8671694 4.873977  4.873977
 4.873977  4.8671694 4.8671694 4.8762465 4.8762465 4.873977  4.8694386
 4.871708  4.8762465 4.880785  4.871708  4.871708  4.871708  4.8785157
 4.880785  4.871708  4.8694386 4.873977  4.8762465 4.8762465 4.8671694
 4.8649006 4.871708  4.873977  4.871708  4.8649006 4.8649006 4.8694386
 4.873977  4.8694386 4.8694386 4.8694386 4.8762465 4.8785157 4.880785
 4.873977  4.8762465 4.883054  4.883054  4.880785  4.8785157 4.8785157
 4.880785  4.883054  4.880785  4.8762465 4.873977  4.8785157 4.8785157
 4.8785157 4.8694386]

fsr_stats=array([[4.87397718e+00, 4.14309764e-03, 4.86943865e+00, 4.87851572e+00],
       [4.87340987e+00, 5.03177460e-03, 4.86943865e+00, 4.88078499e+00],
       [4.87114060e+00, 3.87551297e-03, 4.86716938e+00, 4.87624645e+00],
       ...,
       [5.28300083e+00, 2.17265873e-03, 5.28016424e+00, 5.28470278e+00],
       [5.28356814e+00, 4.34531746e-03, 5.28016424e+00, 5.28924131e+00],
       [5.28186619e+00, 5.03177460e-03, 5.27789497e+00, 5.28924131e+00]])
signal.signal_type=0
jls_ts=234197732024271628
utc_ts=1732878434.7579505

human_datetime='2024-11-29 12:07:14'

Process finished with exit code 0

And for this file everything worked smoothly.

During mine investigation I have noticed a difference between JLS files that were created using Joulescope GUI and my Python script.
gui_example.jls:


my_example.jls:

Check upper left corner - my_example.jls has default value:

2018-01-01T00:00:00+00:00

So I guess my script lacks an explicit definition of the time when my recording starts, but unofrtunately I have not seen (or just missed) explanation in docs/examples how this operation can be done.

Thanks in advance for your support!

============================

Source code
example.py

import time
import joulescope

device = joulescope.scan_require_one(config='auto')
device.open()
filename = r'########\my_example.jls'
jls_writer = joulescope.JlsWriter(device, filename)
jls_writer.open()
device.stream_process_register(jls_writer)
device.start()

time.sleep(3)   # Device under test does something

device.stop()
device.stream_process_unregister(jls_writer)
jls_writer.close()
device.close()

JLSReader.py

from time import strftime, localtime
from pyjls.binding import Reader, jls_to_utc

with Reader(r'###########\gui_example.jls') as reader:
    print("Sources:")
    for source_id, source in reader.sources.items():
        print(f"  {source_id=}, {source.name=}")

    print("\nSignals:")
    for signal_id, signal in reader.signals.items():
        print(
            f"  {signal_id=}, {signal.name=}, {signal.signal_type=}, {signal.sample_rate=}")

    # Example: Read data from an FSR signal for 100 samples
    signal_id = 1
    start_sample_id = 0
    length = 100
    data = reader.fsr(signal_id, start_sample_id, length)
    print(f"\nData for Signal ID {signal_id}: {data}")

    # Example: Read FSR statistics for data
    increment = 4
    max_length = reader.signals[1].length
    stat_length = int(max_length / increment)
    fsr_stats = reader.fsr_statistics(signal_id, start_sample_id, increment, stat_length)
    print(f'\n{fsr_stats=}')

    # Example: Convert sample ID to timestamp
    signal = reader.signals[1]
    print(f'{signal.signal_type=}')
    sample_id = 1000
    jls_ts = reader.sample_id_to_timestamp(1, sample_id)
    print(f'{jls_ts=}')
    utc_ts = jls_to_utc(jls_ts)
    print(f'{utc_ts=}')
    human_datetime = strftime('%Y-%m-%d %H:%M:%S', localtime(utc_ts))
    print(f'\n{human_datetime=}')

What I use

  • OS: Win-11
  • Joulescope: JS110
  • Joulescope App:
    • UI: 1.2.2
    • driver: 1.7.1
    • JLS: 0.11.0
    • Python 3.11.9
    • Platform: Windows-10-10.0.22631-SP0
  • Python: 3.13.0
  • Python Packages:
    • joulescope: 1.2.0
    • pyjoulescope_driver: 1.7.0
    • pyjls: 0.11.0

The UTC timestamp feature is newer than the joulescope API. While the timestamp support exists in the pyjoulescope_driver package, it does not exist in the joulescope package. Can you record using the pyjoulescope_driver package:

python -m pyjoulescope_driver record --signals i,v,p out.jls

If you want to run this from within a script, you can use the Record class.

For what it’s worth, this is pyjoulescope issue #37. While writing UTC time to the JLS file is easy using the Writer.utc method, UTC time simply does not exist for the pyjoulescope StreamBuffer.

1 Like

We are also working to track down and fix issue #296, which can infrequently cause the UTC timestamp to be incorrect. It’s a somewhat rare issue, but you may encounter it. We hope to have a fix soon!