# Path: pyphysim/util/conversion.py
# def binary2gray(num: IntOrIntArray) -> IntOrIntArray:
#     """
#     Convert a number (in decimal format) to the corresponding Gray code
#     (still in decimal format).
# 
#     Parameters
#     ----------
#     num : int | np.ndarray
#         The number in decimal encoding
# 
#     Returns
#     -------
#     num_gray : int | np.ndarray
#         Corresponding gray code (in decimal format) of `num`.
# 
#     Examples
#     --------
#     >>> binary2gray(np.arange(0, 8))
#     array([0, 1, 3, 2, 6, 7, 5, 4])
#     """
#     return xor((num >> 1), num)
# 
# def dB2Linear(valueIndB: NumberOrArray) -> NumberOrArray:
#     """
#     Convert input from dB to linear scale.
# 
#     Parameters
#     ----------
#     valueIndB : int | float | np.ndarray
#         Value in dB
# 
#     Returns
#     -------
#     valueInLinear : int | float | np.ndarray
#         Value in Linear scale.
# 
#     Examples
#     --------
#     >>> dB2Linear(30)
#     1000.0
#     """
#     return pow(10, valueIndB / 10.0)
# 
# def gray2binary(num: IntOrIntArray) -> IntOrIntArray:
#     """
#     Convert a number in Gray code (in decimal format) to its original
#     value (in decimal format).
# 
#     Parameters
#     ----------
#     num : int | np.ndarray
#         The number in gray coding
# 
#     Returns
#     -------
#     num_orig : int | np.ndarray
#         The original number (in decimal format) whose Gray code
#         correspondent is `num`.
# 
#     Examples
#     --------
#     >>> gray2binary(binary2gray(np.arange(0,10)))
#     array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 
#     """
#     temp = xor(num, (num >> 8))
#     temp = xor(temp, (temp >> 4))
#     temp = xor(temp, (temp >> 2))
#     temp = xor(temp, (temp >> 1))
# 
#     return temp
# 
# Path: pyphysim/util/misc.py
# def level2bits(n: int) -> int:
#     """
#     Calculates the number of bits needed to represent n different
#     values.
# 
#     Parameters
#     ----------
#     n : int
#         Number of different levels.
# 
#     Returns
#     -------
#     num_bits : int
#         Number of bits required to represent `n` levels.
# 
#     Examples
#     --------
#     >>> list(map(level2bits,range(1,20)))
#     [1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5]
#     """
#     if n < 1:
#         raise ValueError("level2bits: n must be greater then one")
#     return int2bits(n - 1)
# 
# def qfunc(x: float) -> float:
#     """
#     Calculates the 'q' function of x.
# 
#     Parameters
#     ----------
#     x : float
#         The value to apply the Q function.
# 
#     Returns
#     -------
#     result : float
#         Qfunc(x)
# 
#     Examples
#     --------
#     >>> qfunc(0.0)
#     0.5
#     >>> round(qfunc(1.0), 9)
#     0.158655254
#     >>> round(qfunc(3.0), 9)
#     0.001349898
#     """
#     return cast(float, 0.5 * erfc(x / math.sqrt(2)))


    import matplotlib.pyplot as plt
import math
import numpy as np
from typing import Optional, TypeVar, Union
from pyphysim.util.conversion import binary2gray, dB2Linear, gray2binary
from pyphysim.util.misc import level2bits, qfunc
    def setConstellation(self, symbols: np.ndarray) -> None:
        """
        Set the constellation of the modulator.

        This function should be called in the constructor of the derived
        classes.

        Parameters
        ----------
        symbols : np.ndarray
            A an numpy array with the symbol table.
        """
        M = symbols.size
        self._M = M
        self._K = np.log2(M)
        self.symbols = symbols

    def plotConstellation(self) -> None:  # pragma: no cover
        """Plot the constellation (in a scatter plot).
        """
        fig = plt.figure()
        ax = fig.add_subplot(1, 1, 1)  # one row, one column, first plot
        # circlePatch = patches.Circle((0,0),1)
        # circlePatch.set_fill(False)
        # ax.add_patch(circlePatch)
        ax.scatter(self.symbols.real, self.symbols.imag)

        ax.axis('equal')
        ax.grid()


