Read_by_callback does not display/log captured data

Hi, i want to monitor current for 30 minutes and i want 1000 samples to recorded per second into a csv file. I have a JS220.

After some research i found that i need to run read_by_callback for such an operation.

I ran read_by_callback script as it is with no modification and i got certain logs getting printed into my terminal but i do not see and csv, jls or any kind of plot being generated. Below are the logs i am observing:

2024-01-03 17:45:14,693 INFO     jsdrv open_ll(opt=0)
2024-01-03 17:45:14,694 INFO     jsdrv device_open(u/js220/000796) \\?\usb#vid_16d0&pid_10ba#000796#{e27188c8-98ff-41de-be50-653324c6b19c}
2024-01-03 17:45:14,694 INFO     jsdrv open(opt=0)
2024-01-03 17:45:14,694 INFO     jsdrv bulk_in_stream_open 130
2024-01-03 17:45:14,694 INFO     jsdrv bulk_in_initialize pipe_id=0x82
2024-01-03 17:45:14,694 INFO     jsdrv MAXIMUM_TRANSFER_SIZE pipe_id=0x82 bytes=2097152
2024-01-03 17:45:14,695 INFO     jsdrv port0 connect rsp
2024-01-03 17:45:14,695 INFO     jsdrv JS220 app_id=3, FW=1.2.1, HW=1.0.0, FPGA=1.2.1, protocol=1.0.0
2024-01-03 17:45:14,695 INFO     jsdrv publish to dev $ nul
2024-01-03 17:45:14,695 INFO     jsdrv publish to dev c/!ping u32    1
2024-01-03 17:45:14,696 INFO     jsdrv open complete
2024-01-03 17:45:14,696 INFO     jsdrv on_sampling_frequency(2000000)
2024-01-03 17:45:14,702 INFO     jsdrv publish to dev s/i/range/mode  u8.R  4
2024-01-03 17:45:14,702 INFO     jsdrv publish to dev s/v/range/select  u8.R  0
2024-01-03 17:45:14,702 INFO     jsdrv publish to dev s/v/range/mode  u8.R  1
2024-01-03 17:45:14,706 INFO     jsdrv publish to dev s/i/ctrl  u8.R  1
2024-01-03 17:45:14,714 INFO     jsdrv stream_in_port 21 initial synchronization: u32=0x1b62d841, u64=0x41b6281e7
2024-01-03 17:45:14,714 INFO     jsdrv publish to dev s/v/ctrl  u8.R  1
2024-01-03 17:45:14,718 INFO     jsdrv stream_in_port 22 initial synchronization: u32=0x1b6319b7, u64=0x41b6281e7
2024-01-03 17:45:14,718 INFO     jsdrv publish to dev s/i/range/ctrl  u8.R  1
2024-01-03 17:45:14,722 INFO     jsdrv stream_in_port 23 initial synchronization: u32=0x1b63303d, u64=0x41b6281e7
2024-01-03 17:45:14,722 INFO     jsdrv stream_in_port 20 initial synchronization: u32=0x1b633c18, u64=0x41b6281e7
2024-01-03 17:45:14,722 INFO     jsdrv publish to dev s/gpi/0/ctrl  u8.R  1
2024-01-03 17:45:14,726 INFO     jsdrv stream_in_port 24 initial synchronization: u32=0x1b6359a0, u64=0x41b6281e7
2024-01-03 17:45:14,728 INFO     joulescope.v1.sample_buffer.current add -> auto clear
2024-01-03 17:45:14,728 INFO     joulescope.v1.sample_buffer.current skip head=None, sample_id=8819665952, sample_id_orig=17639331905, sz=16254
2024-01-03 17:45:14,728 INFO     jsdrv publish to dev s/gpi/1/ctrl  u8.R  1
2024-01-03 17:45:14,733 INFO     jsdrv stream_in_port 25 initial synchronization: u32=0x1b6388e0, u64=0x41b6281e7
2024-01-03 17:45:14,734 INFO     joulescope.v1.sample_buffer.voltage add -> auto clear
2024-01-03 17:45:14,734 INFO     joulescope.v1.sample_buffer.voltage skip head=None, sample_id=8819674331, sample_id_orig=17639348663, sz=16254
2024-01-03 17:45:14,737 INFO     joulescope.v1.sample_buffer.power add -> auto clear
2024-01-03 17:45:14,738 INFO     joulescope.v1.sample_buffer.power skip head=None, sample_id=8819677214, sample_id_orig=17639354429, sz=16332
2024-01-03 17:45:14,771 INFO     joulescope.v1.sample_buffer.current_range add -> auto clear
2024-01-03 17:45:14,771 INFO     joulescope.v1.sample_buffer.current_range skip head=None, sample_id=8819678732, sample_id_orig=17639357464, sz=100800
2024-01-03 17:45:14,777 INFO     joulescope.v1.sample_buffer.gpi0 add -> auto clear
2024-01-03 17:45:14,777 INFO     joulescope.v1.sample_buffer.gpi0 skip head=None, sample_id=8819682512, sample_id_orig=17639365024, sz=100800
2024-01-03 17:45:14,780 INFO     joulescope.v1.sample_buffer.gpi1 add -> auto clear
2024-01-03 17:45:14,780 INFO     joulescope.v1.sample_buffer.gpi1 skip head=None, sample_id=8819688560, sample_id_orig=17639377120, sz=100800
2024-01-03 17:45:15,779 INFO     jsdrv publish to dev s/i/ctrl  u8.R  0
2024-01-03 17:45:15,779 INFO     jsdrv publish to dev s/v/ctrl  u8.R  0
2024-01-03 17:45:15,780 INFO     jsdrv publish to dev s/i/range/ctrl  u8.R  0
2024-01-03 17:45:15,780 INFO     jsdrv publish to dev s/gpi/0/ctrl  u8.R  0
2024-01-03 17:45:15,780 INFO     jsdrv publish to dev s/gpi/1/ctrl  u8.R  0
2024-01-03 17:45:15,836 INFO     jsdrv close
2024-01-03 17:45:15,836 INFO     jsdrv device_close(u/js220/000796)
Memory usage: 39.8 MB
2024-01-03 17:45:15,837 INFO     jsdrv bulk_in_finalize ep=0x82
found 0 NaN out of 1000000 samples (1.000 seconds)
2024-01-03 17:45:15,838 INFO     jsdrv close
2024-01-03 17:45:15,838 INFO     jsdrv jsdrv_finalize 00000220B63BAA30
2024-01-03 17:45:15,838 INFO     jsdrv USB backend finalize
2024-01-03 17:45:15,838 INFO     jsdrv JS220 USB upper-level thread done u/js220/000796
2024-01-03 17:45:15,839 INFO     jsdrv finalize usb backend
2024-01-03 17:45:15,839 INFO     jsdrv winusb backend finalize
2024-01-03 17:45:15,839 INFO     jsdrv USB backend_thread done
2024-01-03 17:45:15,840 INFO     jsdrv USB device_thread closing u/js220/000796
2024-01-03 17:45:15,840 INFO     jsdrv device_close(u/js220/000796)
2024-01-03 17:45:15,840 INFO     jsdrv USB device_thread closed u/js220/000796

