"""
PHYSICALLY CORRECT CALIBRATION
Temperature drift happens in ELECTRONICS (current), not in FIELD conversion
"""

import numpy as np

print("="*70)
print("🔥 PHYSICALLY CORRECT CALIBRATION MODEL")
print("Temperature drift: ELECTRONICS layer (α), not FIELD layer (β)")
print("="*70)

# Actual measured currents at different temperatures
current_data = {
    1: {  # Sensor 1
        -20: 10.522,  # mA
        -10: 10.631,
        0: 10.741,
        20: 10.960,
        40: 11.179,
    },
    4: {  # Sensor 4
        -20: 8.928,
        -10: 9.021,
        0: 9.114,
        20: 9.300,
        40: 9.486,
    }
}

print("\n📊 ACTUAL CURRENT MEASUREMENTS:")
print("Sensor | Temp | Current (mA) | After offset | % Change from 20°C")
print("-"*65)

offsets = {1: -0.960, 4: +0.700}

for sensor_id in [1, 4]:
    print(f"\n{'='*30}")
    print(f"SENSOR #{sensor_id}")
    print(f"{'='*30}")
    
    for temp in [-20, -10, 0, 20, 40]:
        I_meas = current_data[sensor_id][temp]
        offset = offsets[sensor_id]
        I_corrected_offset = I_meas + offset
        
        # Calculate % change from 20°C
        if temp == 20:
            I_ref = I_corrected_offset
            pct_change = 0.0
        else:
            I_at_20 = current_data[sensor_id][20] + offset
            pct_change = ((I_corrected_offset - I_at_20) / I_at_20) * 100
        
        print(f"{sensor_id:6} | {temp:4}°C | {I_meas:11.3f} | {I_corrected_offset:12.3f} | {pct_change:6.1f}%")

print("\n" + "="*70)
print("🎯 CALCULATING REAL α FROM CURRENT DATA")
print("="*70)

# Calculate α for each sensor from current data
for sensor_id in [1, 4]:
    I_minus20 = current_data[sensor_id][-20] + offsets[sensor_id]
    I_40 = current_data[sensor_id][40] + offsets[sensor_id]
    I_20 = current_data[sensor_id][20] + offsets[sensor_id]
    
    # α = (I_40 - I_-20) / (I_20 × 60)
    alpha = (I_40 - I_minus20) / (I_20 * 60)
    alpha_percent = alpha * 100
    
    print(f"\nSensor #{sensor_id}:")
    print(f"  I(-20°C) = {I_minus20:.3f} mA")
    print(f"  I(20°C)  = {I_20:.3f} mA")
    print(f"  I(40°C)  = {I_40:.3f} mA")
    print(f"  α = ({I_40:.3f} - {I_minus20:.3f}) / ({I_20:.3f} × 60)")
    print(f"  α = {alpha:.6f} (factor/°C)")
    print(f"  α = {alpha_percent:.3f} %/°C")

print("\n" + "="*70)
print("💻 CORRECT EMBEDDED CALIBRATION CODE")
print("="*70)

correct_code = """// ============================================================================
// ELECTRIC FIELD CALIBRATION - PHYSICALLY CORRECT MODEL
// Temperature compensation in ELECTRONICS layer only
// ============================================================================

#include <stdint.h>
#include <math.h>

// Array indices: 0=Sensor1, 1=Sensor2, 2=Sensor3, 3=Sensor4

// Current offsets (mA) - measured at 20°C
const float CURRENT_OFFSETS[4] = {-0.960f, -0.680f, -0.520f, +0.700f};

// PER-SENSOR temperature coefficients α (current drift)
// Positive: Current INCREASES with temperature
const float ALPHA_COEFFICIENTS[4] = {
    0.00100f,  // Sensor 1: +0.10%/°C (from actual measurements)
    0.00100f,  // Sensor 2: estimated
    0.00100f,  // Sensor 3: estimated  
    0.00100f,  // Sensor 4: estimated
};

// Field gains at 20°C (NO temperature compensation here!)
const float FIELD_GAINS[4] = {1.0981f, 1.0650f, 1.0510f, 0.9280f};

// Physical conversion constant (NO temperature dependence!)
const float K_SENSOR = 90.91f;  // V/m per mA

// ================= CORRECT CALIBRATION FUNCTIONS ====================

/**
 * @brief Calibrate current with temperature compensation
 * @param sensor_idx Sensor index (0-3)
 * @param measured_current Raw current in mA
 * @param temperature Temperature in °C
 * @return Temperature-compensated current in mA
 */
float calibrate_current_with_temperature(uint8_t sensor_idx, float measured_current, float temperature) {
    // I_corr = (I_meas + offset) × (1 + α×(T-20))
    float offset = CURRENT_OFFSETS[sensor_idx];
    float alpha = ALPHA_COEFFICIENTS[sensor_idx];
    
    float corrected = measured_current + offset;
    
    if (temperature != 20.0f) {
        float temp_factor = 1.0f + (alpha * (temperature - 20.0f));
        corrected *= temp_factor;
    }
    
    return corrected;
}

/**
 * @brief Complete calibration pipeline (PHYSICALLY CORRECT)
 * @param sensor_idx Sensor index (0-3)
 * @param measured_current Raw current in mA
 * @param temperature Temperature in °C
 * @return Calibrated electric field in V/m
 */
float calibrate_electric_field(uint8_t sensor_idx, float measured_current, float temperature) {
    // PHYSICAL ORDER (CORRECT):
    // 1. Correct current with offset and temperature (ELECTRONICS)
    float I_corr = calibrate_current_with_temperature(sensor_idx, measured_current, temperature);
    
    // 2. Convert to field using physical constant (NO temperature here!)
    float E_raw = I_corr * K_SENSOR;
    
    // 3. Apply field gain (NO temperature compensation here!)
    float gain = FIELD_GAINS[sensor_idx];
    float E_calibrated = E_raw * gain;
    
    return E_calibrated;
}

// ============================================================================
// SIMPLIFIED INTERFACE (for field use)
// ============================================================================

/**
 * @brief Simple calibration function for field measurements
 * @param sensor_id Sensor number (1-4)
 * @param raw_current Raw current measurement in mA
 * @param temperature Temperature in °C
 * @return Calibrated electric field in V/m
 */
float get_calibrated_field(uint8_t sensor_id, float raw_current, float temperature) {
    // Convert 1-based sensor ID to 0-based index
    uint8_t sensor_idx = sensor_id - 1;
    
    // Apply complete calibration
    return calibrate_electric_field(sensor_idx, raw_current, temperature);
}

/*
// ============================================================================
// USAGE EXAMPLE
// ============================================================================

int main() {
    // Example: Sensor 1 reading 10.522 mA at -20°C
    uint8_t sensor_id = 1;
    float measured_current = 10.522f;
    float temperature = -20.0f;
    
    float field = get_calibrated_field(sensor_id, measured_current, temperature);
    
    printf("Sensor %d at %.1f°C: %.3f mA → %.1f V/m\\n",
           sensor_id, temperature, measured_current, field);
    
    return 0;
}
*/
"""

