import numpy as np
import matplotlib.pyplot as plt
# from scipy.interpolate import interp1d

# frequencies = np.array([20, 40, 100, 200, 400, 1000, 2000, 4000, 
#                         10000, 20000, 40000, 100000, 200000, 400000])

# Cp1_values = np.array([61, 130, 300, 460, 590, 630, 630, 580, 360, 180, 66])
# Cp2_values = np.array([140, 230, 480, 600, 650, 670, 670, 670, 660, 650, 580, 380, 185, 68])
# Cp3_values = np.array([88, 220, 480, 590, 650, 650, 650, 650, 580, 430, 245, 74, 24, 7.5])
# Cp4_values = np.array([48, 96, 230, 230, 245, 250, 255, 255, 250, 245, 240, 200, 130, 52])

# curves = {
#     "2.1": Cp1_values,
#     "2.2": Cp2_values,
#     "2.3": Cp3_values,
#     "2.4": Cp4_values
# }

# plt.figure(figsize=(12, 8))
# plt.xscale('log')
# plt.xlabel("Частота (Гц)", fontsize=14)
# plt.ylabel("$2U_{m\\,вых}$ (мВ)", fontsize=14)
# plt.title("Зависимость $2U_{m\\,вых}$ от частоты с определением полосы пропускания", fontsize=16)

# for label, vals in curves.items():
#     freq = frequencies if len(vals) == len(frequencies) else frequencies[3:]
#     # Найдём максимум
#     Umax = np.max(vals)
#     U_3db = Umax * 0.707

#     # Интерполяция для нахождения частот пересечения
#     f_log = np.log10(freq)
#     # интерполяционная функция по логарифму частоты
#     f_inter = interp1d(f_log, vals, kind='cubic', bounds_error=False, fill_value="extrapolate")

#     # Найдём точки пересечения с U_3db
#     # Переберём диапазон частот более плавно
#     f_fine = np.logspace(np.log10(freq[0]), np.log10(freq[-1]), 10000)
#     v_fine = f_inter(np.log10(f_fine))

#     # Определим, где v_fine пересекает U_3db
#     diff = v_fine - U_3db
#     sign_change_indices = np.where(np.diff(np.sign(diff)) != 0)[0]

#     if len(sign_change_indices) >= 2:
#         # нижняя и верхняя граница
#         fL = f_fine[sign_change_indices[0]]
#         fH = f_fine[sign_change_indices[-1]]
#     else:
#         fL, fH = None, None

#     # Отобразим кривую
#     plt.plot(freq, vals, 'o-', label=label)

#     # Горизонтальная линия -3 дБ
#     plt.axhline(U_3db, color='gray', linestyle='--')

#     # Отметим точки пересечения на графике
#     if fL is not None and fH is not None:
#         plt.plot([fL, fH], [U_3db, U_3db], 'x', color='red')
#         print(f"Для кривой {label}:")
#         print(f"  U_max = {Umax:.2f} мВ")
#         print(f"  Уровень -3 дБ = {U_3db:.2f} мВ")
#         print(f"  Нижняя граница = {fL:.2f} Гц")
#         print(f"  Верхняя граница = {fH:.2f} Гц")
#         print(f"  Полоса пропускания ≈ {fH - fL:.2f} Гц\n")

# plt.legend(fontsize=12)
# plt.grid(True, which="both", ls="--", linewidth=0.5)
# plt.tight_layout()
# plt.show()

# Данные (из предыдущего кода)
data_no_load = {
    "U_in": [300, 270, 240, 210, 180, 150, 120, 90, 60, 30],  # мВ
    "U_out": [8.2, 7.6, 7.0, 6.3, 5.6, 4.9, 4.2, 3.6, 3.0, 1.8],  # В
}
data_with_load = {
    "U_in": [500, 450, 400, 350, 300, 250, 200, 150, 100],  # мВ
    "U_out": [7.2, 6.8, 6.4, 6.0, 5.6, 5.0, 4.2, 3.4, 2.5],  # В
}
data_with_feedback = {
    "U_in": [1300, 1170, 1040, 910, 780, 650, 520, 390, 260],  # мВ
    "U_out": [6.6, 6.5, 6.0, 5.8, 5.0, 4.4, 3.8, 3.0, 1.5],  # В
}

def calc_linear_gain(U_in_mV, U_out_V, num_points=3):
    # Возьмём первые num_points точек
    # Переведём вход в В:
    U_in_V = np.array(U_in_mV) * 1e-3
    U_out_V = np.array(U_out_V)
    
    # Линейная аппроксимация первых num_points точек
    z = np.polyfit(U_in_V[-num_points:], U_out_V[-num_points:], 1)  # берем последние точки, где сигнал меньше
    # z[0] - наклон, z[1] - свободный член
    K = z[0]  # Коэффициент усиления - наклон
    return K, z

# Рассчитаем коэффициенты усиления на линейном участке
K_no_load, poly_no_load = calc_linear_gain(data_no_load["U_in"], data_no_load["U_out"], num_points=3)
K_with_load, poly_with_load = calc_linear_gain(data_with_load["U_in"], data_with_load["U_out"], num_points=3)
K_with_feedback, poly_with_feedback = calc_linear_gain(data_with_feedback["U_in"], data_with_feedback["U_out"], num_points=3)

print("Коэффициент усиления (без нагрузки):", K_no_load)
print("Коэффициент усиления (с нагрузкой):", K_with_load)
print("Коэффициент усиления (с нагрузкой и ООС):", K_with_feedback)

# Построение графика с отображением линейной аппроксимации
fig, ax = plt.subplots(figsize=(10,6))

for (d, c, lbl, poly) in [
    (data_no_load, 'blue', "Без нагрузки", poly_no_load),
    (data_with_load, 'green', "С нагрузкой", poly_with_load),
    (data_with_feedback, 'red', "С нагрузкой и ООС", poly_with_feedback)]:

    U_in_V = np.array(d["U_in"])*1e-3
    U_out_V = np.array(d["U_out"])
    ax.plot(d["U_in"], d["U_out"], 'o', label=lbl, color=c)
    # Линия аппроксимации для линейной области
    x_lin = np.linspace(0, np.max(U_in_V), 100)
    ax.plot(x_lin*1e3, np.polyval(poly, x_lin), '--', color=c)

ax.set_xlabel("Входное напряжение 2U_{вх}, мВ", fontsize=14)
ax.set_ylabel("Выходное напряжение 2U_{вых}, В", fontsize=14)
ax.legend(fontsize=12)
ax.grid(True)
plt.title("Амплитудные характеристики усилителя с линейной аппроксимацией")
plt.show()
