// Copyright 2025 RnD Center "ELVEES", JSC

#include <elcore50-signal-lib/fft.h>

void print_usage() {
  printf("Usage: sample-fft-all DIMENSIONS DATA_TYPE [OPTIONS]\n");
  printf("DIMENSIONS: {1d, 2d}\n");
  printf("DATA_TYPE: {float16, float32, fract16}\n");
  printf("Options description:\n");
  printf("\t-r   number of rows in test matrix:\n");
  printf("\t     \trows = 1 for DIMENSIONS = 1d\n");
  printf("\t     \t16 <= rows <= 512 for DIMENSIONS = 2d\n");
  printf("\t-c   number of columns in test matrix:\n");
  printf("\t     \t256 <= columns <= 262144 for DIMENSIONS = 1d\n");
  printf("\t     \t16 <= columns <= 512 for DIMENSIONS = 2d\n");
  printf("\t     \t256 <= rows * columns <= 262144\n");
  printf("\t-m   type of memory: {0 - DDR, 1 - XYRAM}. Default: 1\n");
  printf("\t-h   Print usage\n");
}

int sample_float16_1d(const int32_t fft_size, const int8_t mem_type);
int sample_float32_1d(const int32_t fft_size, const int8_t mem_type);
int sample_fract16_1d(const int32_t fft_size, const int8_t mem_type);

int sample_float16_2d(const int16_t rows_number, const int16_t cols_number, const int8_t mem_type);
int sample_float32_2d(const int16_t rows_number, const int16_t cols_number, const int8_t mem_type);
int sample_fract16_2d(const int16_t rows_number, const int16_t cols_number, const int8_t mem_type);

int main(int argc, char *argv[]) {
  if ((argc != 2) && (argc < 7)) {
    printf("Error: wrong number of parameters!\n");
    print_usage();
    return 1;
  }

  char *key_h = argv[1];
  if (!strcmp(key_h, "-h")) {
    print_usage();
    return 0;
  }

  char *dim = argv[1];
  if (strcmp(dim, "1d") && strcmp(dim, "2d")) {
    printf("Unrecognized program option: %s\n", dim);
    print_usage();
    return 1;
  }

  char *data_type = argv[2];
  if (strcmp(data_type, "float16") && strcmp(data_type, "float32") && strcmp(data_type, "fract16")) {
    printf("Unrecognized program option: %s\n", data_type);
    print_usage();
    return 1;
  }

  int16_t rows_number;
  int32_t cols_number;
  int32_t fft_size;
  int8_t mem_type = 1;
  for (size_t i = 3; i < argc; i += 2) {
    char *key = argv[i];
    if (!strcmp(key, "-r")) {
      rows_number = atoi(argv[i + 1]);
      if (!strcmp(dim, "1d") && (rows_number > 1)) {
        printf("Error: wrong size!\n");
        print_usage();
        return 1;
      } else if (!strcmp(dim, "2d") && (rows_number < 16)) {
        printf("Error: wrong size!\n");
        print_usage();
        return 1;
      }
    } else if (!strcmp(key, "-c")) {
      cols_number = atoi(argv[i + 1]);
      if (!strcmp(dim, "2d") && (cols_number < 16)) {
        printf("Error: wrong size!\n");
        print_usage();
        return 1;
      }
      fft_size = rows_number * cols_number;
      if ((fft_size < 256) || (fft_size > 262144)) {
        printf("Error: wrong total number of complex numbers");
        printf(" in test matrix: %d\n", fft_size);
        print_usage();
        return 1;
      }
    } else if (!strcmp(key, "-m")) {
      mem_type = atoi(argv[i + 1]);
      if ((mem_type < 0) || (mem_type > 1)) {
        printf("Error: wrong memory type!\n");
        print_usage();
        return 1;
      }
    } else {
      printf("Unrecognized program option: %s\n", key);
      print_usage();
      return 1;
    }
  }

  uint8_t is_passed = 1;
  if (!strcmp(dim, "1d")) {
    if (!strcmp(data_type, "float16")) {
      is_passed = sample_float16_1d(fft_size, mem_type);
    } else if (!strcmp(data_type, "float32")) {
      is_passed = sample_float32_1d(fft_size, mem_type);
    } else if (!strcmp(data_type, "fract16")) {
      is_passed = sample_fract16_1d(fft_size, mem_type);
    }
  } else {
    if (!strcmp(data_type, "float16")) {
      is_passed = sample_float16_2d(rows_number, cols_number, mem_type);
    } else if (!strcmp(data_type, "float32")) {
      is_passed = sample_float32_2d(rows_number, cols_number, mem_type);
    } else if (!strcmp(data_type, "fract16")) {
      is_passed = sample_fract16_2d(rows_number, cols_number, mem_type);
    }
  }

  if (is_passed) {
    printf("passed!\n");
    return 0;
  } else {
    printf("failed!\n");
    return 1;
  }
}

