def test_pulse_with_viterbi():
    """

    :return:
    """
    """
    Generate symbol stream
    """
    tolerance = 1e-3

    number_symbols = 20
    channel = np.zeros((1, 8))
    channel[0, [0, 3, 4, 5]] = 1, 0.5, 0.1, 0.2
    # TODO consolidate this part

    data_gen = training_data_generator(symbol_stream_shape=(1, number_symbols),
                                       channel=channel,
                                       SNR=50,
                                       plot=True,
                                       sampling_period=1,
                                       symbol_period=12)
    data_gen.random_symbol_stream()
    channel_length = 1
    channel_real = pulse_shapes.dirac_channel()  #channel length 1 for dirac
    data_gen.setup_real_channel(channel_real, 1)
    """
    Modulate symbols onto fundamental pulse
    """
    fundamental_pulse = rect_function_class  #Note the passed function here cannot be a lambda function
    parameters = 1 / 12
    data_gen.modulate_version3(fundamental_pulse, parameters)
    """
     Send modulated signal through channel
     """
    data_gen.sample_modulated_function()
    data_gen.convolve_sampled_modulated()
    """
    Setup Receive Filter
    """
    receive_filter = pulse_shapes.rect_receiver_class(1 / 12)
    data_gen.setup_receive_filter(receive_filter)
    data_gen.filter_received_modulated_signal()
    """
    Viterbi Performance with demodulated symbols from sampled transmission
    """
    metric = GaussianChannelMetric(channel, data_gen.demodulated_symbols)
    detected = viterbi_setup_with_nodes(data_gen.alphabet,
                                        data_gen.demodulated_symbols,
                                        channel_length, metric.metric)
    ser_sampled_symbols = symbol_error_rate(detected,
                                            data_gen.symbol_stream_matrix)

    assert ser_sampled_symbols < tolerance
def test_viterbi_net_class():
    """
    Train and save the neural network
    :return:
    """
    """
    setup paths
    """
    """
    Testing the setup and training of a neural network using the viterbiNet Architecture
    :return:
    """
    """
    Choose platform
    """
    device = torch.device("cpu")

    # device = torch.device('cuda') # Uncomment this to run on GPU
    """
    Setup Training Data
    """
    number_symbols = 100

    # channel = np.zeros((1, 5))
    # channel[0, [0, 3, 4]] = 1, 0.5, 0.4

    channel = np.zeros((1, 6))
    channel[0, [0, 1, 2, 3, 4]] = 1, 0.6, 0.3, 0.6, 0.3

    test = random_channel
    check = []
    for i in range(10):
        check.append(test())

    # channel = np.zeros((1, 1))
    # channel[0, 0] = 1

    data_gen = training_data_generator(
        symbol_stream_shape=(1, number_symbols),
        SNR=5,
        plot=True,
        channel=channel,
    )
    # data_gen.setup_channel(shape=None)
    data_gen.random_symbol_stream()
    data_gen.send_through_channel()
    """
    After sending through channel, symbol detection should be performed using something like a matched filter
    """

    x, y = data_gen.get_labeled_data()
    y = np.argmax(
        y, axis=1
    )  # Fix for how the pytorch Cross Entropy expects class labels to be shown
    x = torch.Tensor(x)
    y = torch.Tensor(y)
    train_size = int(.6 * number_symbols)
    x_train = x[0:train_size, :]
    x_test = x[train_size::, :]
    y_train = y[0:train_size]
    y_test = y[train_size::]
    """
    Setup NN and optimizer
    """
    m = data_gen.alphabet.size
    channel_length = data_gen.CIR_matrix.shape[1]

    # N is batch size; D_in is input dimension;
    # H is hidden dimension; D_out is output dimension.
    N, D_in, H1, H2, D_out = number_symbols, 1, 100, 50, np.power(
        m, channel_length)
    N, D_in, H1, H2, H3, D_out = number_symbols, 1, 20, 10, 10, np.power(
        m, channel_length)

    net = models.ViterbiNetDeeper(D_in, H1, H2, H3, D_out)
    #TODO use better optimizer
    optimizer = optim.Adam(net.parameters(), lr=1e-3)
    """
    Train NN
    """
    # criterion = nn.CrossEntropyLoss()
    criterion = nn.NLLLoss()
    train_cost_over_epoch = []
    test_cost_over_epoch = []

    # If training is perfect, then NN should be able to perfectly predict the class to which a test set belongs and thus the loss (KL Divergence) should be zero
    for t in range(2000):
        output = net(x_train)
        loss = criterion(output, y_train.long())
        train_cost_over_epoch.append(loss)
        net.zero_grad()
        print(loss)
        loss.backward()
        optimizer.step()
        test_cost_over_epoch.append(criterion(net(x_test), y_test.long()))

    path = "Output/nn.pt"
    test = os.getcwd()
    # path = '/Users/peterhartig/Documents/Projects/moco_project/molecular-communications-project/Output/nn.pt'
    torch.save(net, path)
    """
    Test NN
    """
    plt.figure()
    plt.plot(test_cost_over_epoch, label='Test Error')
    plt.plot(train_cost_over_epoch, label='Train Error')
    plt.title("Error over epochs")
    plt.xlabel("Epoch")
    plt.ylabel("Error")
    plt.legend(loc='upper left')
    path = "Output/Neural_Network_Convergence.png"
    plt.savefig(path, format="png")
    plt.figure()

    assert True