# Path: pyphysim/util/conversion.py
# def binary2gray(num: IntOrIntArray) -> IntOrIntArray:
#     """
#     Convert a number (in decimal format) to the corresponding Gray code
#     (still in decimal format).
# 
#     Parameters
#     ----------
#     num : int | np.ndarray
#         The number in decimal encoding
# 
#     Returns
#     -------
#     num_gray : int | np.ndarray
#         Corresponding gray code (in decimal format) of `num`.
# 
#     Examples
#     --------
#     >>> binary2gray(np.arange(0, 8))
#     array([0, 1, 3, 2, 6, 7, 5, 4])
#     """
#     return xor((num >> 1), num)
# 
# def dB2Linear(valueIndB: NumberOrArray) -> NumberOrArray:
#     """
#     Convert input from dB to linear scale.
# 
#     Parameters
#     ----------
#     valueIndB : int | float | np.ndarray
#         Value in dB
# 
#     Returns
#     -------
#     valueInLinear : int | float | np.ndarray
#         Value in Linear scale.
# 
#     Examples
#     --------
#     >>> dB2Linear(30)
#     1000.0
#     """
#     return pow(10, valueIndB / 10.0)
# 
# def gray2binary(num: IntOrIntArray) -> IntOrIntArray:
#     """
#     Convert a number in Gray code (in decimal format) to its original
#     value (in decimal format).
# 
#     Parameters
#     ----------
#     num : int | np.ndarray
#         The number in gray coding
# 
#     Returns
#     -------
#     num_orig : int | np.ndarray
#         The original number (in decimal format) whose Gray code
#         correspondent is `num`.
# 
#     Examples
#     --------
#     >>> gray2binary(binary2gray(np.arange(0,10)))
#     array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 
#     """
#     temp = xor(num, (num >> 8))
#     temp = xor(temp, (temp >> 4))
#     temp = xor(temp, (temp >> 2))
#     temp = xor(temp, (temp >> 1))
# 
#     return temp
# 
# Path: pyphysim/util/misc.py
# def level2bits(n: int) -> int:
#     """
#     Calculates the number of bits needed to represent n different
#     values.
# 
#     Parameters
#     ----------
#     n : int
#         Number of different levels.
# 
#     Returns
#     -------
#     num_bits : int
#         Number of bits required to represent `n` levels.
# 
#     Examples
#     --------
#     >>> list(map(level2bits,range(1,20)))
#     [1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5]
#     """
#     if n < 1:
#         raise ValueError("level2bits: n must be greater then one")
#     return int2bits(n - 1)
# 
# def qfunc(x: float) -> float:
#     """
#     Calculates the 'q' function of x.
# 
#     Parameters
#     ----------
#     x : float
#         The value to apply the Q function.
# 
#     Returns
#     -------
#     result : float
#         Qfunc(x)
# 
#     Examples
#     --------
#     >>> qfunc(0.0)
#     0.5
#     >>> round(qfunc(1.0), 9)
#     0.158655254
#     >>> round(qfunc(3.0), 9)
#     0.001349898
#     """
#     return cast(float, 0.5 * erfc(x / math.sqrt(2)))


# Path: pyphysim/modulators/fundamental.py
    import matplotlib.pyplot as plt
import math
import numpy as np
from typing import Optional, TypeVar, Union
from pyphysim.util.conversion import binary2gray, dB2Linear, gray2binary
from pyphysim.util.misc import level2bits, qfunc

    def setConstellation(self, symbols: np.ndarray) -> None:
        """
        Set the constellation of the modulator.

        This function should be called in the constructor of the derived
        classes.

        Parameters
        ----------
        symbols : np.ndarray
            A an numpy array with the symbol table.
        """
        M = symbols.size
        self._M = M
        self._K = np.log2(M)
        self.symbols = symbols

    def plotConstellation(self) -> None:  # pragma: no cover
        """Plot the constellation (in a scatter plot).
        """
        fig = plt.figure()
        ax = fig.add_subplot(1, 1, 1)  # one row, one column, first plot
        # circlePatch = patches.Circle((0,0),1)
        # circlePatch.set_fill(False)
        # ax.add_patch(circlePatch)
        ax.scatter(self.symbols.real, self.symbols.imag)

        ax.axis('equal')
        ax.grid()


        formatString = "{0:0=" + str(level2bits(self._M)) + "b} ({0})"