# Source code for deltasigma._ds_quantize

# -*- coding: utf-8 -*-
# _ds_quantize.py
# This module provides the ds_quantize function.
# This file is part of python-deltasigma.
#
# python-deltasigma is a 1:1 Python replacement of Richard Schreier's
# MATLAB delta sigma toolbox (aka "delsigma"), upon which it is heavily based.
# The delta sigma toolbox is (c) 2009, Richard Schreier.
#
# python-deltasigma is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# LICENSE file for the licensing terms.

"""This module provides the ds_quantize() function, used to quantize signals
according to a user-specified quantizer characteristic.
"""

import numpy as np

[docs]def ds_quantize(y, n=2):
"""Quantize y

Quantize a vector :math:y to:

* an odd integer in :math:[-n+1, n-1], if :math:n is even, or
* an even integer in :math:[-n+1, n-1], if :math:n is odd.

The quantizer implementation details are repeated here from its
documentation for the user's convenience:

The quantizer is ideal, producing integer outputs centered
about zero. Quantizers with an even number of levels are of
the mid-rise type and produce outputs which are odd integers.
Quantizers with an odd number of levels are of the mid-tread
type and produce outputs which are even integers.

This definition gives the same step height for both mid-rise

.. image:: ../doc/_static/quantizer_model.png
:align: center
:alt: Quantizer model

**Parameters:**

n : int or ndarray, optional
The number of levels in the quantizer. If n is an integer,
then all rows of y are fed to the same quantizer.
If n is a column vector, each of its elements specifies
how to quantize the rows of y.

**Returns:**

v : ndarray
The quantized vector.

.. seealso::
:func:bquantize, :func:bunquantize

"""
assert (np.round(n, 0) == n).all()  # did we get an int or an array of int?
if not isinstance(n, np.ndarray):
n = n * np.ones(y.shape)  # we got an int
else:
assert len(n.shape) == 1 or 1 in n.shape
n = (np.ones((max(n.shape), y.shape[1])).T * n).T

i = (n % 2 == 0)
v = np.zeros(y.shape)
v[i] = 2 * np.floor(0.5 * y[i]) + 1     # mid-rise quantizer
v[~i] = 2 * np.floor(0.5 * (y[~i] + 1)) # mid-tread quantizer

# Limit the output
L = n - 1
for m in (-1, 1):
i = (m * v > L)
if i.any():
v[i] = m * L[i]
return v