print(correct_code)

# Save the correct code
with open("physically_correct_calibration.c", "w") as f:
    f.write(correct_code)

print("\n✅ Physically correct C code saved: physically_correct_calibration.c")

print("\n" + "="*70)
print("🧪 VERIFICATION WITH PHYSICALLY CORRECT MODEL")
print("="*70)

# Test the physically correct model
class PhysicallyCorrectCalibrator:
    def __init__(self):
        self.offsets = [-0.960, -0.680, -0.520, +0.700]
        self.alphas = [0.00100, 0.00100, 0.00100, 0.00100]  # %/°C as factor
        self.gains = [1.0981, 1.0650, 1.0510, 0.9280]
        self.k_sensor = 90.91
    
    def calibrate(self, sensor_id, measured_current, temperature=20.0):
        idx = sensor_id - 1  # 0-based index
        
        # CORRECT: Temperature compensation in CURRENT only
        offset = self.offsets[idx]
        alpha = self.alphas[idx]
        
        # I_corr = (I_meas + offset) × (1 + α×(T-20))
        I_corr = measured_current + offset
        
        if temperature != 20.0:
            I_corr *= (1.0 + (alpha * (temperature - 20.0)))
        
        # Convert to field (NO temperature here!)
        E_raw = I_corr * self.k_sensor
        
        # Apply field gain (NO temperature here!)
        E_calibrated = E_raw * self.gains[idx]
        
        return E_calibrated

# Test with actual data
print("\n📊 TEST WITH ACTUAL MEASUREMENTS:")
print("Sensor | Temp | Measured | Calibrated | Expected | Error")
print("-"*65)

calibrator = PhysicallyCorrectCalibrator()

test_cases = [
    (1, 10.522, -20, 1000.0),
    (1, 10.960, 20, 1000.0),
    (1, 11.179, 40, 1000.0),
    (4, 8.928, -20, 1000.0),
    (4, 9.300, 20, 1000.0),
    (4, 9.486, 40, 1000.0),
]

errors = []
for sensor_id, current, temp, expected in test_cases:
    calibrated = calibrator.calibrate(sensor_id, current, temp)
    error = ((calibrated - expected) / expected) * 100
    errors.append(abs(error))
    
    print(f"{sensor_id:6} | {temp:4}°C | {current:8.3f} | {calibrated:10.1f} | {expected:8.0f} | {error:5.1f}%")

max_error = max(errors)
avg_error = np.mean(errors)

print(f"\n📈 PERFORMANCE WITH PHYSICALLY CORRECT MODEL:")
print(f"Maximum error: {max_error:.1f}%")
print(f"Average error: {avg_error:.1f}%")

if max_error < 2.0:
    print("\n🎉 SUCCESS! Error < 2% with physically correct model")
    print("✅ SYSTEM IS NOW FIELD READY!")
else:
    print(f"\n⚠️  Still needs optimization: {max_error:.1f}% > 2% target")
    print("   Next: Measure actual α for each sensor")

print("\n" + "="*70)
print("🚀 PHYSICAL TRUTH: Temperature affects ELECTRONICS, not FIELD CONVERSION")
print("="*70)
