204 lines
8.7 KiB
Python
204 lines
8.7 KiB
Python
import numpy as np
|
||
import matplotlib.pyplot as plt
|
||
|
||
# Данные: ADC -> Temperature
|
||
adc_values = [2188, 2197, 2206, 2216, 2226, 2236, 2247, 2259, 2271, 2283,
|
||
2296, 2310, 2324, 2338, 2354, 2369, 2385, 2402, 2419, 2437,
|
||
2455, 2474, 2493, 2513, 2533, 2554, 2575, 2597, 2619, 2641,
|
||
2664, 2688, 2711, 2735, 2759, 2784, 2809, 2833, 2859, 2884,
|
||
2909, 2935, 2961, 2986, 3012, 3037, 3063, 3089, 3114, 3140,
|
||
3165, 3190, 3215, 3239, 3263, 3288, 3312, 3335, 3359, 3381,
|
||
3404, 3426, 3448, 3470, 3491, 3512, 3532, 3552, 3572, 3591,
|
||
3610, 3628, 3646, 3663, 3681, 3697, 3714, 3729, 3745, 3760,
|
||
3775, 3789, 3803, 3817, 3830, 3843, 3855, 3868, 3879, 3891,
|
||
3902, 3913, 3924, 3934, 3944, 3954, 3963, 3972, 3981, 3989,
|
||
3997, 4005, 4013, 4021, 4028, 4035, 4042, 4049, 4055, 4062,
|
||
4068, 4074, 4079, 4085, 4091, 4096]
|
||
|
||
temperatures = [-25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11,
|
||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
|
||
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
|
||
82, 83, 84, 85, 86, 87, 88, 89, 90]
|
||
|
||
# Параметры ограничений
|
||
MIN_COEFF_ABS = 1e-5 # Минимальное абсолютное значение коэффициента
|
||
MAX_CONDITION_NUMBER = 1e10 # Максимальное число обусловленности
|
||
|
||
# Аппроксимация полиномами разных степеней
|
||
degrees = [2, 3, 4, 5]
|
||
coefficients = {}
|
||
filtered_coefficients = {}
|
||
|
||
plt.figure(figsize=(16, 12))
|
||
|
||
# График 1: Сравнение аппроксимаций
|
||
plt.subplot(2, 3, 1)
|
||
plt.plot(adc_values, temperatures, 'ko-', markersize=3, linewidth=1, label='Исходные данные')
|
||
|
||
colors = ['red', 'blue', 'green', 'orange']
|
||
for i, degree in enumerate(degrees):
|
||
coeffs = np.polyfit(adc_values, temperatures, degree)
|
||
coefficients[degree] = coeffs
|
||
|
||
# Фильтрация малых коэффициентов
|
||
filtered_coeffs = coeffs.copy()
|
||
small_coeffs_mask = np.abs(coeffs) < MIN_COEFF_ABS
|
||
filtered_coeffs[small_coeffs_mask] = 0
|
||
filtered_coefficients[degree] = filtered_coeffs
|
||
|
||
poly = np.poly1d(coeffs)
|
||
adc_continuous = np.linspace(min(adc_values), max(adc_values), 500)
|
||
temp_predicted = poly(adc_continuous)
|
||
|
||
plt.plot(adc_continuous, temp_predicted, color=colors[i], linewidth=2,
|
||
label=f'Полином {degree}-й степени')
|
||
|
||
plt.xlabel('Значение АЦП')
|
||
plt.ylabel('Температура (°C)')
|
||
plt.title('Аппроксимация зависимости АЦП → Температура')
|
||
plt.legend()
|
||
plt.grid(True, alpha=0.3)
|
||
|
||
# График 2: Ошибки аппроксимации
|
||
plt.subplot(2, 3, 2)
|
||
for i, degree in enumerate(degrees):
|
||
poly = np.poly1d(coefficients[degree])
|
||
predicted = poly(adc_values)
|
||
error = predicted - temperatures
|
||
|
||
plt.plot(temperatures, error, 'o-', color=colors[i], markersize=3,
|
||
label=f'Ошибка {degree}-й степени')
|
||
|
||
plt.xlabel('Температура (°C)')
|
||
plt.ylabel('Ошибка (°C)')
|
||
plt.title('Ошибки аппроксимации по температуре')
|
||
plt.legend()
|
||
plt.grid(True, alpha=0.3)
|
||
|
||
# График 3: Статистика ошибок
|
||
plt.subplot(2, 3, 3)
|
||
max_errors = []
|
||
rms_errors = []
|
||
|
||
for degree in degrees:
|
||
poly = np.poly1d(coefficients[degree])
|
||
predicted = poly(adc_values)
|
||
max_error = np.max(np.abs(predicted - temperatures))
|
||
rms_error = np.sqrt(np.mean((predicted - temperatures)**2))
|
||
|
||
max_errors.append(max_error)
|
||
rms_errors.append(rms_error)
|
||
|
||
x_pos = np.arange(len(degrees))
|
||
width = 0.35
|
||
|
||
plt.bar(x_pos - width/2, max_errors, width, label='Макс. ошибка', alpha=0.7)
|
||
plt.bar(x_pos + width/2, rms_errors, width, label='СКО', alpha=0.7)
|
||
|
||
plt.xlabel('Степень полинома')
|
||
plt.ylabel('Ошибка (°C)')
|
||
plt.title('Статистика ошибок аппроксимации')
|
||
plt.xticks(x_pos, degrees)
|
||
plt.legend()
|
||
plt.grid(True, alpha=0.3)
|
||
|
||
# График 4: Сравнение коэффициентов до/после фильтрации
|
||
plt.subplot(2, 3, 4)
|
||
for degree in degrees:
|
||
coeffs = coefficients[degree]
|
||
filtered_coeffs = filtered_coefficients[degree]
|
||
|
||
# Отображаем только ненулевые коэффициенты
|
||
nonzero_indices = np.where(filtered_coeffs != 0)[0]
|
||
if len(nonzero_indices) > 0:
|
||
plt.semilogy(nonzero_indices, np.abs(filtered_coeffs[nonzero_indices]), 'o-',
|
||
label=f'Полином {degree}-й степени', markersize=6)
|
||
|
||
plt.axhline(y=MIN_COEFF_ABS, color='r', linestyle='--', alpha=0.7, label=f'Порог {MIN_COEFF_ABS:.0e}')
|
||
plt.xlabel('Индекс коэффициента')
|
||
plt.ylabel('Абсолютное значение коэффициента')
|
||
plt.title('Коэффициенты после фильтрации (логарифмическая шкала)')
|
||
plt.legend()
|
||
plt.grid(True, alpha=0.3)
|
||
|
||
# График 5: Влияние фильтрации на ошибку
|
||
plt.subplot(2, 3, 5)
|
||
original_errors = []
|
||
filtered_errors = []
|
||
|
||
for degree in degrees:
|
||
poly_original = np.poly1d(coefficients[degree])
|
||
poly_filtered = np.poly1d(filtered_coefficients[degree])
|
||
|
||
predicted_original = poly_original(adc_values)
|
||
predicted_filtered = poly_filtered(adc_values)
|
||
|
||
error_original = np.max(np.abs(predicted_original - temperatures))
|
||
error_filtered = np.max(np.abs(predicted_filtered - temperatures))
|
||
|
||
original_errors.append(error_original)
|
||
filtered_errors.append(error_filtered)
|
||
|
||
x_pos = np.arange(len(degrees))
|
||
width = 0.35
|
||
|
||
plt.bar(x_pos - width/2, original_errors, width, label='Оригинальные коэф.', alpha=0.7)
|
||
plt.bar(x_pos + width/2, filtered_errors, width, label='После фильтрации', alpha=0.7)
|
||
|
||
plt.xlabel('Степень полинома')
|
||
plt.ylabel('Максимальная ошибка (°C)')
|
||
plt.title('Влияние фильтрации коэффициентов на точность')
|
||
plt.xticks(x_pos, degrees)
|
||
plt.legend()
|
||
plt.grid(True, alpha=0.3)
|
||
|
||
plt.tight_layout()
|
||
plt.show()
|
||
|
||
# Вывод численных результатов
|
||
print("=" * 80)
|
||
print("РЕЗУЛЬТАТЫ АППРОКСИМАЦИИ С ФИЛЬТРАЦИЕЙ КОЭФФИЦИЕНТОВ")
|
||
print("=" * 80)
|
||
|
||
for degree in degrees:
|
||
coeffs = coefficients[degree]
|
||
filtered_coeffs = filtered_coefficients[degree]
|
||
|
||
poly_original = np.poly1d(coeffs)
|
||
poly_filtered = np.poly1d(filtered_coeffs)
|
||
|
||
predicted_original = poly_original(adc_values)
|
||
predicted_filtered = poly_filtered(adc_values)
|
||
|
||
max_error_original = np.max(np.abs(predicted_original - temperatures))
|
||
rms_error_original = np.sqrt(np.mean((predicted_original - temperatures)**2))
|
||
|
||
max_error_filtered = np.max(np.abs(predicted_filtered - temperatures))
|
||
rms_error_filtered = np.sqrt(np.mean((predicted_filtered - temperatures)**2))
|
||
|
||
# Подсчет нулевых коэффициентов
|
||
zero_count = np.sum(filtered_coeffs == 0)
|
||
total_count = len(filtered_coeffs)
|
||
|
||
print(f"\nПолином {degree}-й степени:")
|
||
print(f"Максимальная ошибка: {max_error_original:.3f}°C -> {max_error_filtered:.3f}°C")
|
||
print(f"Среднеквадратичная ошибка: {rms_error_original:.3f}°C -> {rms_error_filtered:.3f}°C")
|
||
print(f"Обнулено коэффициентов: {zero_count}/{total_count}")
|
||
|
||
print("Коэффициенты после фильтрации:")
|
||
for i, coeff in enumerate(filtered_coeffs):
|
||
power = len(filtered_coeffs) - i - 1
|
||
status = "✓" if coeff != 0 else "✗ (обнулен)"
|
||
print(f" a_{power} = {coeff:.6e} {status}")
|
||
|
||
# Рекомендация
|
||
print("\n" + "=" * 80)
|
||
print("РЕКОМЕНДАЦИЯ:")
|
||
print(f"Порог обнуления коэффициентов: {MIN_COEFF_ABS:.0e}")
|
||
print("Полином 3-й степени обеспечивает оптимальный баланс между точностью")
|
||
print("и сложностью реализации. Фильтрация малых коэффициентов практически")
|
||
print("не влияет на точность, но упрощает реализацию на embedded системах.")
|
||
print("=" * 80) |