import numpy as np
import pandas as pd
import random

"""
Генерация сигналов-синусоид с переменными периодами и амплитудами.
"""

def generate(periods, amplitudes, frequencies, ground=0, sample_rate=1e-2):
    """
    Генерирует синусоиду с заданным количеством периодов, случайно изменяющейся
    амплитудой и случайно изменяющейся частотой.

    Параметры:
        periods - количество периодов синусоиды. Тип - int.
        amplitudes - список из двух значений амплитуд - минимальной и
    максимальной. Амплитуды будут генерироваться случайно, между двумя этими
    значениями. Тип - list.
        frequencies - список из двух значений частот - минимальной и
    максимальной. Частоты будут генерироваться случайно, между двумя этими
    значениями. Тип - list.
        ground - точка по оси y, относительно которой строится синусоида.
    Значение по умолчанию: 0. Тип - float.
        sample_rate - частота дискретизации сигнала синусоиды. Значение по
    умолчанию: 1e-2. Тип - float.

    Возвращает синусоиду. Тип - list.
    """
    # Инициализация списка
    sgn = []
    # Каждую итерацию цикла создается один период синусоиды
    for i in range(periods):
        # Генерируется амплитуда и частота
        amplitude = random.uniform(amplitudes[0], amplitudes[1])
        frequency = random.uniform(frequencies[0], frequencies[1])
        period = 1 / frequency
        # Создается период синусоиды и добавляется в общий список
        for t in np.arange(0, 2 * np.pi * period, sample_rate):
            sgn.append(amplitude * np.sin(frequency * t) + ground + amplitudes[1])
    return sgn

def reduce(arrays):
    """
    Укорачивает списки до длины меньшего списка.

    Параметры:
        arrays - список, состоящий из списков. Например, список из синусоид,
    сгеренированных с помощью функции generate. Тип - list.

    Возвращает список, состоящий из списков. Тип - list.
    """
    # Вычисляется минимальная длина среди всех списков
    min = len(arrays[0])
    for array in arrays:
        if len(array) < min:
            min = len(array)
    # Все списки укорачиваются до длины самого короткого
    arrays = [array[0:min] for array in arrays]
    return arrays

def createDF(arrays, keys):
    """
    Создает таблицу из списков.

    Параметры:
        arrays - список, состоящий из списков. Например, список из синусоид,
    сгеренированных с помощью функции generate. Тип - list.
        keys - список из названий для столбцов. Тип - list.

    Возвращает таблицу. Тип - pandas.DataFrame.
    """
    df = pd.DataFrame()
    for i in range(0, len(arrays)):
        df[keys[i]] = arrays[i]
    return df

def generateDF(keys, periods=20, amplitudes=[1, 1.5], frequencies=[1/6, 1/2],
               ground=0, sample_rate=1e-2):
    """
    Генерирует таблицу со столбцами из синусоид с заданным количеством периодов,
    случайно изменяющейся амплитудой и случайно изменяющейся частотой.

    Параметры:
        keys - список из названий для столбцов. Тип - list.
        periods - количество периодов синусоиды. Значение по умолчанию: 20.
    Тип - int.
        amplitudes - список из двух значений амплитуд - минимальной и
    максимальной. Амплитуды будут генерироваться случайно, между двумя этими
    значениями. Значение по умолчанию: [1, 1.5]. Тип - list.
        frequencies - список из двух значений частот - минимальной и
    максимальной. Частоты будут генерироваться случайно, между двумя этими
    значениями. Значение по умолчанию: [1/6, 1/2]. Тип - list.
        ground - точка по оси y, относительно которой строится синусоида.
    Значение по умолчанию: 0. Тип - float.
        sample_rate - частота дискретизации сигнала синусоиды. Значение по
    умолчанию: 1e-2. Тип - float.

    Возвращает таблицу. Тип - pandas.DataFrame.
    """
    # Создание списка из синусоид
    xs = []
    for key in keys:
        xs.append(generate(periods, amplitudes, frequencies, ground, sample_rate))
    # Укорачивание списка из синусоид до длины меньшей синусоиды
    xs = reduce(xs)
    return createDF(xs, keys)