float maximum_norm(const float *dsp_res, const float *ref_res, const int size) {
  float diff = fabs(ref_res[0] - dsp_res[0]);
  for (size_t i = 1; i < size * 2; ++i) {
    float diff_i = fabs(ref_res[i] - dsp_res[i]);
    if (diff_i > diff) diff = diff_i;
  }

  return diff;
}

int sample_float16_1d(const int32_t fft_size, const int8_t mem_type) {
  // Выходной вектор для типа float16
  // Выравнивание нужно только при mem_type = 0
  int16_t *fdst = memalign(fft_size * 2 * sizeof(int16_t), fft_size * 2 * sizeof(int16_t));
  // Входной вектор для типа float16
  int16_t *fsrc = memalign(fft_size * 2 * sizeof(int16_t), fft_size * 2 * sizeof(int16_t));
  // Вектор точного решения
  float *fetalon = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));

  // Создание объекта преобразования
  fft_t fft_obj;
  fft_obj.src = fsrc;
  fft_obj.dst = fdst;
  fft_obj.int_mem = mem_type;
  fft_obj.dir = SL_IFFT;
  fft_obj.dim = SL_1D;
  int retval = fft_plan_1d(&fft_obj, fft_size, SL_HFLOAT);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  };

  // Частота входного сигнала
  const int32_t frequency = 5;
  // Входной сигнал и точное решение
  memset(fetalon, 0.0, fft_size * 2 * sizeof(float));
  fetalon[2 * frequency + 1] = 1.0;
  // Преобразование входного сигнала типа float32 в тип float16
  float32_to_float16(fetalon, fsrc, fft_size * 2);

  // Вычисление обратного БПФ
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  float *temp = malloc(fft_size * 2 * sizeof(float));
  if (!fft_obj.big_size || !fft_obj.int_mem) {
    // Нормировка результата обратного БПФ
    float16_to_float32(fdst, temp, fft_size * 2);
    for (size_t i = 0; i < fft_size * 2; ++i) {
      temp[i] /= fft_size;
    }
    float32_to_float16(temp, fdst, fft_size * 2);
    // Подготовка для вычисления прямого БПФ
    fft_obj.src = fdst;
    fft_obj.dst = fsrc;
  } else {
    // Нормировка результата обратного БПФ
    float16_to_float32(fsrc, temp, fft_size * 2);
    for (size_t i = 0; i < fft_size * 2; ++i) {
      temp[i] /= fft_size;
    }
    float32_to_float16(temp, fsrc, fft_size * 2);
    // Подготовка для вычисления прямого БПФ
    fft_obj.src = fsrc;
    fft_obj.dst = fdst;
  }

  // Вычисление прямого БПФ
  fft_obj.dir = SL_FFT;
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    free(temp);
    return 0;
  }

  // Проверка результата
  float16_to_float32(fsrc, temp, fft_size * 2);
  const float norm = maximum_norm(temp, fetalon, fft_size);
  printf("float16 1d sample result:\n");
  printf("fft_size = %d, ", fft_size);
  if (mem_type == 0)
    printf("mem_type = SL_DDR: ");
  else
    printf("mem_type = SL_XYRAM: ");

  // Освобождение ресурсов
  fft_free_sources(&fft_obj);
  free(temp);
  free(fdst);
  free(fsrc);
  free(fetalon);

  return norm < 1e-2;
}