Example #3
0
def test_pulse_with_viterbi():
    """

    :return:
    """
    """
    Generate symbol stream
    """
    number_symbols = 20
    channel = np.zeros((1, 8))
    channel[0, [0, 3, 4, 5]] = 1, 0.5, 0.1, 0.2
    # TODO consolidate this part
    data_gen = training_data_generator(symbol_stream_shape=(1, number_symbols),
                                       SNR=2,
                                       channel=channel,
                                       plot=True,
                                       sampling_period=1,
                                       symbol_period=11)
    data_gen.random_symbol_stream()
    """
    Modulate symbols onto fundamental pulse
    """
    fundamental_pulse = pulse_shapes.rect_function_class(1 / 10)
    data_gen.modulate_fundamental_pulse(fundamental_pulse)
    """
    Setup Channel function
    """
    # channel = pulse_shapes.rect_function_class(1/10)
    # data_gen.setup_real_channel(channel, 5)
    channel_real = pulse_shapes.dirac_channel()
    data_gen.setup_real_channel(channel_real, 1)
    corresponding_channel = np.zeros((1, 8))
    channel[0, [0, 3, 4, 5]] = 1, 0.5, 0.1, 0.2
    """
     Send modulated signal through channel
     """
    data_gen.send_through_channel()
    data_gen.transmit_modulated_signal()
    """
    Setup Receive Filter
    """
    receive_filter = pulse_shapes.rect_function_class(1 / 10)
    data_gen.setup_receive_filter(receive_filter)
    data_gen.filter_received_modulated_signal()
    # data_gen.plot_setup()
    """
    Viterbi Performance with demodulated symbols from sampled transmission
    """
    states = []
    item = []
    get_combinatoric_list(data_gen, channel_length, states, item)

    metric = GaussianChannelMetric(channel, data_gen.demodulated_symbols)
    detected = viterbi_setup_with_nodes(data_gen.alphabet,
                                        data_gen.demodulated_symbols,
                                        data_gen.CIR_matrix.shape[1],
                                        metric.metric)
    ser_sampled_symbols = symbol_error_rate(detected,
                                            data_gen.symbol_stream_matrix)
    """
    Viterbi Performance with demodulated symbols from sampled transmission
    """

    metric = GaussianChannelMetric(channel, data_gen.channel_output)
    detected = viterbi_setup_with_nodes(data_gen.alphabet,
                                        data_gen.channel_output,
                                        data_gen.CIR_matrix.shape[1],
                                        metric.metric)
    ser_symbols = symbol_error_rate(detected, data_gen.symbol_stream_matrix)

    assert True
