Skip to content

Commit 1278b3b

Browse files
authored
Added TMF8829 tools
- Added TMF8829 tools from https://github.com/ams-OSRAM/tmf8829_json_logfile_viewer - Upgrade JupyterLite
1 parent ccf0163 commit 1278b3b

8 files changed

Lines changed: 1772 additions & 7 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737

3838
deploy:
3939
needs: build
40-
if: github.ref == 'refs/heads/main'
40+
# if: github.ref == 'refs/heads/main' # disabled check for main branch
4141
permissions:
4242
pages: write
4343
id-token: write
269 KB
Loading

content/tmf8829/LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (C) 2026 AMS-OSRAM
2+
3+
The MIT License (MIT)
4+
Copyright © 2026 <copyright holders>
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
7+
and associated documentation files (the “Software”), to deal in the Software without
8+
restriction, including without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
10+
Software is furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all copies or
13+
substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
16+
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

content/tmf8829/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# TMF8829 JSON Logfile HTML converter
2+
3+
This repository copies content from https://github.com/ams-OSRAM/tmf8829_json_logfile_viewer and modifies
4+
execution to run the scripts inside JupyterLite. Example to convert all json.gz files to html files:
5+
6+
```python
7+
%run json_to_html.py -i .
8+
```
9+
10+
This tool enables the easy conversion of JSON logfile outputs to html for interactive viewing of
11+
12+
* Distance information in physical distance and x/y/z
13+
* Noise, crosstalk (xtalk), SNR and signal amplitude of each pixel
14+
* Histogram data for the pixels (MP) and reference (Ref)
15+
16+
inside a browser.
17+
18+
A typical output is shown below:
19+
![video](https://raw.githubusercontent.com/ams-OSRAM/tmf8829_json_logfile_viewer/refs/heads/main/media/operation.gif)
20+
21+
## Additional tools
22+
23+
### split_json
24+
25+
Split JSON files into smaller files.
26+
27+
### json_to_csv
28+
29+
JSON to csv converter - e.g. for using with excel.
30+
31+
## Howto use
32+
33+
JSON logfiles can be created using the ams-OSRAM evaluation software downloaded from https://ams-osram.com/tmf8829 - see the user guide for the EVM howto create these files.
34+
35+
Alternatively JSON logfiles can be created with [tmf8829_zeromq_client.py](https://github.com/ams-OSRAM/tmf8829_driver_python/blob/main/tmf8829/zeromq/tmf8829_zeromq_client.py) or the exe program inside TMF8829_Driver_ZMQ_Server_Client_EXE_v-latest-version.zip from https://ams-osram.com/tmf8829 website.
36+
37+
### Inside JupyterLite .ipynb file
38+
Create a JupyterLite file and replace 'tmf8829_log_1770799073' with your actual logfile.
39+
40+
```python
41+
# JSON to HTML conversion
42+
%run json_to_html.py -i tmf8829_log_1770799073.json.gz
43+
44+
# split JSON file into smaller files with 10 measurements
45+
%run split_json.py -i tmf8829_log_1770799073.json.gz -n 10
46+
47+
# JSON to CSV conversion
48+
%run json_to_csv.py tmf8829_log_1770799073.json.gz tmf8829_log_1770799073.csv
49+
```
50+
51+
and open the created html file *tmf8829_log_1770799073._viewer.html* inside JupyterLite
52+
and allow 'Trust HTML':
53+
54+
![image](https://raw.githubusercontent.com//ptr814/ptr814.github.io/refs/heads/main/content/media/operation_jupyterlite.jpg)

content/tmf8829/json_to_csv.py

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#!/usr/bin/env python3
2+
3+
# *****************************************************************************
4+
# * Copyright by ams OSRAM AG *
5+
# * All rights are reserved. *
6+
# * *
7+
# *FOR FULL LICENSE TEXT SEE LICENSES.TXT *
8+
# *****************************************************************************
9+
10+
# Revision log
11+
# 0.1 Initial revision
12+
# 1.0 Updatae to newer json file format logger VERSION = 0x0003
13+
14+
''' Convert a json file to csv'''
15+
16+
import sys
17+
import time
18+
import json
19+
import csv
20+
import gzip
21+
from tkinter import filedialog as tk_fd
22+
23+
histogram_counter = 0
24+
25+
def writeFrameData(data:dict) -> None:
26+
27+
global histogram_counter
28+
29+
if not "Result_Set" in data:
30+
return
31+
32+
for frame in data["Result_Set"]:
33+
34+
if "results" in frame:
35+
histogram_counter = 0
36+
pixel = 0
37+
38+
header_key = []
39+
header_key.append("#PIXEL")
40+
41+
# generate row with keys
42+
row_keys = frame["results"][0][0].keys()
43+
if 'noise' in row_keys:
44+
header_key.append("noise")
45+
if 'xtalk' in row_keys:
46+
header_key.append("xtalk")
47+
if 'peaks' in row_keys:
48+
for i, peak in enumerate(frame["results"][0][0]['peaks']):
49+
if 'distance' in peak:
50+
header_key.append(f"distance{i}")
51+
if 'snr' in peak:
52+
header_key.append(f"snr{i}")
53+
if 'signal' in peak:
54+
header_key.append(f"signal{i}")
55+
if 'x' in peak:
56+
header_key.append(f"x{i}")
57+
if 'y' in peak:
58+
header_key.append(f"y{i}")
59+
if 'z' in peak:
60+
header_key.append(f"z{i}")
61+
csvout.writerow(header_key)
62+
63+
# log the results
64+
65+
for result in frame["results"]:
66+
for result_line in result:
67+
row_val = []
68+
row_val.append(f"#PIXEL{pixel:04}")
69+
if 'noise' in result_line:
70+
row_val.append(result_line["noise"])
71+
if 'xtalk' in result_line:
72+
row_val.append(result_line["xtalk"])
73+
if 'peaks' in result_line:
74+
for peak in result_line["peaks"]:
75+
if 'distance' in peak:
76+
row_val.append(peak["distance"])
77+
if 'snr' in peak:
78+
row_val.append(peak["snr"])
79+
if 'signal' in peak:
80+
row_val.append(peak["signal"])
81+
if 'x' in peak:
82+
row_val.append(peak["x"])
83+
if 'y' in peak:
84+
row_val.append(peak["y"])
85+
if 'z' in peak:
86+
row_val.append(peak["z"])
87+
csvout.writerow(row_val)
88+
pixel += 1
89+
90+
if "mp_histo" in frame:
91+
header_key = []
92+
header_key.append("#RAWBIN")
93+
for i in range(64):
94+
header_key.append(i)
95+
csvout.writerow(header_key)
96+
97+
for mp_data in frame["mp_histo"]:
98+
for histogram in mp_data:
99+
row_val = []
100+
row_val.append(f"#RAW{histogram_counter:03}")
101+
histogram_counter +=1
102+
for value in histogram["bin"]:
103+
row_val.append(value)
104+
csvout.writerow(row_val)
105+
106+
def dumpSection( data:dict, section_name:str, section_tag:str ) -> None:
107+
if section_name in data.keys():
108+
row_key = []
109+
row_value = []
110+
row_key.append(section_tag)
111+
row_value.append(section_tag)
112+
for key, value in data[section_name].items():
113+
row_key.append(key)
114+
row_value.append(value)
115+
csvout.writerow(row_key)
116+
csvout.writerow(row_value)
117+
118+
if __name__ == "__main__":
119+
120+
if len(sys.argv) == 1:
121+
filenames = tk_fd.askopenfilenames(title='Open files', initialdir='./', filetypes=[('Json File', '.json .gz')])
122+
123+
if len(filenames) == 0:
124+
print("Aborted by user.")
125+
sys.exit()
126+
else:
127+
if len(sys.argv) < 3:
128+
print("Missing argument!")
129+
print("Usage : json_2_csv.py inputfile.json/json.gz outputfile.csv")
130+
sys.exit()
131+
filenames = []
132+
filenames.append(sys.argv[1])
133+
134+
# record start time
135+
start = time.time()
136+
137+
for file in filenames:
138+
139+
if file[-2:] == "gz": # Check if we have a gzip compressed file or an uncompressed json file
140+
with gzip.open(file,"r") as gzip_data: # Open the gzip archive
141+
json_data = gzip_data.read() # Read the gzip data into json_data ( byte array )
142+
json_str = json_data.decode("utf-8") # Decode the byte array -> string
143+
measurement_data = json.loads(json_str) # Read the json data
144+
145+
elif file[-4:] == "json":
146+
with open(file) as json_file:
147+
measurement_data = json.load(json_file)
148+
149+
# open CSV writer
150+
if len(sys.argv) == 1:
151+
if (file[-2:] == "gz"):
152+
csv_file_name = file.replace("json.gz","csv")
153+
elif (file[-4:] == "json"):
154+
csv_file_name = file.replace("json","csv")
155+
156+
f = open(csv_file_name,'w', encoding='UTF8', newline='' )
157+
else:
158+
f = open(sys.argv[2],'w', encoding='UTF8', newline='' )
159+
160+
f.write( "sep=,\n")
161+
csvout = csv.writer( f, delimiter=',')
162+
163+
dumpSection(measurement_data, "configuration", "#CONFIG")
164+
writeFrameData(measurement_data)
165+
166+
if len(sys.argv) == 1:
167+
print("Data written to {}".format(csv_file_name))
168+
else:
169+
print("Data written to {}".format(sys.argv[2]))
170+
171+
# csv file close
172+
f.close()
173+
174+
# record end time
175+
end = time.time()
176+
print("Conversion finished in {:.3f}".format(end-start), "s")

0 commit comments

Comments
 (0)