int sample_float32_1d(const int32_t fft_size, const int8_t mem_type) {
  // Выходной вектор для типа float32
  // Выравнивание нужно только при mem_type = 0
  float *fdst = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));
  // Входной вектор для типа float32
  float *fsrc = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));
  // Вектор точного решения
  float *fetalon = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));

  // Создание объекта преобразования
  fft_t fft_obj;
  fft_obj.src = fsrc;
  fft_obj.dst = fdst;
  fft_obj.int_mem = mem_type;
  fft_obj.dir = SL_IFFT;
  fft_obj.dim = SL_1D;
  int retval = fft_plan_1d(&fft_obj, fft_size, SL_FLOAT);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Частота входного сигнала
  const int32_t frequency = 5;
  // Входной сигнал и точное решение
  memset(fsrc, 0.0, fft_size * 2 * sizeof(float));
  fsrc[2 * frequency + 1] = (float)fft_size;
  memcpy(fetalon, fsrc, fft_size * 2 * sizeof(float));

  // Вычисление обратного БПФ
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  if (!fft_obj.big_size || !fft_obj.int_mem) {
    // Нормировка результата обратного БПФ
    for (size_t i = 0; i < fft_size * 2; ++i) {
      fdst[i] /= fft_size;
    }
    // Подготовка для вычисления прямого БПФ
    fft_obj.src = fdst;
    fft_obj.dst = fsrc;
  } else {
    // Нормировка результата обратного БПФ
    for (size_t i = 0; i < fft_size * 2; ++i) {
      fsrc[i] /= fft_size;
    }
    // Подготовка для вычисления прямого БПФ
    fft_obj.src = fsrc;
    fft_obj.dst = fdst;
  }

  // Вычисление прямого БПФ
  fft_obj.dir = SL_FFT;
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Проверка результата
  const float norm = maximum_norm(fsrc, fetalon, fft_size);
  printf("float32 1d sample result:\n");
  printf("fft_size = %d, ", fft_size);
  if (mem_type == 0)
    printf("mem_type = SL_DDR: ");
  else
    printf("mem_type = SL_XYRAM: ");

  // Освобождение ресурсов
  fft_free_sources(&fft_obj);
  free(fdst);
  free(fsrc);
  free(fetalon);

  return norm < 1e-2;
}

