#!/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)