peregrine/iqgen/bits/encoder_gps.py
class GPSL1BitEncoder(BandBitEncoder):
  '''
  Generic single bit encoder for GPS L1 C/A signal
  '''

  def __init__(self, outputConfig):
    '''
    Constructs GPS L1 C/A band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(GPSL1BitEncoder, self).__init__(outputConfig.GPS.L1.INDEX)
peregrine/iqgen/bits/encoder_2bits.py
class TwoBandsTwoBitsEncoder(Encoder):
  '''
  Generic single bit encoder for GPS L1 C/A and L2 Civil signals
  '''

  def __init__(self, bandIndex1, bandIndex2):
    '''
    Constructs GPS L1 C/A and L2 C dual band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(TwoBandsTwoBitsEncoder, self).__init__(BandTwoBitsEncoder.ATT_LVL_DB)
    self.l1Index = bandIndex1
    self.l2Index = bandIndex2

  def addSamples(self, sample_array):
    '''
    Extracts samples of the supported band and converts them into bit stream.

    Parameters
    ----------
    sample_array : numpy.ndarray((4, N))
      Sample vectors ordered by band index.

    Returns
    -------
    numpy.ndarray(dtype=numpy.uint8)
      Array of type uint8 containing the encoded data.
    '''
    band1_samples = sample_array[self.l1Index]
    band2_samples = sample_array[self.l2Index]
    n_samples = len(band1_samples)

    # Signal signs and amplitude
    signs1, amps1 = BandTwoBitsEncoder.convertBand(band1_samples)
    signs2, amps2 = BandTwoBitsEncoder.convertBand(band2_samples)

    self.ensureExtraCapacity(n_samples * 4)

    bits = self.bits
    start = self.n_bits
    end = start + 4 * n_samples
    bits[start + 0:end:4] = signs1
    bits[start + 1:end:4] = amps1
    bits[start + 2:end:4] = signs2
    bits[start + 3:end:4] = amps2
    self.n_bits = end

    if (self.n_bits >= Encoder.BLOCK_SIZE):
      return self.encodeValues()
    else:
      return Encoder.EMPTY_RESULT
peregrine/iqgen/bits/encoder_1bit.py
class BandBitEncoder(Encoder):
  '''
  Base class for single bit encoding.
  '''
  # Minimum is 1.96 dB. Can be up to 3.5 dB.
  # See Global Positioning System: Theory and Applications
  ATT_LVL_DB = 1.96

  def __init__(self, bandIndex):
    '''
    Initializes encoder object.

    Parameters
    ----------
    bandIndex : int
      Index of the band in the generated sample matrix.
    '''
    super(BandBitEncoder, self).__init__(attDb=BandBitEncoder.ATT_LVL_DB)
    self.bandIndex = bandIndex

  def addSamples(self, sample_array):
    '''
    Extracts samples of the supported band and coverts them into bit stream.

    Parameters
    ----------
    sample_array : numpy.ndarray((4, N))
      Sample vectors ordered by band index.

    Returns
    -------
    numpy.ndarray((N), dtype=numpy.uint8)
      Array of type uint8 containing the encoded data.
    '''
    band_samples = sample_array[self.bandIndex]
    n_samples = len(band_samples)

    self.ensureExtraCapacity(n_samples)
    start = self.n_bits
    end = start + n_samples
    self.bits[start:end] = BandBitEncoder.convertBand(band_samples)
    self.n_bits = end

    if (self.n_bits >= Encoder.BLOCK_SIZE):
      return self.encodeValues()

    return Encoder.EMPTY_RESULT

  @staticmethod
  def convertBand(band_samples):
    '''
    Helper method for converting sampled signal band into output bits.

    The samples are compared to 0. Positive values yield value of False.

    Parameters
    ----------
    band_samples : numpy.ndarray((N))
      Vector of signal samples

    Returns
    -------
    signs : numpy.ndarray((N), dtype=numpy.bool)
      Boolean vector of sample signs
    '''
    return band_samples < 0