int sample_fract16_1d(const int32_t fft_size, const int8_t mem_type) {
  // Выходной вектор для типа fractional16
  // Выравнивание нужно только при mem_type = 0
  int16_t *fdst = memalign(fft_size * 2 * sizeof(int16_t), fft_size * 2 * sizeof(int16_t));
  // Входной вектор для типа fractional16
  int16_t *fsrc = memalign(fft_size * 2 * sizeof(int16_t), fft_size * 2 * sizeof(int16_t));
  // Вектор точного решения
  float *fetalon = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));

  // Создание объекта преобразования
  fft_t fft_obj;
  fft_obj.src = fsrc;
  fft_obj.dst = fdst;
  fft_obj.int_mem = mem_type;
  fft_obj.dir = SL_IFFT;
  fft_obj.dim = SL_1D;
  int retval = fft_plan_1d(&fft_obj, fft_size, SL_FRACTIONAL);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Частота входного сигнала
  const int32_t frequency = 5;
  // Входной сигнал и точное решение
  memset(fsrc, 0.0, fft_size * 2 * sizeof(int16_t));
  fsrc[2 * frequency + 1] = 0.99 * 0x8000;
  memset(fetalon, 0.0, fft_size * 2 * sizeof(float));
  fetalon[2 * frequency + 1] = 0.99;

  // Вычисление обратного БПФ
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Подготовка для вычисления прямого БПФ
  if (!fft_obj.int_mem || !fft_obj.big_size) {
    fft_obj.src = fdst;
    fft_obj.dst = fsrc;
  } else {
    fft_obj.src = fsrc;
    fft_obj.dst = fdst;
  }

  // Вычисление прямого БПФ
  fft_obj.dir = SL_FFT;
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Проверка результата
  float *temp = malloc(fft_size * 2 * sizeof(float));
  fract16_to_float32(fsrc, temp, fft_size);
  const float norm = maximum_norm(temp, fetalon, fft_size);
  printf("fract16 1d sample result:\n");
  printf("fft_size = %d, ", fft_size);
  if (mem_type == 0)
    printf("mem_type = SL_DDR: ");
  else
    printf("mem_type = SL_XYRAM: ");

  // Освобождение ресурсов
  fft_free_sources(&fft_obj);
  free(temp);
  free(fdst);
  free(fsrc);
  free(fetalon);

  return norm < 1e-2;
}

int sample_float16_2d(const int16_t rows_number, const int16_t cols_number, const int8_t mem_type) {
  // Общее количество комплексных отсчетов
  const int32_t fft_size = rows_number * cols_number;
  // Выходной вектор для типа float16
  // Выравнивание нужно только при mem_type = 0
  int16_t *fdst = memalign(fft_size * 2 * sizeof(int16_t), fft_size * 2 * sizeof(int16_t));
  //! Входной вектор для типа float16
  int16_t *fsrc = memalign(fft_size * 2 * sizeof(int16_t), fft_size * 2 * sizeof(int16_t));
  //! Вектор точного решения
  float *fetalon = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));

  // Создание объекта преобразования
  fft_t fft_obj;
  fft_obj.src = fsrc;
  fft_obj.dst = fdst;
  fft_obj.int_mem = mem_type;
  fft_obj.dir = SL_IFFT;
  fft_obj.dim = SL_2D;
  int retval = fft_plan_2d(&fft_obj, rows_number, cols_number, SL_HFLOAT);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Частота входного сигнала
  const int16_t frequency1 = 2;
  const int16_t frequency2 = 1;
  // Входной сигнал
  float *temp = malloc(fft_size * 2 * sizeof(float));
  memset(temp, 0.0, fft_size * 2 * sizeof(float));
  temp[2 * (frequency1 * cols_number + frequency2) + 1] = 1.0;
  float32_to_float16(temp, fsrc, fft_size * 2);

  // Вычисление обратного БПФ
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    free(temp);
    return 0;
  }

  // Нормировка результата обратного БПФ
  float16_to_float32(fsrc, temp, fft_size * 2);
  for (size_t i = 0; i < fft_size * 2; ++i) temp[i] /= (float)fft_size;

  if (fft_obj.int_mem && fft_obj.big_size) {
    // Транспонирование результата обратного БПФ
    float *temp_T = malloc(fft_size * 2 * sizeof(float));
    for (size_t i = 0; i < cols_number * 2; i += 2) {
      for (size_t j = 0; j < rows_number * 2; j += 2) {
        temp_T[j * cols_number + i] = temp[i * rows_number + j];
        temp_T[j * cols_number + i + 1] = temp[i * rows_number + j + 1];
      }
    }
    float32_to_float16(temp_T, fsrc, fft_size * 2);
    free(temp_T);
  } else {
    float32_to_float16(temp, fsrc, fft_size * 2);
  }

  // Вычисление прямого БПФ
  fft_obj.src = fsrc;
  fft_obj.dst = fdst;
  fft_obj.dir = SL_FFT;
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    free(temp);
    return 0;
  }

  // Проверка результата
  float16_to_float32(fsrc, temp, fft_size * 2);
  memset(fetalon, 0.0, fft_size * 2 * sizeof(float));
  if (fft_obj.int_mem && fft_obj.big_size)
    fetalon[2 * (frequency2 * rows_number + frequency1) + 1] = 1.0;
  else
    fetalon[2 * (frequency1 * cols_number + frequency2) + 1] = 1.0;

  const float norm = maximum_norm(temp, fetalon, fft_size);
  printf("float16 2d sample result:\n");
  printf("rows = %d, cols = %d, ", rows_number, cols_number);
  if (mem_type == 0)
    printf("mem_type = SL_DDR: ");
  else
    printf("mem_type = SL_XYRAM: ");

  // Освобождение ресурсов
  fft_free_sources(&fft_obj);
  free(temp);
  free(fdst);
  free(fsrc);
  free(fetalon);

  return norm < 1e-2;
}