Note: Running read_by_callback gave the following error:

Traceback (most recent call last):
  File "c:\Users\SystemTest\Downloads\pyjoulescope_examples-main\bin\read_by_callback.py", line 20, in <module>
    from joulescope_examples.plot_cal import plot_iv, print_stats
ModuleNotFoundError: No module named 'joulescope_examples'

so i moved the file one level up along side bin and joulescope_examples. Doing this resolved me the above error.

Hi @systemtest and welcome to the Joulescope forum!

Unless you are attempting to process the samples as they arrive, read_by_callback is not going to help. It does not save anything to a file. This example does require the joulescope_examples package to be in the python path as you discovered. Moving the example as you did is one way to fix the issue. Another is to set the PYTHONPATH environment variable.

If you want to record the statistics data at 1000 Hz, you can use the statistics subcommand from pyjoulescope_driver, like this:

python -m pyjoulescope_driver statistics --frequency 1000 > out.csv

When you are done capturing data, press CTRL-C.

Does this work for you?

Thanks for your quick response @mliberty. Actually i am looking for a function, which when i call into my existing script initiates current measurement and not a CLI command.

Expected function signature: measure_current(duration, frequency)
Expected function output: For duration = 1 second and frequency = 1000Hz a CSV file which looks like the following

time | current

0.001 | 0.00000023
0.002 | 0.00000013
.
.
.
1.000 | 0.00000050

I hope i have provided a better explanation then before. Please let me know if you have any other doubts.

Hi @systemtest - Thank you for the additional information. I am still not sure I understand what you are trying to accomplish. Here are my comments & questions:

A. Function signature

The proposed function signature measure_current(duration, frequency) has a few issues:

  1. Do you want it to simply return the captured data in CSV format? If so, why not return a numpy array which is much easier to use within Python and easy enough to write out to CSV with numpy.savetxt.
  2. If not, how to you specify the CSV file path?
  3. How do you specify the Joulescope device? If you look at any of the joulescope examples, you see that you have to scan for the device and then use that device to all joulescope function calls. For pyjoulescope_driver, you have both the driver context and the device prefix to provide.
  4. Alternatively, you can always use initialize, discover the first connected Joulescope, use it, then finalize. However, this prevents your Python script (and everything else on the system) from doing anything else with any connected Joulescopes. I normally recommend the more controlled approach in (3) and as seen in all the pyjoulescope-examples.

Note that the full initialize/finalize approach (4) is no different from calling out to the system to run the command like I said above. See os.system and subprocess.run. However, the provided statistics entry point does not take a duration. The measure entry point shows how this can be done.

B. CSV file format

CSV files are normally given as:

#time,current
0.001,0.00000023
0.002,0.00000013
.
.
.
1.000,0.00000050

Did you really mean to use | (with spaces) as the separator and not , (no spaces)?

C. Python

You mentioned adding this to an existing Python script.

  1. Are you planning to use this captured data within the same Python script?
  2. How likely is it that you will later want to do something else with your Joulescopes within this script, like toggle GPO’s, read GPI’s, capture voltage, capture energy, etc.?
  3. What is your familiarity and comfort with writing Python?
  4. Are you comfortable creating new code based upon the statistics and measure entry points I referenced above? Note that these use the pyjoulescope_driver package directly rather than joulescope package.
  5. Are you hoping that someone else writes this measure_current function?

Hi @systemtest - Were you able to solve this measurement challenge?

I am happy to provide more help. I think the next step is to answer the questions above so that we can figure out how to get what you want. I am happy to help implement at least a baseline version that you can use. I also just added the detector example which uses the pyjoulescope_driver package directly. Specifying --frequency 1000 and modifying the _on_data method to save to CSV may be close to what you want.