79 self.
root.title(
"Smart PT Calibration System - Diablo FSW")
80 self.
root.geometry(
"1800x1200")
134 "autonomous_accuracy": 0.0,
135 "human_input_requests": 0,
166 """Setup control panel"""
167 control_frame = ttk.LabelFrame(
168 parent, text=
"Smart Calibration Controls", padding=10
170 control_frame.grid(row=0, column=0, columnspan=3, sticky=
"ew", pady=(0, 10))
173 conn_frame = ttk.Frame(control_frame)
174 conn_frame.pack(fill=tk.X, pady=(0, 10))
176 ttk.Label(conn_frame, text=
"Serial Port:").pack(side=tk.LEFT)
178 port_combo = ttk.Combobox(conn_frame, textvariable=self.
port_var, width=15)
180 port_combo.pack(side=tk.LEFT, padx=(5, 10))
188 smart_frame = ttk.Frame(control_frame)
189 smart_frame.pack(fill=tk.X, pady=(0, 10))
193 text=
"Enable Autonomous Mode",
201 text=
"Start Learning",
205 self.
learn_btn.pack(side=tk.LEFT, padx=(0, 10))
209 text=
"Validate Prediction",
217 text=
"Save Learning State",
224 """Setup real-time data display"""
225 data_frame = ttk.LabelFrame(parent, text=
"Real-Time Sensor Data", padding=10)
226 data_frame.grid(row=1, column=0, sticky=
"nsew", padx=(0, 5), pady=(0, 5))
238 data_frame, columns=columns, show=
"headings", height=12
243 self.
data_tree.column(col, width=120, anchor=
"center")
246 scrollbar = ttk.Scrollbar(
247 data_frame, orient=tk.VERTICAL, command=self.
data_tree.yview
251 self.
data_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=
True)
252 scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
267 for i, location
in enumerate(pt_locations):
271 values=(f
"PT {i}", location,
"0.000",
"0.000",
"LOW",
"Offline"),
275 """Setup human input panel"""
276 input_frame = ttk.LabelFrame(parent, text=
"Human Input Interface", padding=10)
277 input_frame.grid(row=1, column=1, sticky=
"nsew", padx=(5, 5), pady=(0, 5))
280 ttk.Label(input_frame, text=
"Pending Human Input Requests:").pack(anchor=
"w")
283 input_frame, height=8, bg=
"#3b3b3b", fg=
"white"
288 input_controls_frame = ttk.Frame(input_frame)
289 input_controls_frame.pack(fill=tk.X)
291 ttk.Label(input_controls_frame, text=
"Selected Sensor:").pack(anchor=
"w")
293 sensor_combo = ttk.Combobox(
296 sensor_combo[
"values"] = [f
"PT {i}" for i
in range(9)]
297 sensor_combo.pack(fill=tk.X, pady=(0, 5))
299 ttk.Label(input_controls_frame, text=
"Reference Pressure (kPa):").pack(
303 ref_entry = ttk.Entry(input_controls_frame, textvariable=self.
ref_pressure_var)
304 ref_entry.pack(fill=tk.X, pady=(0, 5))
307 input_controls_frame,
308 text=
"Confirm Input",
315 input_controls_frame,
323 progress_frame = ttk.Frame(input_frame)
324 progress_frame.pack(fill=tk.X, pady=(10, 0))
326 ttk.Label(progress_frame, text=
"Learning Progress:").pack(anchor=
"w")
333 progress_frame_sensor = ttk.Frame(progress_frame)
334 progress_frame_sensor.pack(fill=tk.X, pady=2)
336 ttk.Label(progress_frame_sensor, text=f
"PT {i}:", width=8).pack(
341 progress_bar = ttk.Progressbar(
342 progress_frame_sensor,
347 progress_bar.pack(side=tk.LEFT, fill=tk.X, expand=
True, padx=(5, 5))
349 self.
progress_bars[i] = ttk.Label(progress_frame_sensor, text=
"0%", width=6)
353 """Setup real-time plotting area"""
354 plot_frame = ttk.LabelFrame(parent, text=
"Real-Time Monitoring", padding=10)
355 plot_frame.grid(row=1, column=2, sticky=
"nsew", padx=(5, 0), pady=(0, 5))
358 self.
fig = Figure(figsize=(10, 8), dpi=100)
359 self.
fig.patch.set_facecolor(
"#2b2b2b")
367 self.
ax_voltage.set_title(
"Real-Time Voltage Readings", color=
"white")
368 self.
ax_voltage.set_ylabel(
"Voltage (V)", color=
"white")
372 self.
ax_pressure.set_title(
"Real-Time Pressure Readings", color=
"white")
373 self.
ax_pressure.set_ylabel(
"Pressure (kPa)", color=
"white")
377 self.
ax_confidence.set_title(
"Confidence Levels", color=
"white")
385 self.
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=
True)
389 "time": deque(maxlen=1000),
390 "voltages": {i: deque(maxlen=1000)
for i
in range(9)},
391 "pressures": {i: deque(maxlen=1000)
for i
in range(9)},
392 "confidence": {i: deque(maxlen=1000)
for i
in range(9)},
396 """Setup status and statistics panel"""
397 status_frame = ttk.LabelFrame(
398 parent, text=
"System Status & Statistics", padding=10
400 status_frame.grid(row=2, column=0, columnspan=3, sticky=
"ew", pady=(5, 0))
403 status_indicators_frame = ttk.Frame(status_frame)
404 status_indicators_frame.pack(fill=tk.X, pady=(0, 10))
407 ttk.Label(status_indicators_frame, textvariable=self.
status_var).pack(
412 perf_frame = ttk.Frame(status_indicators_frame)
413 perf_frame.pack(side=tk.RIGHT)
421 side=tk.LEFT, padx=(10, 0)
423 ttk.Label(perf_frame, textvariable=self.
latency_var).pack(
424 side=tk.LEFT, padx=(10, 0)
426 ttk.Label(perf_frame, textvariable=self.
accuracy_var).pack(
427 side=tk.LEFT, padx=(10, 0)
429 ttk.Label(perf_frame, textvariable=self.
autonomy_var).pack(
430 side=tk.LEFT, padx=(10, 0)
434 stats_frame = ttk.Frame(status_frame)
435 stats_frame.pack(fill=tk.X)
437 ttk.Label(stats_frame, text=
"Sensor Statistics:").pack(anchor=
"w")
448 stats_frame, columns=stats_columns, show=
"headings", height=4
451 for col
in stats_columns:
453 self.
stats_tree.column(col, width=120, anchor=
"center")
460 "",
"end", values=(f
"PT {i}",
"LOW",
"0",
"0%",
"0%")
464 parent.grid_rowconfigure(1, weight=1)
465 parent.grid_columnconfigure(0, weight=1)
466 parent.grid_columnconfigure(1, weight=1)
467 parent.grid_columnconfigure(2, weight=1)
597 """EXACT copy from working channel_plotter.py"""
626 if len(buffer) < payload_len:
632 next_bytes = buffer[payload_len : payload_len + len(self.
MAGIC)]
633 if next_bytes != self.
MAGIC:
636 if len(buffer) < packet_len:
647 total_time_us = int(total_time_us)
648 failures = int(failures)
649 packet_time_us = int(packet_time_us) & self.
UINT32_MAX
650 count_success =
max(1, count -
min(count, failures))
651 per_sample_default = (
652 max(1, total_time_us // count_success)
if total_time_us > 0
else 1
655 for i
in range(count):
657 ch, ok, raw, sample_time, read_dur, conv_dur = (
663 sample_time = int(sample_time)
675 read_us = 0
if read_dur == self.
UINT32_MAX else int(read_dur)
676 conv_us = 0
if conv_dur == self.
UINT32_MAX else int(conv_dur)
677 per_sample = read_us + conv_us
679 per_sample = per_sample_default
680 per_sample =
max(1, int(per_sample))
688 "sample_time": sample_time,
689 "read_time_dur": read_us,
690 "conv_time_dur": conv_us,
693 "predicted_pressure": 0.0,
694 "confidence_level":
"LOW",
695 "needs_human_input":
True,
701 if len(framework.calibration_points) > 2:
704 predicted_pressure, uncertainty = (
705 framework.predict_pressure_with_uncertainty(
706 measurement[
"filtered_voltage"], env_state
709 measurement[
"predicted_pressure"] = predicted_pressure
710 measurement[
"uncertainty"] = uncertainty
711 measurement[
"needs_human_input"] = (
714 measurement[
"confidence_level"] = framework.get_confidence_level()
717 measurement[
"predicted_pressure"] = (
719 ch, measurement[
"filtered_voltage"]
722 measurement[
"needs_human_input"] =
False
723 measurement[
"confidence_level"] = (
727 measurement[
"needs_human_input"] =
True
728 measurement[
"confidence_level"] =
"LOW"
730 measurements.append(measurement)
732 del buffer[:packet_len]
833 """Predict pressure using covariance mapping from other calibrated PTs"""
841 and len(framework.calibration_points) > max_cal_points
844 max_cal_points = len(framework.calibration_points)
846 if best_ref_pt
is None:
852 predicted_pressure, uncertainty = framework.predict_pressure_with_uncertainty(
859 return predicted_pressure * covariance_factor
862 """Get covariance scaling factor between PTs"""
868 0: {1: 0.95, 2: 0.90, 3: 0.85, 4: 0.80, 5: 0.75, 6: 0.70, 7: 0.65, 8: 0.60},
870 1: {0: 0.95, 2: 0.98, 3: 0.85, 4: 0.80, 5: 0.75, 6: 0.70, 7: 0.65, 8: 0.60},
872 2: {0: 0.90, 1: 0.98, 3: 0.85, 4: 0.80, 5: 0.75, 6: 0.70, 7: 0.65, 8: 0.60},
874 3: {0: 0.85, 1: 0.85, 2: 0.85, 4: 0.95, 5: 0.80, 6: 0.75, 7: 0.70, 8: 0.65},
876 4: {0: 0.80, 1: 0.80, 2: 0.80, 3: 0.95, 5: 0.85, 6: 0.80, 7: 0.75, 8: 0.70},
878 5: {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.80, 4: 0.85, 6: 0.90, 7: 0.85, 8: 0.80},
880 6: {0: 0.70, 1: 0.70, 2: 0.70, 3: 0.75, 4: 0.80, 5: 0.90, 7: 0.95, 8: 0.85},
882 7: {0: 0.65, 1: 0.65, 2: 0.65, 3: 0.70, 4: 0.75, 5: 0.85, 6: 0.95, 8: 0.90},
884 8: {0: 0.60, 1: 0.60, 2: 0.60, 3: 0.65, 4: 0.70, 5: 0.80, 6: 0.85, 7: 0.90},
888 target_pt
in pt_relationships
889 and reference_pt
in pt_relationships[target_pt]
891 return pt_relationships[target_pt][reference_pt]
897 self, sensor_id: int, measurement: Dict
900 Robust human input decision using uncertainty quantification
904 if len(framework.calibration_points) < 3:
908 uncertainty = measurement.get(
"uncertainty", 0.1)
909 predicted_pressure = measurement.get(
"predicted_pressure", 0.0)
912 uncertainty_threshold = 0.05
914 if uncertainty > uncertainty_threshold:
919 predicted_pressure < 0
or predicted_pressure > 1000
924 confidence_level = framework.get_confidence_level()
925 if confidence_level ==
"LOW":
927 elif confidence_level ==
"MEDIUM" and uncertainty > 0.02:
1163 """Update statistics display"""
1165 values = list(self.
stats_tree.item(item)[
"values"])
1166 sensor_id = int(values[0].
split()[1])
1171 if state.autonomous_success_count + state.autonomous_failure_count > 0:
1172 success_rate = state.autonomous_success_count / (
1173 state.autonomous_success_count + state.autonomous_failure_count
1176 values[1] = state.confidence_level.name
1177 values[2] = str(state.human_input_count)
1178 values[3] = f
"{success_rate*100:.1f}%"
1179 values[4] = f
"{state.reliability_score*100:.1f}%"
1298 """Confirm human input"""
1311 voltage=measurement[
"filtered_voltage"],
1312 pressure=reference_pressure,
1314 environmental_state=env_state,
1319 result = framework.add_calibration_point(robust_calibration_point)
1322 calibration_point = {
1323 "voltage": measurement[
"filtered_voltage"],
1324 "pressure": reference_pressure,
1332 state.human_input_count += 1
1334 state.calibration_data_points = len(
1339 if state.human_input_count >= 20:
1340 state.confidence_level = ConfidenceLevel.MAXIMUM
1341 elif state.human_input_count >= 10:
1342 state.confidence_level = ConfidenceLevel.HIGH
1343 elif state.human_input_count >= 5:
1344 state.confidence_level = ConfidenceLevel.MEDIUM
1360 messagebox.showinfo(
1361 "Input Confirmed", f
"Calibration data added for PT {sensor_id}"
1365 messagebox.showerror(
1366 "Invalid Input",
"Please enter valid sensor and pressure values"
1388 """Save learning state to file"""
1389 filename = filedialog.asksaveasfilename(
1390 defaultextension=
".json",
1391 filetypes=[(
"JSON files",
"*.json"), (
"All files",
"*.*")],
1392 title=
"Save Learning State",
1397 "timestamp": datetime.now().isoformat(),
1400 "confidence_level": state.confidence_level.name,
1401 "human_input_count": state.human_input_count,
1402 "autonomous_success_count": state.autonomous_success_count,
1403 "autonomous_failure_count": state.autonomous_failure_count,
1404 "reliability_score": state.reliability_score,
1405 "calibration_data_points": state.calibration_data_points,
1409 "calibration_data": {
1410 str(sensor_id): data_points
1415 with open(filename,
"w")
as f:
1416 json.dump(learning_data, f, indent=2)
1418 messagebox.showinfo(
"Saved", f
"Learning state saved to {filename}")