int sample_float32_2d(const int16_t rows_number, const int16_t cols_number, const int8_t mem_type) {
  // Общее количество комплексных отсчетов
  const int32_t fft_size = rows_number * cols_number;
  // Выходной вектор для типа float32
  // Выравнивание нужно только при mem_type = 0
  float *fdst = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));
  // Входной вектор для типа float32
  float *fsrc = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));
  // Вектор точного решения
  float *fetalon = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));

  // Создание объекта преобразования
  fft_t fft_obj;
  fft_obj.src = fsrc;
  fft_obj.dst = fdst;
  fft_obj.int_mem = mem_type;
  fft_obj.dir = SL_IFFT;
  fft_obj.dim = SL_2D;
  int retval = fft_plan_2d(&fft_obj, rows_number, cols_number, SL_FLOAT);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Частота входного сигнала
  const int16_t frequency1 = 2;
  const int16_t frequency2 = 1;
  // Входной сигнал
  memset(fsrc, 0.0, fft_size * 2 * sizeof(float));
  fsrc[2 * (frequency1 * cols_number + frequency2) + 1] = (float)fft_size;

  // Вычисление обратного БПФ
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Нормировка результата обратного БПФ
  for (size_t i = 0; i < fft_size * 2; ++i) fsrc[i] /= (float)fft_size;

  if (fft_obj.int_mem && fft_obj.big_size) {
    // Транспонирование результата обратного БПФ
    for (size_t i = 0; i < cols_number * 2; i += 2) {
      for (size_t j = 0; j < rows_number * 2; j += 2) {
        fdst[j * cols_number + i] = fsrc[i * rows_number + j];
        fdst[j * cols_number + i + 1] = fsrc[i * rows_number + j + 1];
      }
    }
    // Подготовка для вычисления прямого БПФ
    fft_obj.src = fdst;
    fft_obj.dst = fsrc;
    fft_obj.dir = SL_FFT;
  } else {
    // Подготовка для вычисления прямого БПФ
    fft_obj.src = fsrc;
    fft_obj.dst = fdst;
    fft_obj.dir = SL_FFT;
  }

  // Вычисление прямого БПФ
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Проверка результата
  memset(fetalon, 0.0, fft_size * 2 * sizeof(float));
  float norm;
  if (fft_obj.int_mem && fft_obj.big_size) {
    fetalon[2 * (frequency2 * rows_number + frequency1) + 1] = (float)fft_size;
    norm = maximum_norm(fdst, fetalon, fft_size);
  } else {
    fetalon[2 * (frequency1 * cols_number + frequency2) + 1] = (float)fft_size;
    norm = maximum_norm(fsrc, fetalon, fft_size);
  }
  printf("float32 2d sample result:\n");
  printf("rows = %d, cols = %d, ", rows_number, cols_number);
  if (mem_type == 0)
    printf("mem_type = SL_DDR: ");
  else
    printf("mem_type = SL_XYRAM: ");

  // Освобождение ресурсов
  fft_free_sources(&fft_obj);
  free(fdst);
  free(fsrc);
  free(fetalon);

  return norm < 1e-2;
}

