найди баги в коде import time
import sys
import math
import traceback
import numpy as np
sys.path.insert(0,'../basic')

from modem import modem
from modem import ch_emulator
from modem import misc
from autotest_report import autotest_report as autoreport
from autotest_arg_parser import autotest_arg_parser as arg_parser

# -------- Initial settings ---------------
arg_parser.trx_mode = 'simplex' # simplex, packet
# -----------------------------------------
# Init argument parser
ap = arg_parser()
# Parse command line arguments
ap.arg_parse(sys.argv[1:])
emulator = ch_emulator()
# Получение аргументов
host_tx = ap.args.ip_tx
host_retx = ap.args.ip_retx
host_rx = ap.args.ip_rx
freq_tx = ap.args.f_tx
freq_retx_rx = ap.args.f_retx_rx
freq_rx = ap.args.f_rx
trx_mode = ap.args.mode
bw = ap.args.bw
freq_shift = ap.args.f_shift
mod_type = ap.args.mod
code_rate = ap.args.cr
ifs_on_off = ap.args.ifs
ifs_range = ap.args.ifs_rng
ifs_smplx_lock_thr = ap.args.ifs_lck
ifs_adj_step_thr = ap.args.ifs_adj
ifs_rst_thr = ap.args.ifs_rst

BER_target = 1e-6
FER_target = 1 - (1 - BER_target)**(204*8)
FER_target_exp = math.log(FER_target, 10)
baud_num = 12
rx_pkt_num = round((1/BER_target)*200/1632)

# Параметры поиска SNR
SNR_COARSE_START = 0    # Начальный SNR для грубого поиска
SNR_COARSE_END = 30     # Конечный SNR для грубого поиска
SNR_COARSE_STEP = 5     # Шаг грубого поиска
SNR_FINE_POINTS = 10    # Количество точек для детального поиска

# -----------------------------------------------------------------------------------

def get_fine_search_range(transition_snr, fer_value):
    """Определяет диапазон детального поиска на основе значения FER"""
    if fer_value == 1.00e-10:
        # Если FER = 0, берем диапазон от текущей точки -5 dB
        fine_start = max(SNR_COARSE_START, transition_snr - 5)
        fine_end = transition_snr
        print(f"FER=0: детальный поиск в диапазоне {fine_start:.2f} - {fine_end:.2f} dB (от текущей точки -5 dB)")
    elif 1.00e-10 < fer_value < 1.00e+00:
        # Если FER не 0 и не 1, берем диапазон от текущей точки +-2.5 dB
        fine_start = max(SNR_COARSE_START, transition_snr - 2.5)
        fine_end = transition_snr
        print(f"FER≠0 и ≠1: детальный поиск в диапазоне {fine_start:.2f} - {fine_end:.2f} dB (от текущей точки -2.5 dB)")
    else:
        # Если FER=1, используем стандартный диапазон
        fine_start = max(SNR_COARSE_START, transition_snr - SNR_COARSE_STEP/2)
        fine_end = min(SNR_COARSE_END, transition_snr + SNR_COARSE_STEP/2)
        print(f"FER=1: стандартный детальный поиск в диапазоне {fine_start:.2f} - {fine_end:.2f} dB")

    return fine_start, fine_end

# Функция восстановления после сбоя
def recover_from_failure():
    """Выполняет восстановление системы после сбоя приемника"""
    print("Выполняю восстановление после сбоя...")
    try:
        # Выключаем передачу на всех устройствах
        modem.trx_mode_rx(modem, host_tx)
        modem.trx_mode_rx(modem, host_rx)
        modem.trx_mode_rx(modem, host_retx)

        # Сбрасываем модемы и буферы
        modem.modem_reset(host_tx)
        modem.modem_reset(host_rx)
        modem.modem_reset(host_retx)
        modem.tx_buf_reset(host_tx)
        modem.tx_buf_reset(host_rx)
        modem.tx_buf_reset(host_retx)

        # Ждем 5 секунд перед следующим действием
        time.sleep(5)
        print("Восстановление завершено")
        return True
    except Exception as e:
        print(f"Ошибка при восстановлении: {str(e)}")
        return False