def test_dynamic_pulse():
    """

    :return:
    """
    """
    Generate symbol stream
    """
    tolerance = 1e-3

    number_symbols = 10
    channel = np.zeros((1, 2))
    channel[0, [0, 1]] = 1, 1
    data_gen = training_data_generator(symbol_stream_shape=(1, number_symbols),
                                       SNR=2,
                                       plot=True,
                                       sampling_period=1,
                                       symbol_period=10)
    data_gen.random_symbol_stream()
    channel_length = 2
    """
    Setup channel to convolve with
    """
    channel_real = pulse_shapes.rect_receiver_class(
        1 / 5)  #channel length 1 for dirac
    # channel_real = pulse_shapes.dirac_channel() #channel length 1 for dirac

    data_gen.setup_real_channel(channel_real, channel_length)
    """
    Modulate symbols onto fundamental pulse
    """
    fundamental_pulse = dynamic_pulse  #Note the passed function here cannot be a lambda function
    parameters = 1 / 10
    data_gen.modulate_version3(fundamental_pulse, parameters)
    """
     Send modulated signal through channel
     """
    data_gen.transmit_modulated_signal2()
    data_gen.sample_modulated_function()
    data_gen.plot_setup()
    """
    Setup Receive Filter
    """

    receive_filter = pulse_shapes.rect_receiver_class(1 / 10)
    data_gen.setup_receive_filter(receive_filter)
    data_gen.filter_received_modulated_signal()
    """
    Viterbi Performance with demodulated symbols from sampled transmission
    Note that in this case, the receiver is not needed as the viterbi metrics are taken against the over-sampled version
    of the impulse response.
    """
    fundamental_pulse = dynamic_pulse  #Note the passed function here cannot be a lambda function
    parameters = 1 / 10
    data_gen.gaussian_channel_metric_sampled(fundamental_pulse, parameters)
    metric = data_gen.metric_cost_sampled
    detected = viterbi_setup_with_nodes(data_gen.alphabet,
                                        data_gen.demodulated_symbols,
                                        channel_length, metric)
    metric = GaussianChannelMetric(channel, data_gen.demodulated_symbols)
    detected = viterbi_setup_with_nodes(data_gen.alphabet,
                                        data_gen.demodulated_symbols,
                                        channel_length, metric.metric)
    ser_sampled_symbols = symbol_error_rate(detected,
                                            data_gen.symbol_stream_matrix)

    assert ser_sampled_symbols < tolerance
def test_em_real_channel():
    vec = np.linspace(-3, 3, 100)
    samples = []
    for i in vec:
        samples.append(probability_from_gaussian_sources(i, 0, .1))
    plt.plot(vec, samples)
    # plt.show()
    """
    The goal of this test is to ensure that the implemented EM algorithm converges to the correct parameters used to
    to generate a set of data that is then fed into the algorithm.
    :return:
    """
    tolerance = np.power(10.0, -3)
    """
    Setup Training Data
    """
    #EM is stable to number of training examples TODO see when not stable to number of iterations
    number_symbols = 1000

    # channel = np.zeros((1, 5))
    # channel[0, [0, 3, 4]] = 1, 0.5, 0.4

    channel = np.zeros((1, 3))
    channel[0, [0, 1, 2]] = 1, 0.6, 0.3

    # channel = np.zeros((1, 1))
    # channel[0, 0] = 1

    data_gen = training_data_generator(
        symbol_stream_shape=(1, number_symbols),
        SNR=2,
        plot=True,
        channel=channel,
    )
    # data_gen.setup_channel(shape=None)
    data_gen.random_symbol_stream()
    data_gen.send_through_channel()
    num_sources = pow(data_gen.alphabet.size, data_gen.CIR_matrix.shape[1])
    true_variance = 0
    true_mu = 0
    true_alpha = np.ones((1, num_sources)) / num_sources

    # generate data from a set of gaussians
    data = data_gen.channel_output.flatten()
    data_gen.random_symbol_stream()
    data_gen.send_through_channel()
    test_data = data_gen.channel_output.flatten()
    """
    Train Mixture Model
    """
    model, mu, variance, alpha, total_sequence_probability, test_sequence_probability = \
        em_gausian(num_sources, data, 10, test_data=test_data, save=True, both=True)
    """
    Plot Results
    """

    plt.figure()
    plt.plot(total_sequence_probability, label='training_probability')
    plt.plot(test_sequence_probability, label='test_probability')
    path = "Output/Mixture_Model_" + str(time.time()) + "_Convergence.png"
    plt.title("Error over epochs")
    plt.xlabel("Iteration")
    plt.ylabel("Log Probability of Data set")
    plt.legend(loc='upper left')
    plt.savefig(path, format="png")

    # error_mu = np.linalg.norm(np.sort(mu)-np.sort(true_mu))
    # error_variance = np.linalg.norm(np.sort(variance)-np.sort(true_variance))
    # error_alpha = np.linalg.norm(np.sort(true_alpha) - np.sort(alpha))
    """
    Want to plot the probability of a train and test set during each iteration
    """
    # assert error_mu < tolerance and error_variance < tolerance and error_alpha < tolerance
    assert True  #TODO decide on pass criteria