int sample_fract16_2d(const int16_t rows_number, const int16_t cols_number, const int8_t mem_type) {
  // Общее количество комплексных отсчетов
  const int32_t fft_size = rows_number * cols_number;
  // Выходной вектор для типа fractional16
  // Выравнивание нужно только при mem_type = 0
  int16_t *fdst = memalign(fft_size * 2 * sizeof(int16_t), fft_size * 2 * sizeof(int16_t));
  // Входной вектор для типа fractional16
  int16_t *fsrc = memalign(fft_size * 2 * sizeof(int16_t), fft_size * 2 * sizeof(int16_t));
  // Вектор точного решения
  float *fetalon = memalign(fft_size * 2 * sizeof(float), fft_size * 2 * sizeof(float));

  // Создание объекта преобразования
  fft_t fft_obj;
  fft_obj.src = fsrc;
  fft_obj.dst = fdst;
  fft_obj.int_mem = mem_type;
  fft_obj.dir = SL_IFFT;
  fft_obj.dim = SL_2D;
  int retval = fft_plan_2d(&fft_obj, rows_number, cols_number, SL_FRACTIONAL);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Частота входного сигнала
  const int16_t frequency1 = 2;
  const int16_t frequency2 = 1;
  // Входной сигнал
  memset(fsrc, 0.0, fft_size * 2 * sizeof(short));
  fsrc[2 * (frequency1 * cols_number + frequency2) + 1] = 0.99 * 0.99 * 0x8000;

  // Вычисление обратного БПФ
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    return 0;
  }

  // Подготовка для вычисления прямого БПФ
  float *temp = malloc(fft_size * 2 * sizeof(float));
  if (fft_obj.int_mem && fft_obj.big_size) {
    // Транспонирование результата обратного БПФ
    float *temp_T = malloc(fft_size * 2 * sizeof(float));
    fract16_to_float32(fsrc, temp, fft_size);
    for (size_t i = 0; i < cols_number * 2; i += 2) {
      for (size_t j = 0; j < rows_number * 2; j += 2) {
        temp_T[j * cols_number + i] = temp[i * rows_number + j];
        temp_T[j * cols_number + i + 1] = temp[i * rows_number + j + 1];
      }
    }
    float32_to_fract16(temp_T, fsrc, fft_size);
    free(temp_T);
  }

  // Вычисление прямого БПФ
  fft_obj.src = fsrc;
  fft_obj.dst = fdst;
  fft_obj.dir = SL_FFT;
  retval = fft_execute(&fft_obj);
  if (retval) {
    print_error_message(retval);
    // Освобождение ресурсов
    fft_free_sources(&fft_obj);
    free(fdst);
    free(fsrc);
    free(fetalon);
    free(temp);
    return 0;
  }

  // Проверка результата
  fract16_to_float32(fsrc, temp, fft_size);
  memset(fetalon, 0.0, fft_size * 2 * sizeof(float));
  if (fft_obj.int_mem & fft_obj.big_size)
    fetalon[2 * (frequency2 * rows_number + frequency1) + 1] = 0.99 * 0.99;
  else
    fetalon[2 * (frequency1 * cols_number + frequency2) + 1] = 0.99 * 0.99;
  const float norm = maximum_norm(temp, fetalon, fft_size);
  printf("fract16 2d sample result:\n");
  printf("rows = %d, cols = %d, ", rows_number, cols_number);
  if (mem_type == 0)
    printf("mem_type = SL_DDR: ");
  else
    printf("mem_type = SL_XYRAM: ");

  // Освобождение ресурсов
  fft_free_sources(&fft_obj);
  free(temp);
  free(fdst);
  free(fsrc);
  free(fetalon);

  return norm < 1e-2;
}
