"""
CORRECT OFFSET CALIBRATION SYSTEM
Only offset correction, no gain multiplication
"""

import numpy as np

print("="*70)
print("🔧 CORRECT OFFSET-ONLY CALIBRATION")
print("Problem: Used Gain+Offset model, but only Offset is needed")
print("="*70)

# Real data from thermal test at 20°C
sensor_currents_at_20C = {
    1: 10.96,  # mA
    2: 10.68,
    3: 10.52,
    4: 9.30,
}

print("\n📊 MEASURED CURRENTS AT 20°C:")
print("Sensor | Current (mA) | Deviation from 10.0mA")
print("-"*45)

reference_current = 10.00  # mA

for sensor_id, current in sensor_currents_at_20C.items():
    deviation = current - reference_current
    print(f"#{sensor_id:2}     | {current:10.2f} mA | {deviation:7.2f} mA")

# Calculate OFFSET ONLY corrections
print("\n🎯 CALCULATING OFFSET-ONLY CORRECTIONS:")
print("-"*45)

offset_corrections = {}
for sensor_id, current in sensor_currents_at_20C.items():
    # OFFSET = reference - measured (to ADD to measurement)
    offset = reference_current - current
    offset_corrections[sensor_id] = offset
    
    print(f"Sensor #{sensor_id}:")
    print(f"  Measured: {current:.2f} mA")
    print(f"  Offset: {offset:+.3f} mA")
    print(f"  Corrected = Measured + ({offset:+.3f})")

# Test the correction
print("\n✅ VERIFYING OFFSET CORRECTION:")
print("-"*45)

max_error_after = 0
for sensor_id, current in sensor_currents_at_20C.items():
    corrected = current + offset_corrections[sensor_id]
    error = abs(corrected - reference_current)
    max_error_after = max(max_error_after, error)
    
    print(f"Sensor #{sensor_id}:")
    print(f"  Before: {current:.3f} mA")
    print(f"  After:  {corrected:.3f} mA")
    print(f"  Error:  {error:.3f} mA")

print(f"\n📈 Maximum error after offset correction: {max_error_after:.3f} mA")
print(f"✅ {'PASS' if max_error_after < 0.1 else 'FAIL'}")

# Apply to field readings
print("\n" + "="*70)
print("📡 APPLYING TO FIELD READINGS")
print("="*70)

# Simulated field readings (from previous test)
field_readings_at_1000V_m = {
    1: 910.7,  # V/m (what sensor reads when actual field is 1000 V/m)
    2: 939.0,
    3: 951.5,
    4: 1077.6,
}

print("\n📊 Original field readings (at 1000 V/m actual):")
print("Sensor | Reading (V/m) | Error (%)")
print("-"*45)

for sensor_id, reading in field_readings_at_1000V_m.items():
    error = ((reading - 1000) / 1000) * 100
    print(f"#{sensor_id:2}     | {reading:11.1f} | {error:7.1f}%")

# Calculate field calibration factors (DIFFERENT from current calibration!)
print("\n🎯 FIELD CALIBRATION FACTORS:")
print("These are GAIN factors for FIELD readings, not current!")
print("-"*45)

field_cal_factors = {}
for sensor_id, reading in field_readings_at_1000V_m.items():
    # For FIELD readings: we need gain correction
    # Because field reading error comes from sensor sensitivity, not current
    factor = 1000.0 / reading
    field_cal_factors[sensor_id] = factor
    
    print(f"Sensor #{sensor_id}:")
    print(f"  Reads: {reading:.1f} V/m at 1000 V/m actual")
    print(f"  Field Factor: {factor:.6f}")
    print(f"  Equation: Actual_Field = {factor:.4f} × Measured_Field")

# Generate final calibration code
print("\n" + "="*70)
print("💻 GENERATING FINAL CALIBRATION CODE")
print("="*70)