peregrine/iqgen/bits/encoder_1bit.py
class TwoBandsBitEncoder(Encoder):
  '''
  Generic single bit encoder for two band signals
  '''

  def __init__(self, band1, band2):
    '''
    Constructs GPS L1 C/A and L2 C dual band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(TwoBandsBitEncoder, self).__init__(attDb=BandBitEncoder.ATT_LVL_DB)
    self.l1Index = band1
    self.l2Index = band2

  def addSamples(self, sample_array):
    '''
    Extracts samples of the supported band and converts them into bit stream.

    Parameters
    ----------
    sample_array : numpy.ndarray((4, N))
      Sample vectors ordered by band index.

    Returns
    -------
    numpy.ndarray(dtype=numpy.uint8)
      Array of type uint8 containing the encoded data.
    '''
    band1_bits = BandBitEncoder.convertBand(sample_array[self.l1Index])
    band2_bits = BandBitEncoder.convertBand(sample_array[self.l2Index])
    n_samples = len(band1_bits)

    self.ensureExtraCapacity(n_samples * 2)
    start = self.n_bits
    end = start + 2 * n_samples

    self.bits[start + 0:end:2] = band1_bits
    self.bits[start + 1:end:2] = band2_bits
    self.n_bits = end

    if (self.n_bits >= Encoder.BLOCK_SIZE):
      return self.encodeValues()
    else:
      return Encoder.EMPTY_RESULT
peregrine/iqgen/bits/encoder_gps.py
class GPSL2BitEncoder(BandBitEncoder):
  '''
  Generic single bit encoder for GPS L2 Civil signal
  '''

  def __init__(self, outputConfig):
    '''
    Constructs GPS L2 C band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(GPSL2BitEncoder, self).__init__(outputConfig.GPS.L2.INDEX)
peregrine/iqgen/bits/encoder_1bit.py
class FourBandsBitEncoder(Encoder):
  '''
  Generic single bit encoder for two band signals
  '''

  def __init__(self, band1, band2, band3, band4):
    '''
    Constructs GPS L1 C/A and L2 C dual band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(FourBandsBitEncoder, self).__init__(attDb=BandBitEncoder.ATT_LVL_DB)
    self.bandIndexes = [band1, band2, band3, band4]

  def addSamples(self, sample_array):
    '''
    Extracts samples of the supported band and converts them into bit stream.

    Parameters
    ----------
    sample_array : numpy.ndarray((4, N))
      Sample vectors ordered by band index.

    Returns
    -------
    numpy.ndarray(shape=(4, N/2), dtype=numpy.uint8)
      Array of type uint8 containing the encoded data.
    '''
    n_samples = len(sample_array[0])
    self.ensureExtraCapacity(n_samples * 4)
    start = self.n_bits
    end = start + 4 * n_samples

    for band in range(4):
      bandIndex = self.bandIndexes[band]
      band_bits = BandBitEncoder.convertBand(sample_array[bandIndex])
      self.bits[start + band:end:4] = band_bits

    self.n_bits = end

    if (self.n_bits >= Encoder.BLOCK_SIZE):
      return self.encodeValues()
    else:
      return Encoder.EMPTY_RESULT
peregrine/iqgen/if_iface.py
class NormalRateConfig(object):
  '''
  Output control configuration for normal tests.

  Attributes
  ----------
  NAME : string
    Configuration name
  SAMPLE_RATE_HZ : float
    Sample rate in hertz for data generation.
  SAMPLE_BATCH_SIZE : int
    Size of the sample batch in samples.
  N_GROUPS : int
    Number of groups in the configuration
  GROUP_DELAYS: tuple(float * 4)
    Group delays for the configuration
  GPS : object
    GPS band information
  Galileo : object
    Galileo band information
  Beidou : object
    Beidou band information
  GLONASS : object
    Glonass band information
  '''
  NAME = "Normal rate configuration equivalent to decimated data output"
  SAMPLE_RATE_HZ = 24.84375e6
  SAMPLE_BATCH_SIZE = 100000
  N_GROUPS = LowRateConfig.N_GROUPS
  GROUP_DELAYS = LowRateConfig.GROUP_DELAYS

  class GPS(object):
    '''
    Parameters for GPS bands data generation.
    '''
    class L1(object):
      INTERMEDIATE_FREQUENCY_HZ = freq_profile_normal_rate['GPS_L1_IF']
      INDEX = 0
      NAME = GPS_L1_NAME

    class L2(object):
      INTERMEDIATE_FREQUENCY_HZ = freq_profile_normal_rate['GPS_L2_IF']
      INDEX = 1
      NAME = GPS_L2_NAME

  class GLONASS(object):

    class L1(object):
      INTERMEDIATE_FREQUENCIES_HZ = \
          [float(12000000l + b * 562500l) for b in range(7)] + \
          [float(12000000l + b * 562500l) for b in range(-7, 0)]
      INDEX = 2
      NAME = GLONASS_L1_NAME

    class L2(object):
      INTERMEDIATE_FREQUENCIES_HZ = \
          [float(11000000l + b * 437500l) for b in range(7)] + \
          [float(11000000l + b * 437500l) for b in range(-7, 0)]
      INDEX = 3
      NAME = GLONASS_L2_NAME

  class Galileo(object):

    class E1(object):
      INTERMEDIATE_FREQUENCY_HZ = 14.58e6
      INDEX = 0
      NAME = GALILEO_E1_NAME

    class E6(object):
      INTERMEDIATE_FREQUENCY_HZ = 43.75e6
      INDEX = 2
      NAME = GALILEO_E6_NAME

    class E5b(object):
      INTERMEDIATE_FREQUENCY_HZ = 27.86e6
      INDEX = 3
      NAME = GALILEO_E5B_NAME

  class Beidou(object):

    class B1(object):
      INTERMEDIATE_FREQUENCY_HZ = 28.902e6
      INDEX = 0
      NAME = BEIDOU_B1_NAME

    class B2:
      INTERMEDIATE_FREQUENCY_HZ = 27.86e6
      INDEX = 3
      NAME = BEIDOU_B2_NAME

    class B3(object):
      INTERMEDIATE_FREQUENCY_HZ = 33.52e6
      INDEX = 2
      NAME = BEIDOU_B3_NAME
peregrine/iqgen/bits/encoder_gps.py
class GPSL1TwoBitsEncoder(BandTwoBitsEncoder):
  '''
  Generic single bit encoder for GPS L1 C/A signal
  '''

  def __init__(self, outputConfig):
    '''
    Constructs GPS L1 C/A band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(GPSL1TwoBitsEncoder, self).__init__(outputConfig.GPS.L1.INDEX)