def test_results_nerual_net():
    """
    Train and save the neural network
    :return:
    """
    """
    Choose platform
    """
    device = torch.device("cpu")
    # device = torch.device('cuda') # Uncomment this to run on GPU
    """
    Setup Training Data
    """
    number_symbols = 5000
    channel = np.zeros((1, 4))
    channel[0, [0, 1, 2, 3]] = 1, 0.6, 0.3, 0.2
    data_gen = training_data_generator(symbol_stream_shape=(1, number_symbols),
                                       SNR=4,
                                       plot=True,
                                       channel=channel)
    # data_gen.setup_channel(shape=None)
    data_gen.random_symbol_stream()
    data_gen.send_through_channel()
    """
    After sending through channel, symbol detection should be performed using something like a matched filter
    """
    num_inputs_for_training_data = 1
    x, y = data_gen.get_labeled_data(inputs=num_inputs_for_training_data)
    y = np.argmax(
        y, axis=1
    )  # Fix for how the pytorch Cross Entropy expects class labels to be shown
    x = torch.Tensor(x)
    y = torch.Tensor(y)
    train_size = int(.6 * number_symbols)
    x_train = x[0:train_size, :]
    x_test = x[train_size::, :]
    y_train = y[0:train_size]
    y_test = y[train_size::]
    """
    Setup NN and optimizer
    """
    m = data_gen.alphabet.size
    channel_length = data_gen.CIR_matrix.shape[1]

    # N is batch size; D_in is input dimension;
    # H is hidden dimension; D_out is output dimension.
    N, D_in, H1, H2, D_out = number_symbols, num_inputs_for_training_data, 100, 50, np.power(
        m, channel_length)

    net = models.ViterbiNet(D_in, H1, H2, D_out)
    #TODO use better optimizer
    optimizer = optim.SGD(net.parameters(), lr=1e-2)
    optimizer = optim.Adam(net.parameters(), lr=1e-2)
    """
    Train NN
    """
    criterion = nn.CrossEntropyLoss()
    # criterion = nn.NLLLoss()
    train_cost_over_epoch = []
    test_cost_over_epoch = []

    # If training is perfect, then NN should be able to perfectly predict the class to which a test set belongs and thus the loss (KL Divergence) should be zero
    for t in range(400):
        output = net(x_train)
        loss = criterion(output, y_train.long())
        train_cost_over_epoch.append(loss)
        net.zero_grad()
        print(loss)
        loss.backward()
        optimizer.step()
        test_cost_over_epoch.append(criterion(net(x_test), y_test.long()))

    path = "Output/nn.pt"
    torch.save(net, path)
    """
    Test NN
    """
    plt.figure()
    plt.plot(test_cost_over_epoch, label='Test Error')
    plt.plot(train_cost_over_epoch, label='Train Error')
    plt.title(str(data_gen.get_info_for_plot()), fontdict={'fontsize': 10})
    plt.xlabel("Epoch")
    plt.ylabel("Error")
    plt.legend(loc='upper left')
    path = "Output/Neural_Network_Convergence.png"
    path = "Output/NN_ERROR" + str(number_symbols) + " symbols " \
           + str(num_inputs_for_training_data) + " inputs " + str(time.time())+"curves.png"
    plt.savefig(path, format="png")
    plt.show()
    assert True