Adds artifact test.

This commit is contained in:
Pbopbo
2026-03-18 10:41:46 +01:00
parent 80f7522159
commit 39bcd072c0
9 changed files with 836 additions and 21 deletions

173
test_artifact_detection.py Executable file
View File

@@ -0,0 +1,173 @@
#!/usr/bin/env python3
import argparse
import yaml
from datetime import datetime
from pathlib import Path
import sys
import json
sys.path.insert(0, str(Path(__file__).parent))
from src.audio_tests import run_artifact_detection_test
def main():
parser = argparse.ArgumentParser(description='Run artifact detection test on audio loopback and radio path')
parser.add_argument('--serial-number', required=True, help='Serial number (e.g., SN001234)')
parser.add_argument('--software-version', required=True, help='Software version (git commit hash)')
parser.add_argument('--comment', default='', help='Comments about this test')
parser.add_argument('--config', default='config.yaml', help='Path to config file')
parser.add_argument('--duration', type=float, help='Override recording duration in seconds (default from config)')
parser.add_argument('--frequency', type=float, help='Override test frequency in Hz (default from config)')
parser.add_argument('--signal-type', choices=['sine', 'chirp', 'silent'], default='sine',
help='Signal type: sine (single frequency), chirp (frequency sweep), or silent (no signal)')
args = parser.parse_args()
with open(args.config, 'r') as f:
config = yaml.safe_load(f)
if args.duration:
config['artifact_detection']['duration'] = args.duration
if args.frequency:
config['artifact_detection']['test_frequency'] = args.frequency
config['artifact_detection']['signal_type'] = args.signal_type
timestamp = datetime.now()
test_id = timestamp.strftime('%Y%m%d_%H%M%S')
results_dir = Path(config['output']['results_dir'])
results_dir.mkdir(exist_ok=True)
test_output_dir = results_dir / f"{test_id}_artifact_detection"
test_output_dir.mkdir(exist_ok=True)
save_plots = config['output'].get('save_plots', False)
print("=" * 70)
print("ARTIFACT DETECTION TEST")
print("=" * 70)
print(f"Test ID: {test_id}")
print(f"Serial Number: {args.serial_number}")
print(f"Software: {args.software_version}")
if args.comment:
print(f"Comment: {args.comment}")
print(f"Duration: {config['artifact_detection']['duration']} seconds")
signal_type = config['artifact_detection'].get('signal_type', 'sine')
if signal_type == 'sine':
print(f"Signal Type: Sine wave @ {config['artifact_detection']['test_frequency']} Hz")
elif signal_type == 'chirp':
print(f"Signal Type: Chirp (100 Hz - 8000 Hz)")
else:
print(f"Signal Type: Silent (no playback - noise floor measurement)")
if save_plots:
print(f"Plots will be saved to: {test_output_dir}")
print("-" * 70)
print("\nDetection Algorithms:")
for detector_name, detector_settings in config['artifact_detection']['detectors'].items():
status = "ENABLED" if detector_settings.get('enabled', False) else "DISABLED"
print(f" - {detector_name}: {status}")
if detector_settings.get('enabled', False):
for param, value in detector_settings.items():
if param != 'enabled':
print(f" {param}: {value}")
print("\n" + "=" * 70)
signal_type = config['artifact_detection'].get('signal_type', 'sine')
if signal_type == 'sine':
freq = config['artifact_detection']['test_frequency']
print(f"STARTING TEST - Playing {freq}Hz sine wave and recording both channels...")
elif signal_type == 'chirp':
print("STARTING TEST - Playing chirp signal (100-8000Hz) and recording both channels...")
else:
print("STARTING TEST - Recording silence (no playback)...")
print("=" * 70)
print("\nChannel 1: Loopback path (direct audio interface loopback)")
print("Channel 2: DUT/Radio path (through beacon and radio transmission)")
print()
try:
result = run_artifact_detection_test(config, save_plots=save_plots, output_dir=test_output_dir)
print("\n" + "=" * 70)
print("TEST COMPLETE - RESULTS")
print("=" * 70)
signal_type = result.get('signal_type', 'sine')
if signal_type == 'chirp':
print(f"\n📊 Signal: Chirp {result['chirp_f0_hz']} Hz → {result['chirp_f1_hz']} Hz")
elif signal_type == 'silent':
print(f"\n📊 Signal: Silent (no playback - noise floor measurement)")
else:
print(f"\n📊 Test Frequency: {result['test_frequency_hz']} Hz")
print(f"⏱️ Duration: {result['duration_sec']} seconds")
print("\n🔊 CHANNEL 1 (LOOPBACK PATH):")
print(f" Total Artifacts: {result['channel_1_loopback']['total_artifacts']}")
print(f" Artifact Rate: {result['channel_1_loopback']['artifact_rate_per_minute']:.2f} per minute")
if result['channel_1_loopback']['artifacts_by_type']:
print(" By Type:")
for artifact_type, count in result['channel_1_loopback']['artifacts_by_type'].items():
print(f" - {artifact_type}: {count}")
print("\n📻 CHANNEL 2 (DUT/RADIO PATH):")
print(f" Total Artifacts: {result['channel_2_dut']['total_artifacts']}")
print(f" Artifact Rate: {result['channel_2_dut']['artifact_rate_per_minute']:.2f} per minute")
if result['channel_2_dut']['artifacts_by_type']:
print(" By Type:")
for artifact_type, count in result['channel_2_dut']['artifacts_by_type'].items():
print(f" - {artifact_type}: {count}")
ch1_count = result['channel_1_loopback']['total_artifacts']
ch2_count = result['channel_2_dut']['total_artifacts']
if ch2_count > ch1_count:
delta = ch2_count - ch1_count
print(f"\n⚠️ DEGRADATION DETECTED: {delta} more artifacts in radio path vs loopback")
elif ch1_count == ch2_count == 0:
print("\n✅ EXCELLENT: No artifacts detected in either path!")
else:
print(f"\n Loopback baseline: {ch1_count} artifacts")
except Exception as e:
print(f"\n❌ ERROR: {e}")
import traceback
traceback.print_exc()
result = {
'error': str(e),
'test_frequency_hz': config['artifact_detection']['test_frequency'],
'duration_sec': config['artifact_detection']['duration']
}
output_data = {
'metadata': {
'test_id': test_id,
'timestamp': timestamp.isoformat(),
'serial_number': args.serial_number,
'software_version': args.software_version,
'comment': args.comment
},
'artifact_detection_result': result
}
output_file = results_dir / f"{test_id}_artifact_detection_results.yaml"
with open(output_file, 'w') as f:
yaml.dump(output_data, f, default_flow_style=False, sort_keys=False)
json_output_file = results_dir / f"{test_id}_artifact_detection_results.json"
with open(json_output_file, 'w') as f:
json.dump(output_data, f, indent=2)
print("\n" + "=" * 70)
print("✅ Results saved to:")
print(f" YAML: {output_file}")
print(f" JSON: {json_output_file}")
if save_plots:
print(f" Summary plots: {test_output_dir}/")
print(f" Individual anomaly plots: {test_output_dir}/individual_anomalies/")
print("=" * 70)
if __name__ == '__main__':
main()