peregrine/iqgen/bits/encoder_gps.py
class GPSL2TwoBitsEncoder(BandTwoBitsEncoder):
  '''
  Generic single bit encoder for GPS L2 Civil signal
  '''

  def __init__(self, outputConfig):
    '''
    Constructs GPS L2 C band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(GPSL2TwoBitsEncoder, self).__init__(outputConfig.GPS.L2.INDEX)
peregrine/iqgen/bits/encoder_base.py
class Encoder(object):
  '''
  Base encode class.

  Encoder accepts sequence of signal arrays as input and produces byte arrays
  as output.
  '''
  # Block size for encode. Must be a multiple of 8.
  BLOCK_SIZE = 1024 * 8

  EMPTY_RESULT = numpy.ndarray(0, dtype=numpy.uint8)  # Internal empty array

  def __init__(self, bufferSize=1000, attDb=0.):
    '''
    Constructs encoder.

    Parameters
    ----------
    bufferSize : int, optional
      Size of the internal buffer to batch-process samples
    attDb : float, optional
      Encoder attenuation level, optional
    '''
    self.bits = numpy.ndarray(bufferSize, dtype=numpy.int8)
    self.n_bits = 0
    self.attDb = attDb

  def addSamples(self, sample_array):
    '''
    Extracts samples of the supported band and converts them into bit stream.

    Parameters
    ----------
    sample_array : numpy.ndarray((4, N))
      Sample vectors ordered by band index.

    Returns
    -------
    numpy.ndarray(dtype=numpy.uint8)
      Array of type uint8 containing the encoded data.
    '''
    raise NotImplementedError()

  def flush(self):
    '''
    Flushes the data in the buffer.

    Returns
    -------
    ndarray
      Array of type uint8 containing the encoded data.
    '''
    if self.n_bits > 0 and self.n_bits % 8 != 0:
      self.n_bits += (8 - self.n_bits % 8)
    if self.n_bits:
      res = numpy.packbits(self.bits[0:self.n_bits])
      self.bits[0:self.n_bits].fill(0)
      self.n_bits = 0
      return res
    else:
      # Pack bits returns incorrect result in case of empty source bit set.
      return Encoder.EMPTY_RESULT

  def encodeValues(self):
    '''
    Converts buffered bit data into packed array.

    The method converts multiple of 8 bits into single output byte.

    Returns
    -------
    ndarray
      Array of type uint8 containing the encoded data.
    '''
    n_bytes = self.n_bits / 8
    n_offset = n_bytes * 8
    n_left = self.n_bits - n_offset
    res = numpy.packbits(self.bits[0: n_offset])
    self.bits[0:n_left] = self.bits[n_offset:n_offset + n_left]
    self.bits[n_left:].fill(0)
    self.n_bits = n_left
    return res

  def ensureExtraCapacity(self, extraBits):
    '''
    Method verifies that current array has sufficient capacity to hold
    additional bits.

    Parameters
    ----------
    extraBits : int
      Number of extra bits to reserve space for
    '''
    if len(self.bits) < self.n_bits + extraBits:
      self.bits.resize(self.n_bits + extraBits)

  def getAttenuationLevel(self):
    '''
    Method provides encoder attenuation level in dB.

    Returns
    -------
    float
      Encoder attenuation level. Positive value expected.
    '''
    return self.attDb
peregrine/iqgen/bits/encoder_2bits.py
class BandTwoBitsEncoder(Encoder):
  '''
  Base class for two bits encoding.
  '''
  # Minimum is 1.2 dB. Can be up to 3.5 dB.
  # See Global Positioning System: Theory and Applications
  ATT_LVL_DB = 1.2

  def __init__(self, bandIndex):
    '''
    Initializes encoder object.

    Parameters
    ----------
    bandIndex : int
      Index of the band in the generated sample matrix.
    '''
    super(BandTwoBitsEncoder, self).__init__(BandTwoBitsEncoder.ATT_LVL_DB)
    self.bandIndex = bandIndex

  @staticmethod
  def convertBand(band_samples):
    '''
    Helper method for converting sampled signal band into output bits.

    For the sign, the samples are compared to 0. Positive values yield sign of
    True.

    The method builds a power histogram from signal samples. After a histogram
    is built, the 67% power boundary is located. All samples, whose power is
    lower, than the boundary, are reported as False.

    Parameters
    ----------
    band_samples : numpy.ndarray
      Vector of signal samples

    Returns
    -------
    signs : numpy.ndarray(dtype=numpy.bool)
      Boolean vector of sample signs: True for positive, False for negative
    amps : numpy.ndarray(dtype=numpy.bool)
      Boolean vector of sample power: True for high power, False for low power
    '''

    # Signal power is a square of the amplitude
    power = numpy.square(band_samples)
    totalPower = numpy.sum(power)
    totalPowerLimit = totalPower * 0.67

    # Build histogram to find 67% power
    totalBins = 30
    hist, edges = numpy.histogram(power,
                                  bins=totalBins,
                                  density=False)
    avg = (edges[:-1] + edges[1:]) * 0.5
    powers = numpy.cumsum(hist * avg)
    idx = numpy.searchsorted(powers, totalPowerLimit, side="right")
    powerLimit = avg[idx]

    # Signal sign
    signs = band_samples > 0
    amps = power >= powerLimit

    return signs, amps

  def addSamples(self, sample_array):
    '''
    Extracts samples of the supported band and coverts them into bit stream.

    Parameters
    ----------
    sample_array : numpy.ndarray((4, N))
      Sample vectors ordered by band index.

    Returns
    -------
    numpy.ndarray(dtype=numpy.uint8)
      Array of type uint8 containing the encoded data.
    '''
    band_samples = sample_array[self.bandIndex]
    n_samples = len(band_samples)

    # Signal signs and amplitude
    signs, amps = self.convertBand(band_samples)

    self.ensureExtraCapacity(n_samples * 2)

    bits = self.bits
    start = self.n_bits
    end = start + n_samples * 2
    bits[start + 0:end:2] = signs
    bits[start + 1:end:2] = amps
    self.n_bits = end

    if (self.n_bits >= Encoder.BLOCK_SIZE):
      return self.encodeValues()
    else:
      return Encoder.EMPTY_RESULT
peregrine/iqgen/bits/encoder_gps.py
class GPSL1L2TwoBitsEncoder(TwoBandsTwoBitsEncoder):
  '''
  Generic single bit encoder for GPS L1 C/A and L2 Civil signals
  '''

  def __init__(self, outputConfig):
    '''
    Constructs GPS L1 C/A and L2 C dual band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(GPSL1L2TwoBitsEncoder, self).__init__(outputConfig.GPS.L1.INDEX,
                                                outputConfig.GPS.L2.INDEX)