code = """
# ============================================================================
# ELECTRIC FIELD SENSOR CALIBRATION - FINAL CORRECTED VERSION
# Snow Dust Project - Phase 2.5
# Generated: 2026-01-30
# ============================================================================

class SensorCalibration:
    \"\"\"Complete sensor calibration system\"\"\"
    
    # ================= CURRENT OFFSET CORRECTIONS =================
    # Measured at 20°C, reference current = 10.00 mA
    # Apply to POWER MEASUREMENTS only
    CURRENT_OFFSETS = {
        1: -0.960,   # mA (add this to measured current)
        2: -0.680,
        3: -0.520,
        4: +0.700,
    }
    
    # ================= FIELD GAIN CORRECTIONS =====================
    # Measured at known 1000 V/m field
    # Apply to FIELD MEASUREMENTS only
    FIELD_FACTORS = {
        1: 1.0981,   # Multiply measured field by this
        2: 1.0650,
        3: 1.0510,
        4: 0.9280,
    }
    
    # ================= TEMPERATURE COMPENSATION ===================
    # Temperature coefficient: 0.10 %/°C for all sensors
    TEMP_COEFFICIENT = 0.0010  # per °C (0.10%/°C)
    
    @staticmethod
    def calibrate_current(sensor_id, measured_current, temperature=20.0):
        \"\"\"Calibrate current measurement with offset and temperature\"\"\"
        # 1. Apply offset correction
        offset = SensorCalibration.CURRENT_OFFSETS.get(sensor_id, 0.0)
        calibrated = measured_current + offset
        
        # 2. Apply temperature compensation if not at 20°C
        if temperature != 20.0:
            temp_correction = 1.0 + (SensorCalibration.TEMP_COEFFICIENT * (temperature - 20.0))
            calibrated *= temp_correction
        
        return calibrated
    
    @staticmethod
    def calibrate_field(sensor_id, measured_field, temperature=20.0):
        \"\"\"Calibrate field measurement with gain and temperature\"\"\"
        # 1. Apply field gain correction
        factor = SensorCalibration.FIELD_FACTORS.get(sensor_id, 1.0)
        calibrated = measured_field * factor
        
        # 2. Apply temperature compensation
        if temperature != 20.0:
            # Field sensors typically have negative TC
            field_temp_correction = 1.0 - (0.0005 * (temperature - 20.0))
            calibrated *= field_temp_correction
        
        return calibrated
    
    @staticmethod
    def calibrate_all(sensor_id, measured_current, measured_field, temperature=20.0):
        \"\"\"Complete calibration of both current and field\"\"\"
        cal_current = SensorCalibration.calibrate_current(sensor_id, measured_current, temperature)
        cal_field = SensorCalibration.calibrate_field(sensor_id, measured_field, temperature)
        
        return {
            'calibrated_current': cal_current,
            'calibrated_field': cal_field,
            'sensor_id': sensor_id,
            'temperature': temperature,
            'calibration_applied': True
        }

# ============================================================================
# EEPROM CONFIGURATION FOR EMBEDDED SYSTEM
# ============================================================================

"""
# EEPROM structure
code += """# EEPROM address map
EEPROM_CONFIG = {
    'CURRENT_OFFSETS_START': 0x00,   # 16 bytes (4 floats)
    'FIELD_FACTORS_START':   0x10,   # 16 bytes (4 floats)
    'CALIBRATION_DATE':      0x20,   # 8 bytes (timestamp)
    'SERIAL_NUMBERS':        0x28,   # 16 bytes (4 ints)
}

def load_calibration_from_eeprom():
    \"\"\"Load calibration parameters from EEPROM at boot\"\"\"
    import machine  # For MicroPython
    import ustruct
    
    i2c = machine.I2C(0, scl=machine.Pin(22), sda=machine.Pin(21))
    
    # Read current offsets
    i2c.writeto(0x50, bytes([EEPROM_CONFIG['CURRENT_OFFSETS_START']]))
    data = i2c.readfrom(0x50, 16)
    current_offsets = ustruct.unpack('4f', data)
    
    # Read field factors
    i2c.writeto(0x50, bytes([EEPROM_CONFIG['FIELD_FACTORS_START']]))
    data = i2c.readfrom(0x50, 16)
    field_factors = ustruct.unpack('4f', data)
    
    return current_offsets, field_factors

"""

print(code)

# Save to file
with open("final_sensor_calibration.py", "w") as f:
    f.write(code)

print("\n✅ FINAL CALIBRATION CODE SAVED TO: final_sensor_calibration.py")

print("\n" + "="*70)
print("🎯 CALIBRATION STRATEGY SUMMARY")
print("="*70)

print("\n1. 🔧 CURRENT MEASUREMENTS:")
print("   • Only OFFSET correction (no gain)")
print("   • Add fixed offset to each sensor")
print("   • Temperature compensation: 0.10%/°C")

print("\n2. 📡 FIELD MEASUREMENTS:")
print("   • Only GAIN correction (different for each sensor)")
print("   • Multiply by field factor")
print("   • Temperature compensation: -0.05%/°C")

print("\n3. 💾 EMBEDDED SYSTEM:")
print("   • Store offsets/factors in EEPROM")
print("   • Load at boot time")
print("   • Apply in real-time measurements")

print("\n" + "="*70)
print("🚀 READY FOR FIELD DEPLOYMENT AFTER VERIFICATION")
print("="*70)
