RDSS/gui/tabs/main_config.py

1411 lines
70 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env python3
"""
主配置选项卡
"""
import customtkinter as ctk
from tkinter import filedialog
class MainConfigTab(ctk.CTkFrame):
def __init__(self, parent):
super().__init__(parent)
# 配置网格布局
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=0)
self.grid_rowconfigure(1, weight=0)
self.grid_rowconfigure(2, weight=0)
# 基本设置框架
self.basic_frame = ctk.CTkFrame(self)
self.basic_frame.grid(row=0, column=0, sticky="nsew", pady=(0, 10))
self.basic_frame.grid_columnconfigure(0, weight=1)
# 标题
ctk.CTkLabel(
self.basic_frame,
text="基本设置",
font=ctk.CTkFont(size=14, weight="bold")
).grid(row=0, column=0, sticky="w", padx=10, pady=10)
# 事件数量
self.num_events_var = ctk.StringVar(value="8")
self.num_events_var.trace_add('write', self._on_config_change)
ctk.CTkLabel(self.basic_frame, text="序列数量:").grid(row=1, column=0, sticky="w", padx=20, pady=5)
self.num_events_entry = ctk.CTkEntry(
self.basic_frame,
textvariable=self.num_events_var,
width=100
)
self.num_events_entry.grid(row=1, column=0, sticky="w", padx=100, pady=5)
# 添加输入验证
self.num_events_entry.configure(validate="key", validatecommand=(self.num_events_entry.register(self._validate_integer), '%P'))
# 事件生成模式
ctk.CTkLabel(self.basic_frame, text="事件生成模式:").grid(row=2, column=0, sticky="w", padx=20, pady=5)
self.generation_mode_var = ctk.StringVar(value="random")
self.generation_mode_var.trace_add('write', self._on_config_change)
mode_frame = ctk.CTkFrame(self.basic_frame)
mode_frame.grid(row=2, column=0, sticky="w", padx=100, pady=5)
ctk.CTkRadioButton(
mode_frame,
text="随机模式",
variable=self.generation_mode_var,
value="random"
).pack(side="left", padx=10)
ctk.CTkRadioButton(
mode_frame,
text="固定模式",
variable=self.generation_mode_var,
value="fixed"
).pack(side="left", padx=10)
ctk.CTkRadioButton(
mode_frame,
text="脉冲模式",
variable=self.generation_mode_var,
value="pulse"
).pack(side="left", padx=10)
# 打包模式
ctk.CTkLabel(self.basic_frame, text="打包模式:").grid(row=3, column=0, sticky="w", padx=20, pady=5)
self.packing_mode_var = ctk.StringVar(value="separate")
self.packing_mode_var.trace_add('write', self._on_config_change)
pack_frame = ctk.CTkFrame(self.basic_frame)
pack_frame.grid(row=3, column=0, sticky="w", padx=100, pady=5)
ctk.CTkRadioButton(
pack_frame,
text="单独打包(每事件一包)",
variable=self.packing_mode_var,
value="separate"
).pack(side="left", padx=10)
ctk.CTkRadioButton(
pack_frame,
text="整体打包(拼接分包)",
variable=self.packing_mode_var,
value="combined"
).pack(side="left", padx=10)
# 输出格式
ctk.CTkLabel(self.basic_frame, text="输出格式:").grid(row=4, column=0, sticky="w", padx=20, pady=5)
self.output_format_var = ctk.StringVar(value="all")
format_frame = ctk.CTkFrame(self.basic_frame)
format_frame.grid(row=4, column=0, sticky="w", padx=100, pady=5)
self.bin_var = ctk.BooleanVar(value=True)
self.txt_var = ctk.BooleanVar(value=True)
self.debug_var = ctk.BooleanVar(value=False)
ctk.CTkCheckBox(
format_frame,
text="二进制(.bin)",
variable=self.bin_var
).pack(side="left", padx=10)
ctk.CTkCheckBox(
format_frame,
text="文本",
variable=self.txt_var
).pack(side="left", padx=10)
ctk.CTkCheckBox(
format_frame,
text="调试文本",
variable=self.debug_var
).pack(side="left", padx=10)
# 输出文件名
ctk.CTkLabel(self.basic_frame, text="输出文件名:").grid(row=5, column=0, sticky="w", padx=20, pady=5)
self.output_file_var = ctk.StringVar(value="detector_random_separate_8events")
self._user_modified = False # 标记用户是否手动修改过文件名
file_frame = ctk.CTkFrame(self.basic_frame)
file_frame.grid(row=5, column=0, sticky="w", padx=100, pady=5)
file_frame.grid_columnconfigure(0, weight=1)
self.output_entry = ctk.CTkEntry(
file_frame,
textvariable=self.output_file_var,
width=300
)
self.output_entry.grid(row=0, column=0, padx=5, pady=5, sticky="w")
self.output_file_var.trace_add('write', self._on_output_file_changed)
ctk.CTkButton(
file_frame,
text="浏览...",
width=80,
command=self.browse_output_file
).grid(row=0, column=1, padx=5, pady=5, sticky="w")
# 能量转换参数
energy_conversion_frame = ctk.CTkFrame(self.basic_frame)
energy_conversion_frame.grid(row=6, column=0, sticky="w", padx=20, pady=5)
ctk.CTkLabel(energy_conversion_frame, text="能量转换: mV = keV × K + B").pack(side="left", padx=10, pady=5)
ctk.CTkLabel(energy_conversion_frame, text="K:").pack(side="left", padx=10, pady=5)
self.energy_K_var = ctk.StringVar(value="1.0")
self.energy_K_var.trace_add('write', self._on_config_change)
energy_K_entry = ctk.CTkEntry(
energy_conversion_frame,
textvariable=self.energy_K_var,
width=80
)
energy_K_entry.pack(side="left", padx=5, pady=5)
energy_K_entry.configure(validate="key", validatecommand=(energy_K_entry.register(self._validate_float), '%P'))
ctk.CTkLabel(energy_conversion_frame, text="B:").pack(side="left", padx=10, pady=5)
self.energy_B_var = ctk.StringVar(value="0.0")
self.energy_B_var.trace_add('write', self._on_config_change)
energy_B_entry = ctk.CTkEntry(
energy_conversion_frame,
textvariable=self.energy_B_var,
width=80
)
energy_B_entry.pack(side="left", padx=5, pady=5)
energy_B_entry.configure(validate="key", validatecommand=(energy_B_entry.register(self._validate_float), '%P'))
# 工作模式和同步脉冲配置框架
self.timing_frame = ctk.CTkFrame(self)
self.timing_frame.grid(row=1, column=0, sticky="nsew", pady=(0, 10))
self.timing_frame.grid_columnconfigure(0, weight=1)
# 标题
ctk.CTkLabel(
self.timing_frame,
text="工作模式与同步脉冲配置",
font=ctk.CTkFont(size=14, weight="bold")
).grid(row=0, column=0, sticky="w", padx=10, pady=10)
# 工作模式选择
mode_select_frame = ctk.CTkFrame(self.timing_frame)
mode_select_frame.grid(row=1, column=0, sticky="nsew", padx=20, pady=5)
ctk.CTkLabel(mode_select_frame, text="工作模式:").pack(side="left", padx=10, pady=5)
self.work_mode_var = ctk.StringVar(value="CO")
ctk.CTkOptionMenu(
mode_select_frame,
values=["CO", "Sigma", "Combo"],
variable=self.work_mode_var,
width=120
).pack(side="left", padx=10, pady=5)
# 绑定工作模式变化,更新同步脉冲默认值
self.work_mode_var.trace_add('write', self._on_work_mode_change)
# 信号类型选择
ctk.CTkLabel(mode_select_frame, text="信号类型:").pack(side="left", padx=(30, 10), pady=5)
self.signal_type_var = ctk.StringVar(value="电压信号(0x70)")
ctk.CTkOptionMenu(
mode_select_frame,
values=["电压信号(0x70)", "电流信号(0x07)"],
variable=self.signal_type_var,
width=150
).pack(side="left", padx=10, pady=5)
# 同步脉冲配置框架
sync_pulse_frame = ctk.CTkFrame(self.timing_frame)
sync_pulse_frame.grid(row=2, column=0, sticky="nsew", padx=20, pady=10)
sync_pulse_frame.grid_columnconfigure(0, weight=1)
sync_pulse_frame.grid_columnconfigure(1, weight=1)
sync_pulse_frame.grid_columnconfigure(2, weight=1)
sync_pulse_frame.grid_columnconfigure(3, weight=1)
# 同步脉冲1
ctk.CTkLabel(sync_pulse_frame, text="同步脉冲1 个数:").grid(row=0, column=0, sticky="w", padx=10, pady=5)
self.sync_pulse1_count_var = ctk.StringVar(value="475")
pulse1_count_entry = ctk.CTkEntry(sync_pulse_frame, textvariable=self.sync_pulse1_count_var, width=80)
pulse1_count_entry.grid(row=0, column=1, sticky="w", padx=5, pady=5)
pulse1_count_entry.configure(validate="key", validatecommand=(pulse1_count_entry.register(self._validate_integer), '%P'))
ctk.CTkLabel(sync_pulse_frame, text="周期(10ns):").grid(row=0, column=2, sticky="w", padx=10, pady=5)
self.sync_pulse1_period_var = ctk.StringVar(value="16000")
pulse1_period_entry = ctk.CTkEntry(sync_pulse_frame, textvariable=self.sync_pulse1_period_var, width=80)
pulse1_period_entry.grid(row=0, column=3, sticky="w", padx=5, pady=5)
pulse1_period_entry.configure(validate="key", validatecommand=(pulse1_period_entry.register(self._validate_integer), '%P'))
# 同步脉冲1探测器信号数配置
pulse1_signal_frame = ctk.CTkFrame(sync_pulse_frame)
pulse1_signal_frame.grid(row=1, column=0, columnspan=4, sticky="w", padx=20, pady=5)
ctk.CTkLabel(pulse1_signal_frame, text=" 探测器1").pack(side="left", padx=5, pady=5)
self.pulse1_det1_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse1_signal_frame, textvariable=self.pulse1_det1_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse1_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse1_det1_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse1_signal_frame, textvariable=self.pulse1_det1_max_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse1_signal_frame, text="探测器2").pack(side="left", padx=(15, 5), pady=5)
self.pulse1_det2_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse1_signal_frame, textvariable=self.pulse1_det2_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse1_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse1_det2_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse1_signal_frame, textvariable=self.pulse1_det2_max_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse1_signal_frame, text="探测器3").pack(side="left", padx=(15, 5), pady=5)
self.pulse1_det3_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse1_signal_frame, textvariable=self.pulse1_det3_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse1_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse1_det3_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse1_signal_frame, textvariable=self.pulse1_det3_max_var, width=40).pack(side="left", padx=2, pady=5)
# 同步脉冲2
ctk.CTkLabel(sync_pulse_frame, text="同步脉冲2 个数:").grid(row=2, column=0, sticky="w", padx=10, pady=5)
self.sync_pulse2_count_var = ctk.StringVar(value="20")
pulse2_count_entry = ctk.CTkEntry(sync_pulse_frame, textvariable=self.sync_pulse2_count_var, width=80)
pulse2_count_entry.grid(row=2, column=1, sticky="w", padx=5, pady=5)
pulse2_count_entry.configure(validate="key", validatecommand=(pulse2_count_entry.register(self._validate_integer), '%P'))
ctk.CTkLabel(sync_pulse_frame, text="周期(10ns):").grid(row=2, column=2, sticky="w", padx=10, pady=5)
self.sync_pulse2_period_var = ctk.StringVar(value="100000")
pulse2_period_entry = ctk.CTkEntry(sync_pulse_frame, textvariable=self.sync_pulse2_period_var, width=80)
pulse2_period_entry.grid(row=2, column=3, sticky="w", padx=5, pady=5)
pulse2_period_entry.configure(validate="key", validatecommand=(pulse2_period_entry.register(self._validate_integer), '%P'))
# 同步脉冲2探测器信号数配置
pulse2_signal_frame = ctk.CTkFrame(sync_pulse_frame)
pulse2_signal_frame.grid(row=3, column=0, columnspan=4, sticky="w", padx=20, pady=5)
ctk.CTkLabel(pulse2_signal_frame, text=" 探测器1").pack(side="left", padx=5, pady=5)
self.pulse2_det1_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse2_signal_frame, textvariable=self.pulse2_det1_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse2_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse2_det1_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse2_signal_frame, textvariable=self.pulse2_det1_max_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse2_signal_frame, text="探测器2").pack(side="left", padx=(15, 5), pady=5)
self.pulse2_det2_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse2_signal_frame, textvariable=self.pulse2_det2_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse2_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse2_det2_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse2_signal_frame, textvariable=self.pulse2_det2_max_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse2_signal_frame, text="探测器3").pack(side="left", padx=(15, 5), pady=5)
self.pulse2_det3_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse2_signal_frame, textvariable=self.pulse2_det3_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse2_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse2_det3_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse2_signal_frame, textvariable=self.pulse2_det3_max_var, width=40).pack(side="left", padx=2, pady=5)
# 同步脉冲3
ctk.CTkLabel(sync_pulse_frame, text="同步脉冲3 个数:").grid(row=4, column=0, sticky="w", padx=10, pady=5)
self.sync_pulse3_count_var = ctk.StringVar(value="1")
pulse3_count_entry = ctk.CTkEntry(sync_pulse_frame, textvariable=self.sync_pulse3_count_var, width=80)
pulse3_count_entry.grid(row=4, column=1, sticky="w", padx=5, pady=5)
pulse3_count_entry.configure(validate="key", validatecommand=(pulse3_count_entry.register(self._validate_integer), '%P'))
ctk.CTkLabel(sync_pulse_frame, text="周期(10ns):").grid(row=4, column=2, sticky="w", padx=10, pady=5)
self.sync_pulse3_period_var = ctk.StringVar(value="400000")
pulse3_period_entry = ctk.CTkEntry(sync_pulse_frame, textvariable=self.sync_pulse3_period_var, width=80)
pulse3_period_entry.grid(row=4, column=3, sticky="w", padx=5, pady=5)
pulse3_period_entry.configure(validate="key", validatecommand=(pulse3_period_entry.register(self._validate_integer), '%P'))
# 同步脉冲3探测器信号数配置
pulse3_signal_frame = ctk.CTkFrame(sync_pulse_frame)
pulse3_signal_frame.grid(row=5, column=0, columnspan=4, sticky="w", padx=20, pady=5)
ctk.CTkLabel(pulse3_signal_frame, text=" 探测器1").pack(side="left", padx=5, pady=5)
self.pulse3_det1_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse3_signal_frame, textvariable=self.pulse3_det1_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse3_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse3_det1_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse3_signal_frame, textvariable=self.pulse3_det1_max_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse3_signal_frame, text="探测器2").pack(side="left", padx=(15, 5), pady=5)
self.pulse3_det2_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse3_signal_frame, textvariable=self.pulse3_det2_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse3_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse3_det2_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse3_signal_frame, textvariable=self.pulse3_det2_max_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse3_signal_frame, text="探测器3").pack(side="left", padx=(15, 5), pady=5)
self.pulse3_det3_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse3_signal_frame, textvariable=self.pulse3_det3_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse3_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse3_det3_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse3_signal_frame, textvariable=self.pulse3_det3_max_var, width=40).pack(side="left", padx=2, pady=5)
# 同步脉冲4
ctk.CTkLabel(sync_pulse_frame, text="同步脉冲4 个数:").grid(row=6, column=0, sticky="w", padx=10, pady=5)
self.sync_pulse4_count_var = ctk.StringVar(value="0")
pulse4_count_entry = ctk.CTkEntry(sync_pulse_frame, textvariable=self.sync_pulse4_count_var, width=80)
pulse4_count_entry.grid(row=6, column=1, sticky="w", padx=5, pady=5)
pulse4_count_entry.configure(validate="key", validatecommand=(pulse4_count_entry.register(self._validate_integer), '%P'))
ctk.CTkLabel(sync_pulse_frame, text="周期(10ns):").grid(row=6, column=2, sticky="w", padx=10, pady=5)
self.sync_pulse4_period_var = ctk.StringVar(value="0")
pulse4_period_entry = ctk.CTkEntry(sync_pulse_frame, textvariable=self.sync_pulse4_period_var, width=80)
pulse4_period_entry.grid(row=6, column=3, sticky="w", padx=5, pady=5)
pulse4_period_entry.configure(validate="key", validatecommand=(pulse4_period_entry.register(self._validate_integer), '%P'))
# 同步脉冲4探测器信号数配置
pulse4_signal_frame = ctk.CTkFrame(sync_pulse_frame)
pulse4_signal_frame.grid(row=7, column=0, columnspan=4, sticky="w", padx=20, pady=5)
ctk.CTkLabel(pulse4_signal_frame, text=" 探测器1").pack(side="left", padx=5, pady=5)
self.pulse4_det1_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse4_signal_frame, textvariable=self.pulse4_det1_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse4_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse4_det1_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse4_signal_frame, textvariable=self.pulse4_det1_max_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse4_signal_frame, text="探测器2").pack(side="left", padx=(15, 5), pady=5)
self.pulse4_det2_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse4_signal_frame, textvariable=self.pulse4_det2_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse4_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse4_det2_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse4_signal_frame, textvariable=self.pulse4_det2_max_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse4_signal_frame, text="探测器3").pack(side="left", padx=(15, 5), pady=5)
self.pulse4_det3_min_var = ctk.StringVar(value="1")
ctk.CTkEntry(pulse4_signal_frame, textvariable=self.pulse4_det3_min_var, width=40).pack(side="left", padx=2, pady=5)
ctk.CTkLabel(pulse4_signal_frame, text="-").pack(side="left", padx=2, pady=5)
self.pulse4_det3_max_var = ctk.StringVar(value="10")
ctk.CTkEntry(pulse4_signal_frame, textvariable=self.pulse4_det3_max_var, width=40).pack(side="left", padx=2, pady=5)
# 探测器设置框架
self.detector_frame = ctk.CTkFrame(self)
self.detector_frame.grid(row=2, column=0, sticky="nsew", pady=(0, 10))
self.detector_frame.grid_columnconfigure(0, weight=1)
# 标题
ctk.CTkLabel(
self.detector_frame,
text="探测器设置",
font=ctk.CTkFont(size=14, weight="bold")
).grid(row=0, column=0, sticky="w", padx=10, pady=10)
# 探测器选择器
detector_select_frame = ctk.CTkFrame(self.detector_frame)
detector_select_frame.grid(row=1, column=0, sticky="nsew", pady=(0, 10))
self.detector_var = ctk.StringVar(value="detector1")
# 保存当前探测器名称,用于在切换时保存配置
self.current_detector = "detector1"
ctk.CTkRadioButton(
detector_select_frame,
text="探测器1",
variable=self.detector_var,
value="detector1",
command=lambda: self.on_detector_change("detector1")
).pack(side="left", padx=20, pady=10)
ctk.CTkRadioButton(
detector_select_frame,
text="探测器2",
variable=self.detector_var,
value="detector2",
command=lambda: self.on_detector_change("detector2")
).pack(side="left", padx=20, pady=10)
ctk.CTkRadioButton(
detector_select_frame,
text="探测器3",
variable=self.detector_var,
value="detector3",
command=lambda: self.on_detector_change("detector3")
).pack(side="left", padx=20, pady=10)
# 探测器配置框架
self.config_frame = ctk.CTkFrame(self.detector_frame)
self.config_frame.grid(row=2, column=0, sticky="nsew")
# 配置探测器1的默认值
self.detector_configs = {
"detector1": {
"sample_space_size": 5000,
"allow_replacement": True,
"energy_distribution": {
"type": "normal",
"mean": 1000.0,
"std": 200.0
},
"timestamp_distribution": {
"type": "exponential",
"scale": 50.0,
"loc": 0.0
}
},
"detector2": {
"sample_space_size": 4000,
"allow_replacement": True,
"energy_distribution": {
"type": "normal",
"mean": 800.0,
"std": 150.0
},
"timestamp_distribution": {
"type": "uniform",
"low": 0.0,
"high": 200.0
}
},
"detector3": {
"sample_space_size": 6000,
"allow_replacement": True,
"energy_distribution": {
"type": "gamma",
"shape": 2.0,
"scale": 500.0
},
"timestamp_distribution": {
"type": "normal",
"mean": 100.0,
"std": 30.0
}
}
}
# 初始化分布参数变量
self.sample_space_var = ctk.StringVar(value="5000")
self.sample_space_var.trace_add('write', self._on_config_change)
self.allow_replacement_var = ctk.BooleanVar(value=True)
self.allow_replacement_var.trace_add('write', self._on_config_change)
self.energy_dist_type_var = ctk.StringVar(value="normal")
self.energy_dist_type_var.trace_add('write', self._on_config_change)
self.timestamp_dist_type_var = ctk.StringVar(value="exponential")
self.timestamp_dist_type_var.trace_add('write', self._on_config_change)
# 能量分布参数变量
self.energy_mean_var = ctk.StringVar(value="1000.0")
self.energy_mean_var.trace_add('write', self._on_config_change)
self.energy_std_var = ctk.StringVar(value="200.0")
self.energy_std_var.trace_add('write', self._on_config_change)
self.energy_low_var = ctk.StringVar(value="0.0")
self.energy_low_var.trace_add('write', self._on_config_change)
self.energy_high_var = ctk.StringVar(value="2000.0")
self.energy_high_var.trace_add('write', self._on_config_change)
self.energy_scale_var = ctk.StringVar(value="50.0")
self.energy_scale_var.trace_add('write', self._on_config_change)
self.energy_shape_var = ctk.StringVar(value="2.0")
self.energy_shape_var.trace_add('write', self._on_config_change)
self.energy_lam_var = ctk.StringVar(value="1000.0")
self.energy_lam_var.trace_add('write', self._on_config_change)
self.energy_sigma_var = ctk.StringVar(value="0.5")
self.energy_sigma_var.trace_add('write', self._on_config_change)
self.energy_loc_var = ctk.StringVar(value="0.0")
self.energy_loc_var.trace_add('write', self._on_config_change)
self.energy_constant_var = ctk.StringVar(value="1000.0")
self.energy_constant_var.trace_add('write', self._on_config_change)
# 时间戳分布参数变量
self.timestamp_mean_var = ctk.StringVar(value="100.0")
self.timestamp_mean_var.trace_add('write', self._on_config_change)
self.timestamp_std_var = ctk.StringVar(value="30.0")
self.timestamp_std_var.trace_add('write', self._on_config_change)
self.timestamp_low_var = ctk.StringVar(value="0.0")
self.timestamp_low_var.trace_add('write', self._on_config_change)
self.timestamp_high_var = ctk.StringVar(value="200.0")
self.timestamp_high_var.trace_add('write', self._on_config_change)
self.timestamp_scale_var = ctk.StringVar(value="50.0")
self.timestamp_scale_var.trace_add('write', self._on_config_change)
self.timestamp_shape_var = ctk.StringVar(value="2.0")
self.timestamp_shape_var.trace_add('write', self._on_config_change)
self.timestamp_lam_var = ctk.StringVar(value="100.0")
self.timestamp_lam_var.trace_add('write', self._on_config_change)
self.timestamp_sigma_var = ctk.StringVar(value="0.5")
self.timestamp_sigma_var.trace_add('write', self._on_config_change)
self.timestamp_loc_var = ctk.StringVar(value="0.0")
self.timestamp_loc_var.trace_add('write', self._on_config_change)
# 显示当前探测器配置
self.update_config_display()
def _on_config_change(self, *args):
"""配置变化时自动更新输出文件名(仅当用户未手动修改时)"""
# 防止递归调用
if hasattr(self, '_updating_config') and self._updating_config:
return
try:
if not self._user_modified:
# 设置更新标志
self._updating_config = True
# 保存当前探测器的配置(只保存当前探测器,不影响其他探测器)
self.save_detector_config()
generation_mode = self.generation_mode_var.get()
packing_mode = self.packing_mode_var.get()
# 安全获取序列数量,处理非数字输入
try:
num_events = int(self.num_events_var.get())
except Exception:
num_events = 8 # 默认值
# 生成文件名编码
mode_code = {'random': 'R', 'fixed': 'F', 'pulse': 'P'}[generation_mode]
pack_code = {'combined': 'C', 'separate': 'S'}[packing_mode]
# 获取探测器配置
detector_configs = {}
for i in range(1, 4):
det_key = f'detector{i}'
if det_key in self.detector_configs:
detector_configs[det_key] = self.detector_configs[det_key]
# 编码探测器样本空间设置
detector_codes = []
for i in range(1, 4):
det_key = f'detector{i}'
if det_key in detector_configs:
det_config = detector_configs[det_key]
# 样本空间大小(简化表示)
sample_size = det_config.get('sample_space_size', 5000)
if sample_size >= 1000000:
size_code = f"{sample_size//1000000}M"
elif sample_size >= 1000:
size_code = f"{sample_size//1000}K"
else:
size_code = str(sample_size)
# 能量分布编码
energy_dist = det_config.get('energy_distribution', {})
energy_type = energy_dist.get('type', 'normal')
energy_code = {'normal': 'N', 'exponential': 'E', 'gamma': 'G', 'uniform': 'U'}[energy_type]
# 时间戳分布编码
time_dist = det_config.get('timestamp_distribution', {})
time_type = time_dist.get('type', 'exponential')
time_code = {'normal': 'N', 'exponential': 'E', 'gamma': 'G', 'uniform': 'U'}[time_type]
detector_codes.append(f"D{i}{size_code}{energy_code}{time_code}")
detector_str = '_'.join(detector_codes)
# 生成文件名: {模式}{打包}_{事件数}_{探测器编码}
output_filename = f"{mode_code}{pack_code}_{num_events}ev_{detector_str}"
# 检查控件是否还存在
if hasattr(self, 'output_file_var'):
try:
self.output_file_var.set(output_filename)
except:
pass
# 清除更新标志
self._updating_config = False
except Exception as e:
# 确保清除更新标志
self._updating_config = False
pass
def _validate_integer(self, value):
"""验证整数输入"""
if value == "":
return True
try:
int(value)
return True
except ValueError:
return False
def _validate_float(self, value):
"""验证浮点数输入"""
if value == "":
return True
try:
float(value)
return True
except ValueError:
return False
def _on_output_file_focus_in(self, event):
"""当输出文件名文本框获得焦点时,保存当前值"""
# 保存当前值,用于在`_on_output_file_changed`中检查是否真的被修改了
if hasattr(self, 'output_file_var'):
self._last_output_file_value = self.output_file_var.get()
def _on_output_file_changed(self, *args):
"""当输出文件名被手动修改时"""
# 检查是否真的被修改了
if hasattr(self, '_last_output_file_value') and hasattr(self, 'output_file_var'):
if self.output_file_var.get() != self._last_output_file_value:
self._user_modified = True
def _on_work_mode_change(self, *args):
"""工作模式变化时更新同步脉冲默认值"""
mode = self.work_mode_var.get()
if mode == "CO":
self.sync_pulse1_count_var.set("475")
self.sync_pulse1_period_var.set("16000")
self.sync_pulse2_count_var.set("0")
self.sync_pulse2_period_var.set("0")
self.sync_pulse3_count_var.set("0")
self.sync_pulse3_period_var.set("0")
self.sync_pulse4_count_var.set("0")
self.sync_pulse4_period_var.set("0")
elif mode == "Sigma":
self.sync_pulse1_count_var.set("57")
self.sync_pulse1_period_var.set("88000")
self.sync_pulse2_count_var.set("0")
self.sync_pulse2_period_var.set("0")
self.sync_pulse3_count_var.set("0")
self.sync_pulse3_period_var.set("0")
self.sync_pulse4_count_var.set("0")
self.sync_pulse4_period_var.set("0")
elif mode == "Combo":
self.sync_pulse1_count_var.set("475")
self.sync_pulse1_period_var.set("16000")
self.sync_pulse2_count_var.set("20")
self.sync_pulse2_period_var.set("100000")
self.sync_pulse3_count_var.set("4")
self.sync_pulse3_period_var.set("1000000")
self.sync_pulse4_count_var.set("0")
self.sync_pulse4_period_var.set("0")
def browse_output_file(self):
"""浏览输出文件路径"""
filename = filedialog.asksaveasfilename(
defaultextension=".bin",
filetypes=[("Binary files", "*.bin"), ("All files", "*.*")]
)
if filename:
import os
self.output_file_var.set(os.path.splitext(filename)[0])
def on_detector_change(self, new_detector):
"""探测器切换时的回调"""
# 保存当前探测器的配置使用self.current_detector即切换前的探测器
self.save_detector_config_for_detector(self.current_detector)
# 更新当前探测器名称
self.current_detector = new_detector
# 更新配置显示
self.update_config_display()
def update_config_display(self):
"""更新配置显示"""
# 设置更新标志防止在更新配置显示时触发_on_config_change
self._updating_config = True
# 清空现有内容
for widget in self.config_frame.winfo_children():
widget.destroy()
detector = self.detector_var.get()
config = self.detector_configs[detector]
# 样本空间设置(横向排列)
sample_frame = ctk.CTkFrame(self.config_frame)
sample_frame.grid(row=0, column=0, columnspan=2, sticky="w", padx=20, pady=10)
ctk.CTkLabel(sample_frame, text="样本空间大小:").pack(side="left", padx=10, pady=5)
self.sample_space_var.set(str(config["sample_space_size"]))
sample_space_entry = ctk.CTkEntry(
sample_frame,
textvariable=self.sample_space_var,
width=100
)
sample_space_entry.pack(side="left", padx=5, pady=5)
sample_space_entry.configure(validate="key", validatecommand=(sample_space_entry.register(self._validate_integer), '%P'))
self.allow_replacement_var.set(config["allow_replacement"])
ctk.CTkCheckBox(
sample_frame,
text="允许重复抽样",
variable=self.allow_replacement_var
).pack(side="left", padx=20, pady=5)
# 分布类型(同一行)
energy_type_frame = ctk.CTkFrame(self.config_frame)
energy_type_frame.grid(row=3, column=0, columnspan=2, sticky="w", padx=20, pady=5)
ctk.CTkLabel(energy_type_frame, text="能量(keV)分布类型:").pack(side="left", padx=10, pady=5)
self.energy_dist_type_var.set(config["energy_distribution"]["type"])
ctk.CTkOptionMenu(
energy_type_frame,
values=["normal", "uniform", "exponential", "gamma", "poisson", "lognormal", "constant"],
variable=self.energy_dist_type_var,
command=self.on_energy_dist_type_change
).pack(side="left", padx=10, pady=5)
# 分布参数(根据类型动态显示)
self.energy_params_frame = ctk.CTkFrame(self.config_frame)
self.energy_params_frame.grid(row=4, column=0, columnspan=2, sticky="w", padx=40, pady=5)
self.update_energy_params()
# 分布类型(同一行)
timestamp_type_frame = ctk.CTkFrame(self.config_frame)
timestamp_type_frame.grid(row=7, column=0, columnspan=2, sticky="w", padx=20, pady=5)
ctk.CTkLabel(timestamp_type_frame, text="时间戳(us)分布类型:").pack(side="left", padx=10, pady=5)
self.timestamp_dist_type_var.set(config["timestamp_distribution"]["type"])
ctk.CTkOptionMenu(
timestamp_type_frame,
values=["normal", "uniform", "exponential", "gamma", "poisson", "lognormal"],
variable=self.timestamp_dist_type_var,
command=self.on_timestamp_dist_type_change
).pack(side="left", padx=10, pady=5)
# 分布参数(根据类型动态显示)
self.timestamp_params_frame = ctk.CTkFrame(self.config_frame)
self.timestamp_params_frame.grid(row=8, column=0, columnspan=2, sticky="w", padx=40, pady=5)
self.update_timestamp_params()
# 清除更新标志
self._updating_config = False
def on_energy_dist_type_change(self, value):
"""能量分布类型变化时的回调"""
self.update_energy_params()
def on_timestamp_dist_type_change(self, value):
"""时间戳分布类型变化时的回调"""
self.update_timestamp_params()
def update_energy_params(self):
"""更新能量分布参数"""
# 清空现有内容
for widget in self.energy_params_frame.winfo_children():
widget.destroy()
dist_type = self.energy_dist_type_var.get()
config = self.detector_configs[self.detector_var.get()]["energy_distribution"]
if dist_type == "normal":
# 均值和标准差
ctk.CTkLabel(self.energy_params_frame, text="均值:").pack(side="left", padx=10, pady=5)
self.energy_mean_var.set(str(config.get("mean", 1000.0)))
energy_mean_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_mean_var,
width=100
)
energy_mean_entry.pack(side="left", padx=5, pady=5)
energy_mean_entry.configure(validate="key", validatecommand=(energy_mean_entry.register(self._validate_float), '%P'))
ctk.CTkLabel(self.energy_params_frame, text="标准差:").pack(side="left", padx=10, pady=5)
self.energy_std_var.set(str(config.get("std", 200.0)))
energy_std_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_std_var,
width=100
)
energy_std_entry.pack(side="left", padx=5, pady=5)
energy_std_entry.configure(validate="key", validatecommand=(energy_std_entry.register(self._validate_float), '%P'))
elif dist_type == "uniform":
# 最小值和最大值
ctk.CTkLabel(self.energy_params_frame, text="最小值:").pack(side="left", padx=10, pady=5)
self.energy_low_var.set(str(config.get("low", 0.0)))
energy_low_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_low_var,
width=100
)
energy_low_entry.pack(side="left", padx=5, pady=5)
energy_low_entry.configure(validate="key", validatecommand=(energy_low_entry.register(self._validate_float), '%P'))
ctk.CTkLabel(self.energy_params_frame, text="最大值:").pack(side="left", padx=10, pady=5)
self.energy_high_var.set(str(config.get("high", 2000.0)))
energy_high_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_high_var,
width=100
)
energy_high_entry.pack(side="left", padx=5, pady=5)
energy_high_entry.configure(validate="key", validatecommand=(energy_high_entry.register(self._validate_float), '%P'))
elif dist_type == "exponential":
# 尺度参数
ctk.CTkLabel(self.energy_params_frame, text="尺度参数:").pack(side="left", padx=10, pady=5)
self.energy_scale_var.set(str(config.get("scale", 50.0)))
energy_scale_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_scale_var,
width=100
)
energy_scale_entry.pack(side="left", padx=5, pady=5)
energy_scale_entry.configure(validate="key", validatecommand=(energy_scale_entry.register(self._validate_float), '%P'))
# 位置参数(延迟/偏移)
ctk.CTkLabel(self.energy_params_frame, text="延迟/偏移:").pack(side="left", padx=10, pady=5)
self.energy_loc_var.set(str(config.get("loc", 0.0)))
energy_loc_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_loc_var,
width=100
)
energy_loc_entry.pack(side="left", padx=5, pady=5)
energy_loc_entry.configure(validate="key", validatecommand=(energy_loc_entry.register(self._validate_float), '%P'))
elif dist_type == "gamma":
# 尺度参数
ctk.CTkLabel(self.energy_params_frame, text="尺度参数:").pack(side="left", padx=10, pady=5)
self.energy_scale_var.set(str(config.get("scale", 50.0)))
energy_scale_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_scale_var,
width=100
)
energy_scale_entry.pack(side="left", padx=5, pady=5)
energy_scale_entry.configure(validate="key", validatecommand=(energy_scale_entry.register(self._validate_float), '%P'))
# 形状参数
ctk.CTkLabel(self.energy_params_frame, text="形状参数:").pack(side="left", padx=10, pady=5)
self.energy_shape_var.set(str(config.get("shape", 2.0)))
energy_shape_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_shape_var,
width=100
)
energy_shape_entry.pack(side="left", padx=5, pady=5)
energy_shape_entry.configure(validate="key", validatecommand=(energy_shape_entry.register(self._validate_float), '%P'))
elif dist_type == "poisson":
# lambda参数
ctk.CTkLabel(self.energy_params_frame, text="lambda:").pack(side="left", padx=10, pady=5)
self.energy_lam_var.set(str(config.get("lam", 1000.0)))
energy_lam_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_lam_var,
width=100
)
energy_lam_entry.pack(side="left", padx=5, pady=5)
energy_lam_entry.configure(validate="key", validatecommand=(energy_lam_entry.register(self._validate_float), '%P'))
elif dist_type == "lognormal":
# 均值和sigma
ctk.CTkLabel(self.energy_params_frame, text="均值:").pack(side="left", padx=10, pady=5)
self.energy_mean_var.set(str(config.get("mean", 6.0)))
energy_mean_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_mean_var,
width=100
)
energy_mean_entry.pack(side="left", padx=5, pady=5)
energy_mean_entry.configure(validate="key", validatecommand=(energy_mean_entry.register(self._validate_float), '%P'))
ctk.CTkLabel(self.energy_params_frame, text="sigma:").pack(side="left", padx=10, pady=5)
self.energy_sigma_var.set(str(config.get("sigma", 0.5)))
energy_sigma_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_sigma_var,
width=100
)
energy_sigma_entry.pack(side="left", padx=5, pady=5)
energy_sigma_entry.configure(validate="key", validatecommand=(energy_sigma_entry.register(self._validate_float), '%P'))
elif dist_type == "constant":
# 常量值
ctk.CTkLabel(self.energy_params_frame, text="常量值:").pack(side="left", padx=10, pady=5)
self.energy_constant_var.set(str(config.get("value", 1000.0)))
energy_constant_entry = ctk.CTkEntry(
self.energy_params_frame,
textvariable=self.energy_constant_var,
width=100
)
energy_constant_entry.pack(side="left", padx=5, pady=5)
energy_constant_entry.configure(validate="key", validatecommand=(energy_constant_entry.register(self._validate_float), '%P'))
def update_timestamp_params(self):
"""更新时间戳分布参数"""
# 清空现有内容
for widget in self.timestamp_params_frame.winfo_children():
widget.destroy()
dist_type = self.timestamp_dist_type_var.get()
config = self.detector_configs[self.detector_var.get()]["timestamp_distribution"]
if dist_type == "normal":
# 均值和标准差
ctk.CTkLabel(self.timestamp_params_frame, text="均值:").pack(side="left", padx=10, pady=5)
self.timestamp_mean_var.set(config.get("mean", 100.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_mean_var,
width=100
).pack(side="left", padx=5, pady=5)
ctk.CTkLabel(self.timestamp_params_frame, text="标准差:").pack(side="left", padx=10, pady=5)
self.timestamp_std_var.set(config.get("std", 30.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_std_var,
width=100
).pack(side="left", padx=5, pady=5)
elif dist_type == "uniform":
# 最小值和最大值
ctk.CTkLabel(self.timestamp_params_frame, text="最小值:").pack(side="left", padx=10, pady=5)
self.timestamp_low_var.set(config.get("low", 0.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_low_var,
width=100
).pack(side="left", padx=5, pady=5)
ctk.CTkLabel(self.timestamp_params_frame, text="最大值:").pack(side="left", padx=10, pady=5)
self.timestamp_high_var.set(config.get("high", 200.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_high_var,
width=100
).pack(side="left", padx=5, pady=5)
elif dist_type == "exponential":
# 尺度参数
ctk.CTkLabel(self.timestamp_params_frame, text="尺度参数:").pack(side="left", padx=10, pady=5)
self.timestamp_scale_var.set(config.get("scale", 50.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_scale_var,
width=100
).pack(side="left", padx=5, pady=5)
# 位置参数(延迟/偏移)
ctk.CTkLabel(self.timestamp_params_frame, text="延迟/偏移:").pack(side="left", padx=10, pady=5)
self.timestamp_loc_var.set(config.get("loc", 0.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_loc_var,
width=100
).pack(side="left", padx=5, pady=5)
elif dist_type == "gamma":
# 尺度参数
ctk.CTkLabel(self.timestamp_params_frame, text="尺度参数:").pack(side="left", padx=10, pady=5)
self.timestamp_scale_var.set(config.get("scale", 50.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_scale_var,
width=100
).pack(side="left", padx=5, pady=5)
# 形状参数
ctk.CTkLabel(self.timestamp_params_frame, text="形状参数:").pack(side="left", padx=10, pady=5)
self.timestamp_shape_var.set(config.get("shape", 2.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_shape_var,
width=100
).pack(side="left", padx=5, pady=5)
elif dist_type == "poisson":
# lambda参数
ctk.CTkLabel(self.timestamp_params_frame, text="lambda:").pack(side="left", padx=10, pady=5)
self.timestamp_lam_var.set(config.get("lam", 100.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_lam_var,
width=100
).pack(side="left", padx=5, pady=5)
elif dist_type == "lognormal":
# 均值和sigma
ctk.CTkLabel(self.timestamp_params_frame, text="均值:").pack(side="left", padx=10, pady=5)
self.timestamp_mean_var.set(config.get("mean", 4.0))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_mean_var,
width=100
).pack(side="left", padx=5, pady=5)
ctk.CTkLabel(self.timestamp_params_frame, text="sigma:").pack(side="left", padx=10, pady=5)
self.timestamp_sigma_var.set(config.get("sigma", 0.5))
ctk.CTkEntry(
self.timestamp_params_frame,
textvariable=self.timestamp_sigma_var,
width=100
).pack(side="left", padx=5, pady=5)
def save_detector_config(self):
"""保存探测器配置"""
detector = self.detector_var.get()
self.save_detector_config_for_detector(detector)
def save_detector_config_for_detector(self, detector):
"""保存指定探测器的配置"""
if detector not in self.detector_configs:
print(f"警告:探测器 {detector} 不存在")
return
# 更新样本空间大小和替换设置
try:
self.detector_configs[detector]["sample_space_size"] = int(self.sample_space_var.get())
except Exception:
self.detector_configs[detector]["sample_space_size"] = 5000 # 默认值
self.detector_configs[detector]["allow_replacement"] = self.allow_replacement_var.get()
# 更新能量分布 - 先清除旧参数,再设置新参数
dist_type = self.energy_dist_type_var.get()
# 保留type清除其他所有参数
old_config = self.detector_configs[detector]["energy_distribution"]
self.detector_configs[detector]["energy_distribution"] = {"type": dist_type}
if dist_type == "normal":
try:
self.detector_configs[detector]["energy_distribution"]["mean"] = float(self.energy_mean_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["mean"] = 1000.0
try:
self.detector_configs[detector]["energy_distribution"]["std"] = float(self.energy_std_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["std"] = 200.0
elif dist_type == "uniform":
try:
self.detector_configs[detector]["energy_distribution"]["low"] = float(self.energy_low_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["low"] = 0.0
try:
self.detector_configs[detector]["energy_distribution"]["high"] = float(self.energy_high_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["high"] = 2000.0
elif dist_type == "exponential":
try:
self.detector_configs[detector]["energy_distribution"]["scale"] = float(self.energy_scale_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["scale"] = 50.0
try:
self.detector_configs[detector]["energy_distribution"]["loc"] = float(self.energy_loc_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["loc"] = 0.0
elif dist_type == "gamma":
try:
self.detector_configs[detector]["energy_distribution"]["shape"] = float(self.energy_shape_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["shape"] = 2.0
try:
self.detector_configs[detector]["energy_distribution"]["scale"] = float(self.energy_scale_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["scale"] = 50.0
elif dist_type == "poisson":
try:
self.detector_configs[detector]["energy_distribution"]["lam"] = float(self.energy_lam_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["lam"] = 1000.0
elif dist_type == "lognormal":
try:
self.detector_configs[detector]["energy_distribution"]["mean"] = float(self.energy_mean_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["mean"] = 6.0
try:
self.detector_configs[detector]["energy_distribution"]["sigma"] = float(self.energy_sigma_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["sigma"] = 0.5
elif dist_type == "constant":
try:
self.detector_configs[detector]["energy_distribution"]["value"] = float(self.energy_constant_var.get())
except Exception:
self.detector_configs[detector]["energy_distribution"]["value"] = 1000.0
# 更新时间戳分布 - 先清除旧参数,再设置新参数
dist_type = self.timestamp_dist_type_var.get()
# 保留type清除其他所有参数
self.detector_configs[detector]["timestamp_distribution"] = {"type": dist_type}
if dist_type == "normal":
try:
self.detector_configs[detector]["timestamp_distribution"]["mean"] = float(self.timestamp_mean_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["mean"] = 100.0
try:
self.detector_configs[detector]["timestamp_distribution"]["std"] = float(self.timestamp_std_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["std"] = 30.0
elif dist_type == "uniform":
try:
self.detector_configs[detector]["timestamp_distribution"]["low"] = float(self.timestamp_low_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["low"] = 0.0
try:
self.detector_configs[detector]["timestamp_distribution"]["high"] = float(self.timestamp_high_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["high"] = 200.0
elif dist_type == "exponential":
try:
self.detector_configs[detector]["timestamp_distribution"]["scale"] = float(self.timestamp_scale_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["scale"] = 50.0
try:
self.detector_configs[detector]["timestamp_distribution"]["loc"] = float(self.timestamp_loc_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["loc"] = 0.0
elif dist_type == "gamma":
try:
self.detector_configs[detector]["timestamp_distribution"]["shape"] = float(self.timestamp_shape_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["shape"] = 2.0
try:
self.detector_configs[detector]["timestamp_distribution"]["scale"] = float(self.timestamp_scale_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["scale"] = 50.0
elif dist_type == "poisson":
try:
self.detector_configs[detector]["timestamp_distribution"]["lam"] = float(self.timestamp_lam_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["lam"] = 100.0
elif dist_type == "lognormal":
try:
self.detector_configs[detector]["timestamp_distribution"]["mean"] = float(self.timestamp_mean_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["mean"] = 4.0
try:
self.detector_configs[detector]["timestamp_distribution"]["sigma"] = float(self.timestamp_sigma_var.get())
except Exception:
self.detector_configs[detector]["timestamp_distribution"]["sigma"] = 0.5
def get_config(self):
"""获取配置"""
# 保存当前探测器的配置
self.save_detector_config()
# 解析信号类型
signal_type_str = self.signal_type_var.get()
if "0x70" in signal_type_str:
signal_type = 0x0070
else:
signal_type = 0x0007
# 构建基本配置
config = {
"num_events": int(self.num_events_var.get()) if self.num_events_var.get().strip() else 1,
"event_generation_mode": self.generation_mode_var.get(),
"packing_mode": self.packing_mode_var.get(),
"output_format": self._get_output_format(),
"output_file": self.output_file_var.get(),
"energy_conversion": {
"K": float(self.energy_K_var.get()) if self.energy_K_var.get().strip() else 1.0,
"B": float(self.energy_B_var.get()) if self.energy_B_var.get().strip() else 0.0
},
"work_mode": self.work_mode_var.get(),
"signal_type": signal_type,
"sync_pulses": [
{
"count": int(self.sync_pulse1_count_var.get()) if self.sync_pulse1_count_var.get().strip() else 0,
"period": int(self.sync_pulse1_period_var.get()) if self.sync_pulse1_period_var.get().strip() else 0
},
{
"count": int(self.sync_pulse2_count_var.get()) if self.sync_pulse2_count_var.get().strip() else 0,
"period": int(self.sync_pulse2_period_var.get()) if self.sync_pulse2_period_var.get().strip() else 0
},
{
"count": int(self.sync_pulse3_count_var.get()) if self.sync_pulse3_count_var.get().strip() else 0,
"period": int(self.sync_pulse3_period_var.get()) if self.sync_pulse3_period_var.get().strip() else 0
},
{
"count": int(self.sync_pulse4_count_var.get()) if self.sync_pulse4_count_var.get().strip() else 0,
"period": int(self.sync_pulse4_period_var.get()) if self.sync_pulse4_period_var.get().strip() else 0
}
]
}
# 添加同步脉冲探测器信号数配置
def safe_int(var, default):
try:
return int(var.get()) if var.get().strip() else default
except ValueError:
return default
config["sync_pulse_signals"] = {
"pulse1": {
"detector1": {"min": safe_int(self.pulse1_det1_min_var, 1), "max": safe_int(self.pulse1_det1_max_var, 10)},
"detector2": {"min": safe_int(self.pulse1_det2_min_var, 1), "max": safe_int(self.pulse1_det2_max_var, 10)},
"detector3": {"min": safe_int(self.pulse1_det3_min_var, 1), "max": safe_int(self.pulse1_det3_max_var, 10)}
},
"pulse2": {
"detector1": {"min": safe_int(self.pulse2_det1_min_var, 1), "max": safe_int(self.pulse2_det1_max_var, 10)},
"detector2": {"min": safe_int(self.pulse2_det2_min_var, 1), "max": safe_int(self.pulse2_det2_max_var, 10)},
"detector3": {"min": safe_int(self.pulse2_det3_min_var, 1), "max": safe_int(self.pulse2_det3_max_var, 10)}
},
"pulse3": {
"detector1": {"min": safe_int(self.pulse3_det1_min_var, 1), "max": safe_int(self.pulse3_det1_max_var, 10)},
"detector2": {"min": safe_int(self.pulse3_det2_min_var, 1), "max": safe_int(self.pulse3_det2_max_var, 10)},
"detector3": {"min": safe_int(self.pulse3_det3_min_var, 1), "max": safe_int(self.pulse3_det3_max_var, 10)}
},
"pulse4": {
"detector1": {"min": safe_int(self.pulse4_det1_min_var, 1), "max": safe_int(self.pulse4_det1_max_var, 10)},
"detector2": {"min": safe_int(self.pulse4_det2_min_var, 1), "max": safe_int(self.pulse4_det2_max_var, 10)},
"detector3": {"min": safe_int(self.pulse4_det3_min_var, 1), "max": safe_int(self.pulse4_det3_max_var, 10)}
}
}
# 确保每个探测器配置都包含name键
for detector_name, detector_config in self.detector_configs.items():
detector_config['name'] = detector_name
return config, self.detector_configs
def set_config(self, config, detector_configs=None):
"""设置配置"""
# 设置基本配置
if "num_events" in config:
self.num_events_var.set(config["num_events"])
if "event_generation_mode" in config:
self.generation_mode_var.set(config["event_generation_mode"])
if "packing_mode" in config:
self.packing_mode_var.set(config["packing_mode"])
if "output_format" in config:
self._set_output_format(config["output_format"])
if "output_file" in config:
self.output_file_var.set(config["output_file"])
# 设置能量转换参数
if "energy_conversion" in config:
energy_conv = config["energy_conversion"]
if "K" in energy_conv:
self.energy_K_var.set(energy_conv["K"])
if "B" in energy_conv:
self.energy_B_var.set(energy_conv["B"])
# 设置同步脉冲探测器信号数配置
if "sync_pulse_signals" in config:
sync_signals = config["sync_pulse_signals"]
# Pulse 1
if "pulse1" in sync_signals:
p1 = sync_signals["pulse1"]
if "detector1" in p1:
self.pulse1_det1_min_var.set(str(p1["detector1"].get("min", 1)))
self.pulse1_det1_max_var.set(str(p1["detector1"].get("max", 10)))
if "detector2" in p1:
self.pulse1_det2_min_var.set(str(p1["detector2"].get("min", 1)))
self.pulse1_det2_max_var.set(str(p1["detector2"].get("max", 10)))
if "detector3" in p1:
self.pulse1_det3_min_var.set(str(p1["detector3"].get("min", 1)))
self.pulse1_det3_max_var.set(str(p1["detector3"].get("max", 10)))
# Pulse 2
if "pulse2" in sync_signals:
p2 = sync_signals["pulse2"]
if "detector1" in p2:
self.pulse2_det1_min_var.set(str(p2["detector1"].get("min", 1)))
self.pulse2_det1_max_var.set(str(p2["detector1"].get("max", 10)))
if "detector2" in p2:
self.pulse2_det2_min_var.set(str(p2["detector2"].get("min", 1)))
self.pulse2_det2_max_var.set(str(p2["detector2"].get("max", 10)))
if "detector3" in p2:
self.pulse2_det3_min_var.set(str(p2["detector3"].get("min", 1)))
self.pulse2_det3_max_var.set(str(p2["detector3"].get("max", 10)))
# Pulse 3
if "pulse3" in sync_signals:
p3 = sync_signals["pulse3"]
if "detector1" in p3:
self.pulse3_det1_min_var.set(str(p3["detector1"].get("min", 1)))
self.pulse3_det1_max_var.set(str(p3["detector1"].get("max", 10)))
if "detector2" in p3:
self.pulse3_det2_min_var.set(str(p3["detector2"].get("min", 1)))
self.pulse3_det2_max_var.set(str(p3["detector2"].get("max", 10)))
if "detector3" in p3:
self.pulse3_det3_min_var.set(str(p3["detector3"].get("min", 1)))
self.pulse3_det3_max_var.set(str(p3["detector3"].get("max", 10)))
# Pulse 4
if "pulse4" in sync_signals:
p4 = sync_signals["pulse4"]
if "detector1" in p4:
self.pulse4_det1_min_var.set(str(p4["detector1"].get("min", 1)))
self.pulse4_det1_max_var.set(str(p4["detector1"].get("max", 10)))
if "detector2" in p4:
self.pulse4_det2_min_var.set(str(p4["detector2"].get("min", 1)))
self.pulse4_det2_max_var.set(str(p4["detector2"].get("max", 10)))
if "detector3" in p4:
self.pulse4_det3_min_var.set(str(p4["detector3"].get("min", 1)))
self.pulse4_det3_max_var.set(str(p4["detector3"].get("max", 10)))
# 设置探测器配置
if detector_configs and isinstance(detector_configs, dict):
for detector, det_config in detector_configs.items():
if detector in self.detector_configs:
# 清理配置,只保留必要的参数
cleaned_config = self._clean_detector_config(det_config)
self.detector_configs[detector] = cleaned_config
# 更新探测器配置显示
self.update_config_display()
def _clean_detector_config(self, det_config):
"""清理探测器配置,只保留必要的参数"""
cleaned = {
"sample_space_size": det_config.get("sample_space_size", 5000),
"allow_replacement": det_config.get("allow_replacement", True),
"energy_distribution": {},
"timestamp_distribution": {}
}
# 清理能量分布配置
energy_dist = det_config.get("energy_distribution", {})
energy_type = energy_dist.get("type", "normal")
cleaned["energy_distribution"]["type"] = energy_type
if energy_type == "normal":
cleaned["energy_distribution"]["mean"] = energy_dist.get("mean", 1000.0)
cleaned["energy_distribution"]["std"] = energy_dist.get("std", 200.0)
elif energy_type == "uniform":
cleaned["energy_distribution"]["low"] = energy_dist.get("low", 0.0)
cleaned["energy_distribution"]["high"] = energy_dist.get("high", 2000.0)
elif energy_type == "exponential":
cleaned["energy_distribution"]["scale"] = energy_dist.get("scale", 50.0)
cleaned["energy_distribution"]["loc"] = energy_dist.get("loc", 0.0)
elif energy_type == "gamma":
cleaned["energy_distribution"]["shape"] = energy_dist.get("shape", 2.0)
cleaned["energy_distribution"]["scale"] = energy_dist.get("scale", 50.0)
elif energy_type == "poisson":
cleaned["energy_distribution"]["lam"] = energy_dist.get("lam", 1000.0)
elif energy_type == "lognormal":
cleaned["energy_distribution"]["mean"] = energy_dist.get("mean", 6.0)
cleaned["energy_distribution"]["sigma"] = energy_dist.get("sigma", 0.5)
elif energy_type == "constant":
cleaned["energy_distribution"]["value"] = energy_dist.get("value", 1000.0)
# 清理时间戳分布配置
timestamp_dist = det_config.get("timestamp_distribution", {})
timestamp_type = timestamp_dist.get("type", "exponential")
cleaned["timestamp_distribution"]["type"] = timestamp_type
if timestamp_type == "normal":
cleaned["timestamp_distribution"]["mean"] = timestamp_dist.get("mean", 1000.0)
cleaned["timestamp_distribution"]["std"] = timestamp_dist.get("std", 200.0)
elif timestamp_type == "uniform":
cleaned["timestamp_distribution"]["low"] = timestamp_dist.get("low", 0.0)
cleaned["timestamp_distribution"]["high"] = timestamp_dist.get("high", 2000.0)
elif timestamp_type == "exponential":
cleaned["timestamp_distribution"]["scale"] = timestamp_dist.get("scale", 50.0)
cleaned["timestamp_distribution"]["loc"] = timestamp_dist.get("loc", 0.0)
elif timestamp_type == "gamma":
cleaned["timestamp_distribution"]["shape"] = timestamp_dist.get("shape", 2.0)
cleaned["timestamp_distribution"]["scale"] = timestamp_dist.get("scale", 50.0)
elif timestamp_type == "poisson":
cleaned["timestamp_distribution"]["lam"] = timestamp_dist.get("lam", 1000.0)
elif timestamp_type == "lognormal":
cleaned["timestamp_distribution"]["mean"] = timestamp_dist.get("mean", 6.0)
cleaned["timestamp_distribution"]["sigma"] = timestamp_dist.get("sigma", 0.5)
return cleaned
def _get_output_format(self):
"""获取输出格式"""
formats = []
if self.bin_var.get():
formats.append("binary")
if self.txt_var.get():
formats.append("text")
if self.debug_var.get():
formats.append("debug")
if not formats:
return "binary"
if len(formats) == 3:
return "all"
return formats[0]
def _set_output_format(self, format_str):
"""设置输出格式"""
if format_str == "all":
self.bin_var.set(True)
self.txt_var.set(True)
self.debug_var.set(True)
elif format_str == "binary":
self.bin_var.set(True)
self.txt_var.set(False)
self.debug_var.set(False)
elif format_str == "text":
self.bin_var.set(False)
self.txt_var.set(True)
self.debug_var.set(False)
elif format_str == "debug":
self.bin_var.set(False)
self.txt_var.set(False)
self.debug_var.set(True)