# Создание отчета
ar = autoreport()
ar.get_fpga_pw_ver(host_tx, host_rx, host_retx)
ar.set_md_file_name(trx_mode, modem.rd_modem_type(host_tx))
ar.write_fpga_pw_ver_table()

# Текстовый лог
txt_file = open(f'{ar.md_file.file_name}.txt', 'w')
txt_file.write(f'{trx_mode}\n')

snr_table_data = [['-']*len(bw) for _ in range(len(code_rate)*len(mod_type))]
freq_shift_meas = [0.0]*len(bw)
error_flag = 0

try:
    for b_idx, ibw in enumerate(bw):
        print(f"\n=== Обработка полосы {ibw} Hz ({b_idx+1}/{len(bw)}) ===")
        print(f"Настройка модемов для полосы {ibw} Hz...")
        # Настройки для текущей полосы
        modem.trx_mode_rx(modem, host_rx)
        modem.trx_mode_web_fdd(host_retx)
        modem.trx_mode_rx(modem, host_tx)
        time.sleep(1)
        modem.modem_reset(host_tx)
        modem.modem_reset(host_rx)
        modem.tx_buf_reset(host_tx)
        modem.tx_buf_reset(host_rx)
        modem.set_freq(host_tx, freq_tx)
        modem.set_baudrate_hpi(modem, host_retx, '32M')
        modem.set_baudrate_hpi(modem, host_tx, ibw)
        modem.set_baudrate_hpi(modem, host_rx, ibw)
        time.sleep(2)

        print(f"Калибровка частоты для полосы {ibw} Hz...")
        # Калибровка частоты
        emulator.set_snr_by_rx_rssi_in_simplex_mode(modem, misc, host_tx, host_retx, host_rx, 25, 'simplex', 'ch_emulator_att')
        ch_emulator.freq_shift_disable(modem, host_retx)
        freq_error = ch_emulator.get_rx_freq_error_simplex_rx_web(host_rx, int(host_tx.split('.')[2]))
        freq_shift_corrected = freq_shift[b_idx] - freq_error
        ch_emulator.freq_shift_enable(ch_emulator, host_retx, freq_shift_corrected)
        print(f"Корректировка сдвига частоты: {freq_error:.2f} Hz -> установлено {freq_shift_corrected:.2f} Hz")

        # Подготовка графиков
        print("Подготовка графиков...")
        autoreport.create_figs(ibw)
        txt_file.write(f'{ibw}\n')
        ar.md_file.new_header(1, f'FER(SNR), BER(EbNo) {ibw}Hz')

        for j, imod in enumerate(mod_type):
            for k, icr in enumerate(code_rate):
                skip_current = False  # Флаг пропуска текущего режима
                current_mod = f"{imod}{icr}"
                print(f"\n--- Обработка комбинации: модуляция {imod}, код {icr} ({j+1}/{len(mod_type)}x{k+1}/{len(code_rate)}) ---")
                print(f"Установка параметров: {current_mod}")
                modem.set_txrx_param_hpi(modem, host_tx, host_rx, imod, icr, baud_num)

                # Грубый поиск SNR
                print(f"\nГрубый поиск SNR для {current_mod} от {SNR_COARSE_START} до {SNR_COARSE_END} с шагом {SNR_COARSE_STEP}")
                snr_coarse = list(range(SNR_COARSE_START, SNR_COARSE_END + 1, SNR_COARSE_STEP))
                real_snr, fer = [], []
                transition_snr = None  # Для хранения SNR точки перехода (0 < FER < 1)
                transition_fer = None   # Для хранения значения FER в точке перехода

                # Этап 1: Грубый поиск
                for isnr in snr_coarse:
                    try:
                        print(f"Попытка SNR = {isnr} dB...", end=' ')
                        modem.trx_mode_rx(modem, host_rx)
                        modem.trx_mode_rx(modem, host_tx)
                        modem.modem_reset(host_tx)
                        modem.modem_reset(host_rx)
                        modem.trx_mode_simplex_rx(modem, host_rx)
                        modem.trx_mode_simplex_tx(modem, host_tx)
                        modem.set_agc_fast_mode(host_rx)

                        # Установка SNR
                        real_snr_val = emulator.set_snr_by_rx_rssi(
                            modem, misc, host_tx, host_retx, host_rx, isnr, 'ch_emulator_att_out_gain'
                        )

                        # Измерение FER
                        fer_val = ch_emulator.meas_fer_web(host_rx, rx_pkt_num, 10000, int(host_tx.split('.')[2]))
                        if (fer_val > 1 or fer_val < 0):
                            fer_val = 1
                        fer_val = max(fer_val, 1e-10)

                        real_snr.append(real_snr_val)
                        fer.append(fer_val)
                        if real_snr_val is not None and fer_val is not None:
                            print(f"Реальное SNR: {real_snr_val:.2f} dB, FER: {fer_val:.2e}")
                        else:
                            print(f"Ошибка измерения: real_snr_val={real_snr_val}, fer_val={fer_val}")

                        # Обнаружение точки перехода (FER не 0 и не 1)
                        if transition_snr is None and 0 < fer_val < 1:
                            transition_snr = real_snr_val
                            transition_fer = fer_val
                            print(f"!!! НАЙДЕНА ТОЧКА ПЕРЕХОДА: SNR = {transition_snr:.2f} dB, FER = {fer_val:.2e} !!!")

                        if fer_val < FER_target:
                            print(f"Достигнут целевой FER {FER_target:.2e} при SNR {real_snr_val:.2f} dB")
                            break  # Прерываем при достижении цели
                    except Exception as e:
                        print(f"\nОшибка при измерении FER: {str(e)}")
                        print(traceback.format_exc())

                        # Выполняем процедуру восстановления
                        if recover_from_failure():
                            skip_current = True
                            break  # Выходим из цикла по SNR
                        else:
                            # Если восстановление не удалось, прерываем весь тест
                            raise

                # Если была ошибка - пропускаем текущий режим
                if skip_current:
                    print(f"Пропускаю режим {imod}{icr} из-за ошибки")
                    # Записываем заглушку в результаты
                    snr_table_data[j*len(code_rate)+k][b_idx] = 'ERR'
                    txt_file.write(f'{imod}{icr}\nERROR: Measurement failed\n')
                    continue

                # Определение области для детального поиска
                if transition_snr is not None:
                    # Используем новую функцию для определения диапазона на основе FER
                    fine_start, fine_end = get_fine_search_range(transition_snr, transition_fer)
                    print(f"Детальный поиск в диапазоне: {fine_start:.2f} - {fine_end:.2f} dB")
                    snr_fine = np.linspace(fine_start, fine_end, SNR_FINE_POINTS)
                else:
                    # Стандартная логика определения диапазона
                    try:
                        threshold_idx = next(i for i, f in enumerate(fer) if f < FER_target)
                        print(f"Порог FER найден при индексе {threshold_idx} (SNR {real_snr[threshold_idx]:.2f} dB)")
                        if threshold_idx > 0:
                            fine_start = real_snr[threshold_idx-1]
                        else:
                            fine_start = max(SNR_COARSE_START, real_snr[threshold_idx] - SNR_COARSE_STEP)
                        fine_end = real_snr[threshold_idx]
                        print(f"Детальный поиск в диапазоне: {fine_start:.2f} - {fine_end:.2f} dB")
                        snr_fine = np.linspace(fine_start, fine_end, SNR_FINE_POINTS)
                    except StopIteration:
                        print("Целевой FER не достигнут в грубом диапазоне")
                        snr_fine = []

                # Этап 2: Детальный поиск
                if len(snr_fine) > 0:
                    print(f"\nДетальный поиск ({len(snr_fine)} точек)...")
                    for idx, isnr in enumerate(snr_fine):
                        try:
                            print(f"Детальный поиск {idx+1}/{len(snr_fine)}: SNR = {isnr:.2f} dB...", end=' ')
                            modem.trx_mode_rx(modem, host_rx)
                            modem.trx_mode_rx(modem, host_tx)
                            modem.modem_reset(host_tx)
                            modem.modem_reset(host_rx)
                            modem.trx_mode_simplex_rx(modem, host_rx)
                            modem.trx_mode_simplex_tx(modem, host_tx)
                            modem.set_agc_fast_mode(host_rx)

                            real_snr_val = emulator.set_snr_by_rx_rssi(
                                modem, misc, host_tx, host_retx, host_rx, isnr, 'emulator_att_out_gain', 'ch_emulator_att_out_gain'
                            )
                            fer_val = ch_emulator.meas_fer_web(host_rx, rx_pkt_num, 10000, int(host_tx.split('.')[2]))
                            if (fer_val > 1 or fer_val < 0):
                                fer_val = 1
                            fer_val = max(fer_val, 1e-10)

                            real_snr.append(real_snr_val)
                            fer.append(fer_val)
                            print(f"Реальное SNR: {real_snr_val:.2f} dB, FER: {fer_val:.2e}")
                            if fer_val == 1e-10:
                                print("FER = 0, прерывание детального поиска")
                                break
                        except Exception as e:
                            print(f"\nОшибка при детальном измерении FER: {str(e)}")
                            print(traceback.format_exc())

                            # Выполняем процедуру восстановления
                            if recover_from_failure():
                                skip_current = True
                                break  # Выходим из цикла детального поиска
                            else:
                                # Если восстановление не удалось, прерываем весь тест
                                raise

                # Если была ошибка в детальном поиске - пропускаем текущий режим
                if skip_current:
                    print(f"Пропускаю режим {imod}{icr} из-за ошибки")
                    # Записываем заглушку в результаты
                    snr_table_data[j*len(code_rate)+k][b_idx] = 'ERR'
                    txt_file.write(f'{imod}{icr}\nERROR: Detailed measurement failed\n')
                    continue

                # Сортировка данных по SNR
                combined = sorted(zip(real_snr, fer), key=lambda x: x[0])
                real_snr_sorted, fer_sorted = zip(*combined) if combined else ([], [])

                # Расчет чувствительности
                fer_exp = [math.log(f, 10) for f in fer_sorted] if fer_sorted else []
                sens_snr = 100.0  # Значение по умолчанию

                if fer_exp:
                    try:
                        thr_idx = next(i for i, f in enumerate(fer_exp) if f <= FER_target_exp)
                        if thr_idx == 0:
                            sens_snr = real_snr_sorted[0]
                        else:
                            x = [real_snr_sorted[thr_idx-1], real_snr_sorted[thr_idx]]
                            y = [fer_exp[thr_idx-1], fer_exp[thr_idx]]
                            sens_snr = x[0] + (FER_target_exp - y[0]) * (x[1] - x[0]) / (y[1] - y[0])
                        print(f"Расчетная чувствительность: {sens_snr:.2f} dB")
                    except StopIteration:
                        sens_snr = 100.0
                        print("Целевой FER не достигнут в измеренном диапазоне")
                else:
                    print("Нет данных для расчета чувствительности")

                # Запись результатов
                snr_table_data[j*len(code_rate)+k][b_idx] = f'{sens_snr:.2f}'
                autoreport.update_figs(real_snr_sorted, fer_sorted, imod, icr)
                txt_file.write(f'{imod}{icr}\nSNR: {" ".join(map(str, real_snr_sorted))}\nFER: {" ".join(map(str, fer_sorted))}\nSens: {sens_snr}\n')

        ar.save_figs(ibw)
        ar.write_figs(ibw)

except Exception as e:
    error_flag = 1
    print(f'Error: {e}\n{traceback.format_exc()}')

finally:
    txt_file.close()
    ar.write_snr_table(snr_table_data, bw, code_rate, mod_type, freq_shift_meas, error_flag)
    ar.save_report()