#!/usr/bin/env python3 import argparse import yaml from pathlib import Path from datetime import datetime def print_separator(char='-', length=70): print(char * length) def format_value(value, suffix=''): if isinstance(value, float): return f"{value:.3f}{suffix}" return f"{value}{suffix}" def display_results(yaml_file: Path): with open(yaml_file, 'r') as f: data = yaml.safe_load(f) metadata = data['metadata'] results = data['test_results'] print("\n" + "=" * 70) print(f" AUDIO TEST RESULTS") print("=" * 70) print("\nšŸ“‹ Test Metadata:") print_separator() print(f" Test ID: {metadata['test_id']}") print(f" Timestamp: {metadata['timestamp']}") print(f" PCB Version: {metadata['pcb_version']}") print(f" PCB Revision: {metadata['pcb_revision']}") print(f" Software Version: {metadata['software_version']}") if metadata.get('notes'): print(f" Notes: {metadata['notes']}") if 'latency_test' in data: latency = data['latency_test'] print("\nšŸŽÆ Latency Test (Chirp):") print_separator() if 'error' in latency: print(f" Error: {latency['error']}") else: print(f" Average: {latency['avg']:.3f} ms") print(f" Min: {latency['min']:.3f} ms") print(f" Max: {latency['max']:.3f} ms") print(f" Std Dev: {latency['std']:.4f} ms") print("\nšŸ“Š Frequency Sweep Results:") print_separator() header = f"{'Freq (Hz)':<12} {'THD CH1 (%)':<13} {'THD CH2 (%)':<13} {'SNR CH1 (dB)':<14} {'SNR CH2 (dB)':<14}" print(header) print(f"{'':12} {'(Loopback)':<13} {'(DUT)':<13} {'(Loopback)':<14} {'(DUT)':<14}") print_separator() for result in results: if 'error' in result: print(f"{result['frequency_hz']:<12} ERROR: {result['error']}") else: freq = result['frequency_hz'] thd_ch1 = format_value(result.get('thd_ch1_loopback_percent', result.get('thd_input_percent', 0))) thd_ch2 = format_value(result.get('thd_ch2_dut_percent', result.get('thd_output_percent', 0))) snr_ch1 = format_value(result.get('snr_ch1_loopback_db', result.get('snr_input_db', 0))) snr_ch2 = format_value(result.get('snr_ch2_dut_db', result.get('snr_output_db', 0))) print(f"{freq:<12} {thd_ch1:<13} {thd_ch2:<13} {snr_ch1:<14} {snr_ch2:<14}") print_separator() valid_results = [r for r in results if 'error' not in r] if valid_results: avg_thd_ch1 = sum(r.get('thd_ch1_loopback_percent', r.get('thd_input_percent', 0)) for r in valid_results) / len(valid_results) avg_thd_ch2 = sum(r.get('thd_ch2_dut_percent', r.get('thd_output_percent', 0)) for r in valid_results) / len(valid_results) avg_snr_ch1 = sum(r.get('snr_ch1_loopback_db', r.get('snr_input_db', 0)) for r in valid_results) / len(valid_results) avg_snr_ch2 = sum(r.get('snr_ch2_dut_db', r.get('snr_output_db', 0)) for r in valid_results) / len(valid_results) print("\nšŸ“ˆ Average Values:") print_separator() print(f" THD CH1 (Loopback): {avg_thd_ch1:.3f} %") print(f" THD CH2 (DUT): {avg_thd_ch2:.3f} %") print(f" SNR CH1 (Loopback): {avg_snr_ch1:.2f} dB") print(f" SNR CH2 (DUT): {avg_snr_ch2:.2f} dB") print("\n" + "=" * 70 + "\n") def list_all_results(results_dir: Path): yaml_files = sorted(results_dir.rglob("*_results.yaml")) if not yaml_files: print("No test results found.") return print("\n" + "=" * 70) print(" AVAILABLE TEST RESULTS") print("=" * 70 + "\n") for yaml_file in yaml_files: try: with open(yaml_file, 'r') as f: data = yaml.safe_load(f) metadata = data['metadata'] timestamp = datetime.fromisoformat(metadata['timestamp']) print(f"šŸ“„ {yaml_file.name}") print(f" Date: {timestamp.strftime('%Y-%m-%d %H:%M:%S')}") print(f" PCB: {metadata['pcb_version']} Rev {metadata['pcb_revision']}") print(f" SW: {metadata['software_version']}") if metadata.get('notes'): print(f" Note: {metadata['notes']}") print() except Exception as e: print(f"āš ļø {yaml_file.name} (corrupted - skipping)") print() def main(): parser = argparse.ArgumentParser(description='View PCB test results') parser.add_argument('file', nargs='?', help='YAML results file to view') parser.add_argument('--list', action='store_true', help='List all available test results') parser.add_argument('--results-dir', default='test_results', help='Directory containing results') args = parser.parse_args() results_dir = Path(args.results_dir) if args.list or not args.file: list_all_results(results_dir) else: yaml_file = Path(args.file) if not yaml_file.exists(): yaml_file = results_dir / args.file if not yaml_file.exists(): print(f"Error: File not found: {yaml_file}") return 1 display_results(yaml_file) if __name__ == '__main__': main()