peregrine/iqgen/bits/encoder_gps.py
class GPSL1L2BitEncoder(TwoBandsBitEncoder):
  '''
  Generic single bit encoder for GPS L1 C/A and L2 Civil signals
  '''

  def __init__(self, outputConfig):
    '''
    Constructs GPS L1 C/A and L2 C dual band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(GPSL1L2BitEncoder, self).__init__(outputConfig.GPS.L1.INDEX,
                                            outputConfig.GPS.L2.INDEX)
peregrine/iqgen/bits/encoder_2bits.py
class FourBandsTwoBitsEncoder(Encoder):
  '''
  Generic single bit encoder for two band signals
  '''

  def __init__(self, band1, band2, band3, band4):
    '''
    Constructs GPS L1 C/A and L2 C dual band single bit encoder object.

    Parameters
    ----------
    outputConfig : object
      Output parameters object.
    '''
    super(FourBandsTwoBitsEncoder, self).__init__(
        BandTwoBitsEncoder.ATT_LVL_DB)
    self.bandIndexes = [band1, band2, band3, band4]

  def addSamples(self, sample_array):
    '''
    Extracts samples of the supported bands and converts them into bit stream.

    Parameters
    ----------
    sample_array : numpy.ndarray((4, N))
      Sample vectors ordered by band index.

    Returns
    -------
    numpy.ndarray(dtype=numpy.uint8)
      Array of type uint8 containing the encoded data.
    '''
    n_samples = len(sample_array[0])
    self.ensureExtraCapacity(n_samples * 8)
    start = self.n_bits
    end = start + 8 * n_samples
    bits = self.bits

    for band in range(4):
      bandIndex = self.bandIndexes[band]
      # Signal signs and amplitude
      signs, amps = BandTwoBitsEncoder.convertBand(sample_array[bandIndex])
      bits[start + band * 2 + 0:end:8] = signs
      bits[start + band * 2 + 1:end:8] = amps

    self.n_bits = end

    if (self.n_bits >= Encoder.BLOCK_SIZE):
      return self.encodeValues()
    else:
      return Encoder.EMPTY_RESULT


Question: from peregrine.iqgen.bits.encoder_base import Encoder as EncoderBase
from peregrine.iqgen.bits.encoder_1bit import BandBitEncoder
from peregrine.iqgen.bits.encoder_1bit import TwoBandsBitEncoder
from peregrine.iqgen.bits.encoder_1bit import FourBandsBitEncoder
from peregrine.iqgen.bits.encoder_2bits import BandTwoBitsEncoder
from peregrine.iqgen.bits.encoder_2bits import TwoBandsTwoBitsEncoder
from peregrine.iqgen.bits.encoder_2bits import FourBandsTwoBitsEncoder
from peregrine.iqgen.bits.encoder_gps import GPSL1BitEncoder
from peregrine.iqgen.bits.encoder_gps import GPSL2BitEncoder
from peregrine.iqgen.bits.encoder_gps import GPSL1L2BitEncoder
from peregrine.iqgen.bits.encoder_gps import GPSL1TwoBitsEncoder
from peregrine.iqgen.bits.encoder_gps import GPSL2TwoBitsEncoder
from peregrine.iqgen.bits.encoder_gps import GPSL1L2TwoBitsEncoder
from peregrine.iqgen.if_iface import NormalRateConfig
import numpy
  assert len(converted) == 0
  assert converted.dtype == numpy.uint8
  assert encoder.n_bits == 4


def test_TwoBandsTwoBitsEncoder_init():
  '''
  Test dual bit two band encoder constructor
  '''
  encoder = TwoBandsTwoBitsEncoder(0, 1)
  assert encoder.l1Index == 0
  assert encoder.l2Index == 1
  encoder = TwoBandsTwoBitsEncoder(1, 0)
  assert encoder.l1Index == 1
  assert encoder.l2Index == 0


def test_TwoBandsTwoBitsEncoder_addSamples0():
  '''
  Test dual bit encoder samples adding and conversion
  '''
  encoder = TwoBandsTwoBitsEncoder(0, 1)
  samples = numpy.ndarray((2, EncoderBase.BLOCK_SIZE + 1), dtype=numpy.float)
  samples[0].fill(-1.)
  samples[1].fill(1.)
  converted = encoder.addSamples(samples)
  assert len(converted) == len(samples[0]) / 2
  assert converted.dtype == numpy.uint8
  assert (converted == 0x22).all()
  converted = encoder.flush()
  assert len(converted) == 1
  assert converted.dtype == numpy.uint8
  assert converted[0] == 0x20


def test_TwoBandsTwoBitsEncoder_addSamples1():
  '''
  Test dual bit encoder samples adding and conversion
  '''
  encoder = TwoBandsTwoBitsEncoder(0, 1)
  samples = numpy.ndarray((2, 2), dtype=numpy.float)
  samples[0].fill(-1.)
  samples[1].fill(1.)
  converted = encoder.addSamples(samples)
  assert len(converted) == 0
  assert converted.dtype == numpy.uint8
  assert encoder.n_bits == 8


def test_FourBandsTwoBitsEncoder_init():
  '''
  Test dual bit four band encoder constructor
  '''
  encoder = FourBandsTwoBitsEncoder(0, 1, 2, 3)
  assert encoder.bandIndexes[0] == 0
  assert encoder.bandIndexes[1] == 1
  assert encoder.bandIndexes[2] == 2
  assert encoder.bandIndexes[3] == 3
  encoder = FourBandsTwoBitsEncoder(3, 2, 1, 0)
  assert encoder.bandIndexes[0] == 3
  assert encoder.bandIndexes[1] == 2
  assert encoder.bandIndexes[2] == 1
  assert encoder.bandIndexes[3] == 0


def test_FourBandsTwoBitsEncoder_addSamples0():
  '''
  Test dual bit encoder samples adding and conversion
  '''
  encoder = FourBandsTwoBitsEncoder(0, 1, 0, 1)
  samples = numpy.ndarray((2, EncoderBase.BLOCK_SIZE + 1), dtype=numpy.float)
  samples[0].fill(-1.)
  samples[1].fill(1.)
  converted = encoder.addSamples(samples)
  assert len(converted) == len(samples[0])
  assert converted.dtype == numpy.uint8
  assert (converted == 0x22).all()
  converted = encoder.flush()
  assert len(converted) == 0
  assert converted.dtype == numpy.uint8


def test_FourBandsTwoBitsEncoder_addSamples1():
  '''
  Test single bit encoder samples adding and conversion
  '''
  encoder = FourBandsTwoBitsEncoder(0, 1, 0, 1)
  samples = numpy.ndarray((2, 1), dtype=numpy.float)
  samples[0].fill(-1.)
  samples[1].fill(1.)
  converted = encoder.addSamples(samples)
  assert len(converted) == 0
  assert converted.dtype == numpy.uint8
  assert encoder.n_bits == 8


def test_GPSL1BitEncoder_init():
  '''
  Test construction of GPS L1 single bit encoder
  '''
  encoder = GPSL1BitEncoder(NormalRateConfig)
  assert isinstance(encoder, EncoderBase)
  assert isinstance(encoder, BandBitEncoder)
  assert encoder.bandIndex == NormalRateConfig.GPS.L1.INDEX


def test_GPSL2BitEncoder_init():
  '''
  Test construction of GPS L2 single bit encoder
  '''
  encoder = GPSL2BitEncoder(NormalRateConfig)
  assert isinstance(encoder, EncoderBase)
  assert isinstance(encoder, BandBitEncoder)
  assert encoder.bandIndex == NormalRateConfig.GPS.L2.INDEX


def test_GPSL1L2BitEncoder_init():
  '''
  Test construction of GPS L1/L2 single bit dual band encoder
  '''

Answer:   encoder = GPSL1L2BitEncoder(NormalRateConfig)