feat: add ini→yaml conversion and tests for SP2-XR instrument parameters
This commit is contained in:
266
tests/data/sample_SP2XR.ini
Normal file
266
tests/data/sample_SP2XR.ini
Normal file
@@ -0,0 +1,266 @@
|
||||
[Custom]
|
||||
Display Tab=TRUE
|
||||
Display Names=<2>
|
||||
Display Names 0=set 1
|
||||
Display Names 1=set 2
|
||||
Sets=<2>
|
||||
Sets 0.Cluster.Graph 1=<8>
|
||||
Sets 0.Cluster.Graph 1 0.Plot.Channel=+5V Laser Rail (V)
|
||||
Sets 0.Cluster.Graph 1 0.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 1 1.Plot.Channel= +5V Rail (V)
|
||||
Sets 0.Cluster.Graph 1 1.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 1 2.Plot.Channel=+12V Rail (V)
|
||||
Sets 0.Cluster.Graph 1 2.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 1 3.Plot.Channel=3.3V Iso Rail (V)
|
||||
Sets 0.Cluster.Graph 1 3.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 1 4.Plot.Channel=UPS Output (V)
|
||||
Sets 0.Cluster.Graph 1 4.Plot.Left/Right=TRUE
|
||||
Sets 0.Cluster.Graph 1 5.Plot.Channel=Inlet Air Temp (C)
|
||||
Sets 0.Cluster.Graph 1 5.Plot.Left/Right=TRUE
|
||||
Sets 0.Cluster.Graph 1 6.Plot.Channel=Crystal TEC Temp (C)
|
||||
Sets 0.Cluster.Graph 1 6.Plot.Left/Right=TRUE
|
||||
Sets 0.Cluster.Graph 1 7.Plot.Channel=Laser Heatsink Temp (C)
|
||||
Sets 0.Cluster.Graph 1 7.Plot.Left/Right=TRUE
|
||||
Sets 0.Cluster.Graph 2=<8>
|
||||
Sets 0.Cluster.Graph 2 0.Plot.Channel=Laser TEC Temp (C)
|
||||
Sets 0.Cluster.Graph 2 0.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 2 1.Plot.Channel=Crystal TEC Temp (C)
|
||||
Sets 0.Cluster.Graph 2 1.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 2 2.Plot.Channel=Inlet Air Temp (C)
|
||||
Sets 0.Cluster.Graph 2 2.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 2 3.Plot.Channel=Computer Heatsink Temp (C)
|
||||
Sets 0.Cluster.Graph 2 3.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 2 4.Plot.Channel=Laser Heatsink Temp (C)
|
||||
Sets 0.Cluster.Graph 2 4.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 2 5.Plot.Channel=Outlet Air Temp (C)
|
||||
Sets 0.Cluster.Graph 2 5.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 2 6.Plot.Channel=Battery Temp (C)
|
||||
Sets 0.Cluster.Graph 2 6.Plot.Left/Right=FALSE
|
||||
Sets 0.Cluster.Graph 2 7.Plot.Channel=Laser TEC Sense
|
||||
Sets 0.Cluster.Graph 2 7.Plot.Left/Right=TRUE
|
||||
Sets 1.Cluster.Graph 1=<4>
|
||||
Sets 1.Cluster.Graph 1 0.Plot.Channel=Threshold Crossing Events
|
||||
Sets 1.Cluster.Graph 1 0.Plot.Left/Right=FALSE
|
||||
Sets 1.Cluster.Graph 1 1.Plot.Channel=Dual Qualified Scatter and Incand Particles
|
||||
Sets 1.Cluster.Graph 1 1.Plot.Left/Right=FALSE
|
||||
Sets 1.Cluster.Graph 1 2.Plot.Channel=Qualified Scatter Only Particles
|
||||
Sets 1.Cluster.Graph 1 2.Plot.Left/Right=FALSE
|
||||
Sets 1.Cluster.Graph 1 3.Plot.Channel=Qualified Incand Only Particles
|
||||
Sets 1.Cluster.Graph 1 3.Plot.Left/Right=FALSE
|
||||
Sets 1.Cluster.Graph 2=<8>
|
||||
Sets 1.Cluster.Graph 2 0.Plot.Channel=Baseline Sizer Lo
|
||||
Sets 1.Cluster.Graph 2 0.Plot.Left/Right=FALSE
|
||||
Sets 1.Cluster.Graph 2 1.Plot.Channel=Baseline Sizer Hi
|
||||
Sets 1.Cluster.Graph 2 1.Plot.Left/Right=FALSE
|
||||
Sets 1.Cluster.Graph 2 2.Plot.Channel=Baseline Incand Lo
|
||||
Sets 1.Cluster.Graph 2 2.Plot.Left/Right=FALSE
|
||||
Sets 1.Cluster.Graph 2 3.Plot.Channel=Baseline Incand Hi
|
||||
Sets 1.Cluster.Graph 2 3.Plot.Left/Right=FALSE
|
||||
Sets 1.Cluster.Graph 2 4.Plot.Channel=Bandwidth Sizer Hi
|
||||
Sets 1.Cluster.Graph 2 4.Plot.Left/Right=TRUE
|
||||
Sets 1.Cluster.Graph 2 5.Plot.Channel=Bandwidth Sizer Lo
|
||||
Sets 1.Cluster.Graph 2 5.Plot.Left/Right=TRUE
|
||||
Sets 1.Cluster.Graph 2 6.Plot.Channel=Bandwidth Incand Lo
|
||||
Sets 1.Cluster.Graph 2 6.Plot.Left/Right=TRUE
|
||||
Sets 1.Cluster.Graph 2 7.Plot.Channel=Bandwidth Incand Hi
|
||||
Sets 1.Cluster.Graph 2 7.Plot.Left/Right=TRUE
|
||||
[Raw Options]
|
||||
byte 0: data mux=High Dynamic Range Traces
|
||||
Raw Data Particle Selection=First Scatter
|
||||
Scatter relPeak=0
|
||||
Incand relPeak=0
|
||||
Inter-raw Period (ms)=100
|
||||
leader sample count=400
|
||||
footer sample count=400
|
||||
[Scatter Parameters]
|
||||
Graph=Counts
|
||||
X Mode=Size
|
||||
Norm?=FALSE
|
||||
Cumulative=FALSE
|
||||
[Versions]
|
||||
Instrument Name=SP2XR
|
||||
SP2 Version=2.01.01.19
|
||||
Acq Version=2.00.00.00
|
||||
Last Date Updated=4/11/2019 6:24:36 AM
|
||||
[Trigger Settings]
|
||||
Scatter Transit Time Min=10
|
||||
Scatter Transit Time Max=65535
|
||||
Scatter FWHM Min=30
|
||||
Scatter FWHM Max=65535
|
||||
Scatter Inter Particle Time Min=10
|
||||
Incand Transit Time Min=5
|
||||
Incand Transit Time Max=65535
|
||||
Incand FWHM Min=30
|
||||
Incand FWHM Max=65535
|
||||
Incand Inter Particle Time Min=10
|
||||
Paired Particle Delay Max=10
|
||||
Scatter Threshold Min=36100
|
||||
Scatter Hysteresis Min=2703
|
||||
Incand Threshold Min=50700
|
||||
Incand Hysteresis Min=5394
|
||||
Scatter Threshold Max=559000000
|
||||
Scatter Hysteresis Max=0
|
||||
Incand Threshold Max=2147483647
|
||||
Incand Hysteresis Max=0
|
||||
Forced Trigger=FALSE
|
||||
Forced Trigger Interval(ms)=1000
|
||||
[# Samples S]
|
||||
# Samples S=0
|
||||
[Program]
|
||||
Data File Path=D:\DMT\SP2XR Data
|
||||
Restart Files=FALSE
|
||||
Graph 0 Left=YAG Output Monitor (V)
|
||||
Graph 0 Right=Laser Driver Current Monitor (A)
|
||||
Graph 1 Left=Scattering Particle Conc (cts/ccm)
|
||||
Graph 1 Right=Incand Particle Conc (cts/ccm)
|
||||
Control Cycle Time=0
|
||||
NTP Server=
|
||||
Write File?=FALSE
|
||||
Graph Backgrounds=16448250
|
||||
Graph 2 Left=Sheath Flow Controller Read (sccm)
|
||||
Graph 2 Right=Sample Flow Controller Read (sccm)
|
||||
Description=
|
||||
Serial Number=0001
|
||||
2 or 3 Graphs=TRUE
|
||||
Time Range=12 Hours
|
||||
OSDS Format=
|
||||
Num to Avg=0
|
||||
Global 2=0
|
||||
Global 3=0
|
||||
Global 4=0
|
||||
Global 5=0
|
||||
Shut Down Sequence=
|
||||
Crisis Shut Down Seq=turn off pump and laser
|
||||
Write SP2b Data File=TRUE
|
||||
Write HK File=TRUE
|
||||
Write Raw Binary Data=TRUE
|
||||
TabChannelNum=0
|
||||
OptimizeChannelNum=0
|
||||
Write HDF5 File=TRUE
|
||||
NumParticlesPerHDF5File=100000
|
||||
Laser Temp Set=29
|
||||
Laser Current Set=1.9
|
||||
Spare 4 Set=0
|
||||
Spare 5 Set=0
|
||||
PMT HV Set=0.46
|
||||
Interface Board Scaling=<24>
|
||||
Interface Board Scaling 0=1/(0.000849+0.000261*ln(10000/(65536/VAR-1))+0.000000125*ln(10000/(65536/VAR-1))^3)-273.15
|
||||
Interface Board Scaling 1=
|
||||
Interface Board Scaling 2=(1.0 / (1.1135E-3 + 2.368E-4 * (ln(1E4 * (1-(VAR / (65536.0 * 1.001))) / (VAR / (65536.0 * 1.001)))) + 7.396E-8 * (ln(1E4 * (1-(VAR / (65536.0 * 1.001))) / (VAR / (65536.0 * 1.001))))^3)) - 273.15
|
||||
Interface Board Scaling 3=(1.0 / (1.1135E-3 + 2.368E-4 * (ln(1E4 * (1-(VAR / (65536.0 * 1.001))) / (VAR / (65536.0 * 1.001)))) + 7.396E-8 * (ln(1E4 * (1-(VAR / (65536.0 * 1.001))) / (VAR / (65536.0 * 1.001))))^3)) - 273.15
|
||||
Interface Board Scaling 4=(1.0 / (1.1135E-3 + 2.368E-4 * (ln(1E4 * (1-(VAR / (65536.0 * 1.001))) / (VAR / (65536.0 * 1.001)))) + 7.396E-8 * (ln(1E4 * (1-(VAR / (65536.0 * 1.001))) / (VAR / (65536.0 * 1.001))))^3)) - 273.15
|
||||
Interface Board Scaling 5=(1.0 / (1.1135E-3 + 2.368E-4 * (ln(1E4 * (1-(VAR / (65536.0 * 1.001))) / (VAR / (65536.0 * 1.001)))) + 7.396E-8 * (ln(1E4 * (1-(VAR / (65536.0 * 1.001))) / (VAR / (65536.0 * 1.001))))^3)) - 273.15
|
||||
Interface Board Scaling 6=0.0000625*VAR
|
||||
Interface Board Scaling 7=VAR/72+105.55
|
||||
Interface Board Scaling 8=0.125*VAR
|
||||
Interface Board Scaling 9=0.000125*VAR
|
||||
Interface Board Scaling 10=0.000125*VAR
|
||||
Interface Board Scaling 11=2.01*0.0000625 *VAR
|
||||
Interface Board Scaling 12=
|
||||
Interface Board Scaling 13=0.000125*VAR
|
||||
Interface Board Scaling 14=0.000125*VAR
|
||||
Interface Board Scaling 15=4.57*0.0000625*VAR
|
||||
Interface Board Scaling 16=0.0152587890625*VAR
|
||||
Interface Board Scaling 17=1/(0.000894+0.00025*ln((1662.22* VAR)/(39897.3 - VAR))+0.0000002*ln((1662.22*VAR)/(39897.3 -VAR))^3)-273.15
|
||||
Interface Board Scaling 18=(69.8+11.5) /11.5*0.0000625*VAR
|
||||
Interface Board Scaling 19=4.57*0.0000625*VAR
|
||||
Interface Board Scaling 20=0.000125*VAR
|
||||
Interface Board Scaling 21=1.1*0.0000625 *VAR
|
||||
Interface Board Scaling 22=
|
||||
Interface Board Scaling 23=
|
||||
ABD 0408 Scaling=<16>
|
||||
ABD 0408 Scaling 0=
|
||||
ABD 0408 Scaling 1=
|
||||
ABD 0408 Scaling 2=
|
||||
ABD 0408 Scaling 3=
|
||||
ABD 0408 Scaling 4=
|
||||
ABD 0408 Scaling 5=VAR*0.00625
|
||||
ABD 0408 Scaling 6=7.98*(6.25E-5*VAR)
|
||||
ABD 0408 Scaling 7=-84.962*(6.25E-5*VAR-1.8639)
|
||||
ABD 0408 Scaling 8=
|
||||
ABD 0408 Scaling 9=
|
||||
ABD 0408 Scaling 10=
|
||||
ABD 0408 Scaling 11=
|
||||
ABD 0408 Scaling 12=
|
||||
ABD 0408 Scaling 13=
|
||||
ABD 0408 Scaling 14=
|
||||
ABD 0408 Scaling 15=
|
||||
Save Every Nth Particle=1
|
||||
zip files=TRUE
|
||||
Particle Density (g/cc)=1.8
|
||||
Pump Start-Up State=FALSE
|
||||
[Detector DAC Settings]
|
||||
Scatter unused A=23790
|
||||
Scatter unused B=65535
|
||||
[Incand Parameters]
|
||||
Graph=Counts
|
||||
X Mode=Mass
|
||||
Norm?=FALSE
|
||||
Cumulative=FALSE
|
||||
[Control]
|
||||
Alarms=<3>
|
||||
Alarms 0.Alarm.Name=TurnPumpON
|
||||
Alarms 0.Alarm.Channel=Elapsed Time
|
||||
Alarms 0.Alarm.Condition=>
|
||||
Alarms 0.Alarm.Threshold=0
|
||||
Alarms 0.Alarm.Action=Turn Pump On
|
||||
Alarms 0.Alarm.Hysteresis=0
|
||||
Alarms 0.Alarm.Target Channel=
|
||||
Alarms 0.Alarm.Set Value=0
|
||||
Alarms 0.Alarm.Min Time=0
|
||||
Alarms 0.Alarm.Sequence=turn off pump and laser
|
||||
Alarms 0.Alarm.Target Alarm=TurnPumpON
|
||||
Alarms 1.Alarm.Name=Turn Laser On
|
||||
Alarms 1.Alarm.Channel=Elapsed Time
|
||||
Alarms 1.Alarm.Condition=>
|
||||
Alarms 1.Alarm.Threshold=5
|
||||
Alarms 1.Alarm.Action=Turn Laser On
|
||||
Alarms 1.Alarm.Hysteresis=0
|
||||
Alarms 1.Alarm.Target Channel=
|
||||
Alarms 1.Alarm.Set Value=0
|
||||
Alarms 1.Alarm.Min Time=0
|
||||
Alarms 1.Alarm.Sequence=
|
||||
Alarms 1.Alarm.Target Alarm=Turn Laser On
|
||||
Alarms 2.Alarm.Name=StartRecording
|
||||
Alarms 2.Alarm.Channel=Elapsed Time
|
||||
Alarms 2.Alarm.Condition=>
|
||||
Alarms 2.Alarm.Threshold=10
|
||||
Alarms 2.Alarm.Action=Start Writing Data
|
||||
Alarms 2.Alarm.Hysteresis=0
|
||||
Alarms 2.Alarm.Target Channel=
|
||||
Alarms 2.Alarm.Set Value=0
|
||||
Alarms 2.Alarm.Min Time=0
|
||||
Alarms 2.Alarm.Sequence=
|
||||
Alarms 2.Alarm.Target Alarm=Turn Laser On
|
||||
Sequences=<0>
|
||||
Timers=<0>
|
||||
[Pump]
|
||||
Pump=TRUE
|
||||
[# Samples I]
|
||||
# Samples I=0
|
||||
[SampleFlow]
|
||||
SampleFlow (sccm)=30
|
||||
[SheathFlow]
|
||||
SheathFlow (sccm)=600
|
||||
[Polling Interval]
|
||||
HK Stream Interval (ms)=1000
|
||||
PbP Stream Interval (ms)=1000
|
||||
[Fans Settings]
|
||||
Case Fan Mode=normal
|
||||
Case Fan On Threshold=35
|
||||
Case Fan Off Threshold=33
|
||||
Laser Fan Mode=forced off
|
||||
Laser Fan On Threshold=27
|
||||
Laser Fan Off Threshold=24
|
||||
[Channel Order]
|
||||
Channel Order=<0>
|
||||
Digits=<0>
|
||||
[Streaming Data]
|
||||
Port=0
|
||||
Baud Rate=0
|
||||
Channels=<0>
|
||||
Bus=Serial Port
|
||||
[Calculated Channels]
|
||||
Calculated Channels=<0>
|
||||
[Calculations]
|
||||
Calculations=<0>
|
||||
39
tests/test_xr_ini_to_yaml.py
Normal file
39
tests/test_xr_ini_to_yaml.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
from sp2xr.helpers import read_xr_ini_file, export_xr_ini_to_yaml
|
||||
|
||||
# Paths for testing
|
||||
DATA = Path(__file__).parent / "data"
|
||||
INI_FILE = DATA / "sample_SP2XR.ini"
|
||||
YAML_FILE = DATA / "sample_SP2XR_config.yaml"
|
||||
|
||||
|
||||
def test_ini_to_yaml_conversion(tmp_path):
|
||||
"""Test that an .ini file is correctly parsed and exported to YAML."""
|
||||
|
||||
# 1. Read parameters from ini
|
||||
params = read_xr_ini_file(INI_FILE)
|
||||
assert isinstance(params, dict)
|
||||
assert "SaveRate" in params, "Missing expected parameter from ini parsing"
|
||||
|
||||
# 2. Export to YAML
|
||||
yaml_path = tmp_path / "out_config.yaml"
|
||||
export_xr_ini_to_yaml(INI_FILE, yaml_path)
|
||||
assert yaml_path.exists(), "YAML file was not created"
|
||||
|
||||
# 3. Reload YAML and check values
|
||||
with open(yaml_path, "r") as f:
|
||||
loaded = yaml.safe_load(f)
|
||||
assert "SaveRate" in loaded, "SaveRate not found in YAML output"
|
||||
|
||||
# 4. Simulate user adding calibration
|
||||
loaded["calibration"] = {"mass_factor": 1.05, "mass_offset": -0.1}
|
||||
with open(yaml_path, "w") as f:
|
||||
yaml.dump(loaded, f, sort_keys=False)
|
||||
|
||||
# 5. Reload and verify calibration is preserved
|
||||
with open(yaml_path, "r") as f:
|
||||
updated = yaml.safe_load(f)
|
||||
assert "calibration" in updated, "Calibration section missing after update"
|
||||
|
||||
print("✅ INI → YAML conversion test passed successfully")
|
||||
Reference in New Issue
Block a user