Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion optic/comm/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ def monteCarloMI(rx, tx, M, constType, px=None):

for k in range(nModes):
σ2 = noiseVar[k]
MI[k] = calcMI(rx[:, k], tx[:, k], σ2, constSymb, px)
MI[k] = calcMI(rx[:, k], tx[:, k], σ2, constSymb, px)[0]
return MI


Expand Down
28 changes: 28 additions & 0 deletions tests/test_dsp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""
Test functions in dsp.py

"""

from optic.dsp.core import finddelay
import numpy as np


def test_finddelay_for_arrays_of_real_values():
delay = 35

a = np.arange(0, 100)
b = np.roll(a, -delay)

assert delay == finddelay(a, b)
assert delay == -finddelay(b, a)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Include tests for non-integer and negative delays.

The tests for finddelay function currently handle basic cases. Including scenarios with non-integer and negative delays could help in validating the function's robustness and correctness under more diverse conditions.

Suggested change
assert delay == -finddelay(b, a)
assert delay == -finddelay(b, a)
assert delay == -finddelay(b + 0.5, a) # Test with non-integer values
assert delay == -finddelay(b, a - 0.5) # Test with non-integer values

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment helpful?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the comment type correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the comment area correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this comment become an LLM test?



def test_finddelay_for_arrays_of_complex_values():
delay = 57

a = np.arange(0, 100) + 1j * np.arange(0, 100)
b = np.roll(a, -delay)

assert delay == finddelay(a, b)
assert delay == -finddelay(b, a)
97 changes: 97 additions & 0 deletions tests/test_metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import unittest

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider structuring tests to use test fixtures for common setup.

The setUp method is currently empty. Utilizing this for setting up common test parameters or objects used across multiple test methods can make the tests cleaner and reduce redundancy.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment helpful?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the comment type correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the comment area correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this comment become an LLM test?

import numpy as np
from optic.dsp.core import pnorm
from optic.models.channels import awgn
from optic.comm.modulation import modulateGray
from optic.comm.metrics import (
fastBERcalc,
calcLLR,
monteCarloGMI,
monteCarloMI,
Qfunc,
calcEVM,
theoryBER,
calcLinOSNR,
GN_Model_NyquistWDM,
ASE_NyquistWDM,
GNmodel_OSNR,
)

class TestCommunicationMetrics(unittest.TestCase):

def setUp(self):
# Set up common parameters or fixtures if needed
pass

def test_fastBERcalc(self):
# Add test cases for fastBERcalc

# Run BER vs Ebn0 Monte Carlo simulation in the AWGN channel

qamOrder = [4, 16, 64, 256] # Modulation order

EbN0dB_ = np.arange(10, 25.5, 0.5)
BER = np.zeros((len(EbN0dB_),len(qamOrder)))
BER_theory = np.zeros((len(EbN0dB_),len(qamOrder)))

for ii, M in enumerate(qamOrder):

for indSNR in range(EbN0dB_.size):

EbN0dB = EbN0dB_[indSNR]

# generate random bits
bitsTx = np.random.randint(2, size=int(np.log2(M)*1e5))

# Map bits to constellation symbols
symbTx = modulateGray(bitsTx, M, 'qam')

# Normalize symbols energy to 1
symbTx = pnorm(symbTx)

# AWGN channel
snrdB = EbN0dB + 10*np.log10(np.log2(M))
symbRx = awgn(symbTx, snrdB)

# BER calculation
BER[indSNR, ii] = fastBERcalc(symbRx, symbTx, M, 'qam')[0][0]
BER_theory[indSNR, ii] = theoryBER(M, EbN0dB, 'qam')

if BER[indSNR, ii] == 0:
break

np.testing.assert_array_almost_equal(BER, BER_theory, decimal=3)

def test_monteCarlo_MI_and_GMI(self):
# Run GMI vs SNR Monte Carlo simulation
qamOrder = [4, 16, 64] # Modulation order

SNR = np.arange(15, 26, 1)
MI = np.zeros((len(SNR),len(qamOrder)))
GMI = np.zeros((len(SNR),len(qamOrder)))

for ii, M in enumerate(qamOrder):
for indSNR in range(SNR.size):

snrdB = SNR[indSNR]

# generate random bits
bitsTx = np.random.randint(2, size=int(np.log2(M)*1e5))

# Map bits to constellation symbols
symbTx = modulateGray(bitsTx, M, 'qam')

# Normalize symbols energy to 1
symbTx = pnorm(symbTx)

# AWGN channel
symbRx = awgn(symbTx, snrdB)

# GMI estimation
MI[indSNR, ii] = monteCarloMI(symbRx, symbTx, M, 'qam')[0]
GMI[indSNR, ii] = monteCarloGMI(symbRx, symbTx, M, 'qam')[0][0]

np.testing.assert_array_almost_equal(MI, GMI, decimal=1)

if __name__ == '__main__':
unittest.main()
56 changes: 56 additions & 0 deletions tests/test_modulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import unittest
import numpy as np
from optic.utils import bitarray2dec, dec2bitarray
from optic.comm.modulation import grayCode, grayMapping, minEuclid, demap, modulateGray, demodulateGray

class TestModulationFunctions(unittest.TestCase):
def test_GrayCode(self):
# Test GrayCode function for different values of n
for n in range(1, 6):
with self.subTest(n=n):
result = grayCode(n)
self.assertEqual(len(result), 2**n)
self.assertEqual(len(result[0]), n)

def test_GrayMapping(self):
# Test GrayMapping function for different values of M and constType
M_values = [4, 16, 64]
constTypes = ['qam', 'psk', 'pam']
for M in M_values:
for constType in constTypes:
with self.subTest(M=M, constType=constType):
result = grayMapping(M, constType)
self.assertEqual(len(result), M)

def test_minEuclid(self):
# Test minEuclid function with some example inputs
symb = np.array([1+1j, 2+2j, 3+3j])
const = np.array([1+1j, 3+3j, 2+2j])
result = minEuclid(symb, const)
np.testing.assert_array_equal(result, np.array([0, 2, 1]))

def test_demap(self):
# Test demap function with some example inputs
indSymb = np.array([0, 2, 1])
bitMap = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
result = demap(indSymb, bitMap)
np.testing.assert_array_equal(result, np.array([0, 0, 1, 0, 0, 1]))

def test_modulateGray(self):
# Test modulateGray function with some example inputs
bits = np.array([0, 1, 0, 0, 1, 0])
M = 4
constType = 'qam'
result = modulateGray(bits, M, constType)
self.assertEqual(len(result), len(bits) // int(np.log2(M)))

def test_demodulateGray(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add assertions to verify the correctness of the output values.

The test for demodulateGray checks the length of the result but does not verify that the output values are correct. Adding assertions to check the actual demodulated bits against expected values would strengthen the test.

Suggested change
def test_demodulateGray(self):
def test_demodulateGray(self):
# Test demodulateGray function with some example inputs
symb = np.array([1+1j, 3+3j, 2+2j])
expected_bits = [0, 1, 3] # Example expected output
result = demodulateGray(symb, M)
self.assertEqual(result, expected_bits)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment helpful?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the comment type correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the comment area correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this comment become an LLM test?

# Test demodulateGray function with some example inputs
symb = np.array([1+1j, 3+3j, 2+2j])
M = 4
constType = 'qam'
result = demodulateGray(symb, M, constType)
self.assertEqual(len(result), len(symb) * int(np.log2(M)))

if __name__ == '__main__':
unittest.main()