NQLib documentation¶
NQLib¶
NQLib is a Python library to design noise shaping quantizer for discrete-valued input control.
## What can I do with NQLib?
In the real world, a dynamic system may have to be controlled by discrete-valued signals due to the inclusion of actuators that are driven by ON/OFF or network with capacity limitations. In such a case, a good output may be obtained by converting continuous-valued input to discrete-valued input with a quantizer designed by NQLib.
## Documentation
All the documentation is available at https://knttnk.github.io/NQLib/.
Examples of usage are available at https://colab.research.google.com/drive/1Ui-XqaTZCjwqRXC3ZeMeMCbPqGxK9YXO.
## References
NQLib is a Python library version of ODQ Toolbox, which were developed in MATLAB.
The algorithms used in NQLib are based on the following paper.
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53, pp. 2064–2075 (2008)
[2] S. Azuma, Y. Minami and T. Sugie: Optimal dynamic quantizers for feedback control with discrete-level actuators; Journal of Dynamic Systems, Measurement, and Control, Vol. 133, No. 2, 021005 (2011)
[3] 南,加嶋:システムの直列分解に基づく動的量子化器設計;計測自動制御学会論文集,Vol. 52, pp. 46–51(2016)
[4] R. Morita, S. Azuma, Y. Minami and T. Sugie: Graphical design software for dynamic quantizers in control systems; SICE Journal of Control, Measurement, and System Integration, Vol. 4, No. 5, pp. 372-379 (2011)
[5] Y. Minami and T. Muromaki: Differential evolution-based synthesis of dynamic quantizers with fixed-structures; International Journal of Computational Intelligence and Applications, Vol. 15, No. 2, 1650008 (2016)
## License
This software is released under the MIT License, see LICENSE.txt.
- class nqlib.Controller(A, B1, B2, C, D1, D2)¶
Bases:
object
State-space model of a controller K.
The controller K is given by:
- K{ x(t+1) = A x(t) + B1 r(t) + B2 y(t)
{ u(t) = C x(t) + D1 r(t) + D2 y(t)
References
[5] Y. Minami and T. Muromaki: Differential evolution-based synthesis of dynamic quantizers with fixed-structures; International Journal of Computational Intelligence and Applications, Vol. 15, No. 2, 1650008 (2016)
Example
>>> import nqlib >>> K = nqlib.Controller(A=0, ... B1=0, ... B2=[0, 0], ... C=0, ... D1=1, ... D2=[-20, -3]) >>> K.A array([[0]])
- __init__(A, B1, B2, C, D1, D2)¶
Initialize a Controller instance.
- Parameters:
A (array_like) – State matrix (n x n), real.
B1 (array_like) – Input matrix for r (n x l), real.
B2 (array_like) – Input matrix for y (n x p), real.
C (array_like) – Output matrix (m x n), real.
D1 (array_like) – Feedthrough matrix for r (m x l), real.
D2 (array_like) – Feedthrough matrix for y (m x p), real.
- Raises:
TypeError – If any argument cannot be interpreted as a matrix.
ValueError – If matrix dimensions are inconsistent.
Example
>>> import nqlib >>> K = nqlib.Controller(A=0, ... B1=0, ... B2=[0, 0], ... C=0, ... D1=1, ... D2=[-20, -3]) >>> K.B1 array([[0]])
- class nqlib.DynamicQuantizer(A, B, C, q)¶
Bases:
object
Dynamic quantizer.
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(1.0) >>> Q = nqlib.DynamicQuantizer(0.6, 1, 1, q) >>> Q.quantize([0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]) array([[ 0., 0., 0., 0., 0., -1., -2., -3.]])
- property A¶
State matrix (N x N, real). N >= 1.
- property B¶
Input matrix (N x m, real). m >= 1.
- property C¶
Output matrix (m x N, real).
- property N¶
Order of this dynamic quantizer (N >= 1).
Equals the number of rows (or columns) in A.
- __init__(A, B, C, q)¶
Initialize a DynamicQuantizer instance.
The dynamic quantizer is defined by the following equations:
- Q{ xi(t+1) = A xi(t) + B u(t)
{ v(t) = q( C xi(t) + u(t) )
- Parameters:
A (NDArrayNum) – State matrix (N x N, real). N >= 1.
B (NDArrayNum) – Input matrix (N x m, real). m >= 1.
C (NDArrayNum) – Output matrix (m x N, real).
q (StaticQuantizer) – Static quantizer instance.
- Raises:
ValueError – If matrix dimensions are inconsistent.
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(1.0) >>> Q = nqlib.DynamicQuantizer(0.6, 1.0, 1.0, q) >>> Q.quantize([0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6]) array([[1., 1., 1., 1., 1., 2., 3.]])
- cost(system, steptime=InfInt.Value, _check_stability=True)¶
Compute the cost (E(Q)) for the quantizer and system.
- Parameters:
system (System) – System instance.
steptime (int or InfInt, optional) – Number of steps (default: infint, which implies that this function calculates until convergence). steptime >= 1.
_check_stability (bool, optional) – If True, check stability (default: True).
- Returns:
Estimation of E(Q) in the given steptime.
- Return type:
float
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control; IEEE Transactions on Automatic Control, Vol. 53, pp. 2064–2075 (2008)
Example
>>> import nqlib >>> import numpy as np >>> G = nqlib.System( ... A=[[1.15, 0.05], ... [0.00, 0.99]], ... B1=[[1], ... [1]], ... B2=[[0.004], ... [0.099]], ... C1=[1., 0.], C2=[-15., -3.], ... D1=0, D2=0, ... ) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design_AG( ... system=G, ... q=q, ... ) >>> np.isclose(E, Q.cost(G)) np.True_
- property delta¶
The maximum allowed quantization error of q. Declares that for any real vector u, max(abs(q(u)-u)) <= delta. delta > 0.
- static design(system, *, q, steptime=InfInt.Value, max_gain_wv=inf, max_N=InfInt.Value, verbose=False, use_analytical_method=True, use_LP_method=True, use_design_GB_method=True, use_DE_method=False, solver=None)¶
Design a stable and optimal dynamic quantizer for a system.
- Parameters:
system (System) – Stable system instance.
q (StaticQuantizer) – Static quantizer instance.
steptime (int or InfInt, optional) – Estimation time (default: infint). steptime >= 1.
max_gain_wv (float, optional) – Upper limit of gain w->v (default: inf). max_gain_wv >= 0.
max_N (int or InfInt, optional) – Upper limit of quantizer order (default: infint). max_N >= 1.
verbose (bool, optional) – If True, print progress (default: False).
use_analytical_method (bool, optional) – Use analytical method (default: True).
use_LP_method (bool, optional) – Use LP method (default: True).
use_design_GB_method (bool, optional) – Use gradient-based method (default: True).
use_DE_method (bool, optional) – Use differential evolution method (default: False).
solver (str or None, optional) – CVXPY solver name (default: None).
- Returns:
Q (DynamicQuantizer or None) – Designed quantizer or None if not found.
E (float) – Estimated E(Q). If Q is None, E is inf.
- Raises:
ValueError – If system is unstable.
Example
>>> import nqlib >>> P = nqlib.Plant( ... A =[[ 1.8, 0.8], ... [-1.0, 0. ]], ... B =[[1.], ... [0.]], ... C1 =[0.01, -0.09], ... C2 =[0, 0], ... ) >>> G = nqlib.System.from_FF(P) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design( ... system=G, ... q=q, ... steptime=100, ... ) >>> Q.is_stable True >>> E < 0.5 np.True_
- static design_AG(system, *, q, allow_unstable=False, verbose=False)¶
Algebraically design a stable and optimal dynamic quantizer for a system.
- Parameters:
system (System) – Stable and SISO system instance.
q (StaticQuantizer) – Static quantizer instance.
allow_unstable (bool, optional) – Allow unstable quantizer (default: False). It is recommended to set verbose to True, so that you are reminded the result is unstable. If this is True, the design method in reference [3] will not be used.
verbose (bool, optional) – If True, print progress (default: False).
- Returns:
Q (DynamicQuantizer or None) – Designed quantizer or None if not found.
E (float) – Estimated E(Q). If Q is None, E is inf.
- Raises:
ValueError – If system is unstable.
Example
>>> import nqlib >>> P = nqlib.Plant( ... A =[[ 1.8, 0.8], ... [-1.0, 0. ]], ... B =[[1.], ... [0.]], ... C1 =[0.01, -0.09], ... C2 =[0, 0], ... ) >>> G = nqlib.System.from_FF(P) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design_AG(system=G, q=q) >>> Q.is_stable True >>> E < 0.5 np.True_
- static design_DE(system, *, q, N, steptime=InfInt.Value, max_gain_wv=inf, verbose=False)¶
Design a stable and optimal dynamic quantizer using differential evolution.
- Parameters:
system (System) – Stable and SISO system instance.
q (StaticQuantizer) – Static quantizer instance.
N (int) – Order of the resulting quantizer. N >= 1.
steptime (int or InfInt, optional) – Estimation time (default: infint). steptime >= 1.
max_gain_wv (float, optional) – Upper limit of gain w->v (default: inf). max_gain_wv >= 0.
verbose (bool, optional) – If True, print progress (default: False).
- Returns:
Q (DynamicQuantizer or None) – Designed quantizer or None if not found.
E (float) – Estimated E(Q). If Q is None, E is inf.
- Raises:
ValueError – If system is unstable.
References
[5] Y. Minami and T. Muromaki: Differential evolution-based synthesis of dynamic quantizers with fixed-structures; International Journal of Computational Intelligence and Applications, Vol. 15, No. 2, 1650008 (2016)
Example
>>> import nqlib >>> G = nqlib.System( ... A=[[1.15, 0.05], ... [0.00, 0.99]], ... B1=[[1], ... [1]], ... B2=[[0.004], ... [0.099]], ... C1=[1., 0.], C2=[-15., -3.], ... D1=0, D2=0, ... ) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design_DE( ... system=G, ... q=q, ... N=2, ... ) >>> Q.is_stable True >>> E < 0.01 np.True_
- static design_GD(system, *, q, N, steptime=InfInt.Value, max_gain_wv=inf, verbose=False, method='SLSQP', obj_type='exp')¶
Design a stable and optimal dynamic quantizer using gradient-based optimization.
- Parameters:
system (System) – Stable and SISO system instance.
q (StaticQuantizer) – Static quantizer instance.
N (int) – Order of the resulting quantizer. N >= 1.
steptime (int or InfInt, optional) – Estimation time (default: infint). steptime >= 1.
max_gain_wv (float, optional) – Upper limit of gain w->v (default: inf). max_gain_wv >= 0.
verbose (bool, optional) – If True, print progress (default: False).
method (str, optional) – Optimization method for scipy.optimize.minimize (default: ‘SLSQP’). (If None, this function does not specify the method).
obj_type (str, optional) – Objective function type (default: ‘exp’).
- Returns:
Q (DynamicQuantizer or None) – Designed quantizer or None if not found.
E (float) – Estimated E(Q). If Q is None, E is inf.
- Raises:
ValueError – If system is unstable.
References
[5] Y. Minami and T. Muromaki: Differential evolution-based synthesis of dynamic quantizers with fixed-structures; International Journal of Computational Intelligence and Applications, Vol. 15, No. 2, 1650008 (2016)
Example
>>> import nqlib >>> G = nqlib.System( ... A=[[1.15, 0.05], ... [0.00, 0.99]], ... B1=[[1], ... [1]], ... B2=[[0.004], ... [0.099]], ... C1=[1., 0.], C2=[-15., -3.], ... D1=0, D2=0, ... ) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design_GD( ... system=G, ... q=q, ... N=2, ... ) >>> Q.is_stable True >>> E < 0.01 np.True_
- static design_LP(system, *, q, dim=InfInt.Value, T=InfInt.Value, max_gain_wv=inf, solver=None, verbose=False)¶
Design a stable and optimal dynamic quantizer using the linear programming method.
Note that this method does not guarantee that Q.gain_wv() < max_gain_wv will be True.
- Parameters:
system (System) – Stable and SISO system instance.
q (StaticQuantizer) – Static quantizer instance.
dim (int or InfInt, optional) – Upper limit of quantizer order (default: infint). dim >= 1.
T (int or InfInt, optional) – Estimation time (default: infint) (T > 0).
max_gain_wv (float, optional) – Upper limit of gain w->v (default: inf) (max_gain_wv > 0).
solver (str or None, optional) – CVXPY solver name (default: None). You can check the available solvers by nqlib.installed_solvers(). (If None, this function does not specify the solver).
verbose (bool, optional) – If True, print progress (default: False).
- Returns:
Q (DynamicQuantizer or None) – Designed quantizer or None if not found.
E (float) – Estimated E(Q). If Q is None, E is inf.
- Raises:
ValueError – If system is unstable.
References
[4] R. Morita, S. Azuma, Y. Minami and T. Sugie: Graphical design software for dynamic quantizers in control systems; SICE Journal of Control, Measurement, and System Integration, Vol. 4, No. 5, pp. 372-379 (2011)
Example
>>> import nqlib >>> P = nqlib.Plant( ... A =[[ 1.8, 0.8], ... [-1.0, 0. ]], ... B =[[1.], ... [0.]], ... C1 =[0.01, -0.09], ... C2 =[0, 0], ... ) >>> G = nqlib.System.from_FF(P) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design_LP( ... system=G, ... q=q, ... T=100, ... dim=2, ... max_gain_wv=2.0, ... ) >>> Q.is_stable True >>> E < 0.5 np.True_
- static from_SISO_parameters(parameters, *, q)¶
Create a SISO dynamic quantizer from parameters. The resulting dynamic quantizer is in a reachable canonical form from a 1D array of parameters, which is a concatenation of the coefficients.
The form of the parameters is as follows:
| a = parameters[:N] | c = parameters[N:] | A = [[ 0, 1, 0, ..., 0] | [ 0, 0, 1, ..., 0] | : | [ 0, 0, 0, ..., 1] | [ -a[0], -a[1], -a[2], ..., -a[N-1]] | B = [ [0], [0], [0], ..., [1]] | C = [ c[0], c[1], c[2], ..., c[N-1]]
- Parameters:
parameters (NDArrayNum) – 1D array of parameters, concatenating a and c.
q (StaticQuantizer) – Static quantizer that this dynamic quantizer uses.
- Returns:
Dynamic quantizer created from the parameters.
- Return type:
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> Q = nqlib.DynamicQuantizer.from_SISO_parameters([1, 0.33], q=q) >>> Q.A array([[-1.]]) >>> Q.C array([[0.33]])
- property gain_uv¶
Gain from u to v.
- gain_wv(steptime=InfInt.Value, verbose=False)¶
Compute the gain from w to v for this quantizer.
- Parameters:
steptime (int or InfInt, optional) – The number of time steps to use for the gain calculation. If infint, calculation continues until convergence. steptime >= 1 (default: infint, which means until convergence).
verbose (bool, optional) – If True, print progress information during calculation (default: False).
- Returns:
Estimated gain w->v.
- Return type:
float
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control; IEEE Transactions on Automatic Control, Vol. 53, pp. 2064–2075 (2008)
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> dq = nqlib.DynamicQuantizer(0.5, 0.1, 0.1, q) >>> dq.gain_wv() < 1.021 np.True_
- property is_stable¶
Check if the quantizer is stable.
- Returns:
True if stable, False otherwise.
- Return type:
bool
References
[2] S. Azuma, Y. Minami and T. Sugie: Optimal dynamic quantizers for feedback control with discrete-level actuators; Journal of Dynamic Systems, Measurement, and Control, Vol. 133, No. 2, 021005 (2011)
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> Q = nqlib.DynamicQuantizer(0.5, 1.0, 1.0, q) >>> Q.is_stable False
- property m¶
Number of inputs (m >= 1).
Equals the number of columns in B and the number of rows in C.
- property minreal¶
Minimal realization of this quantizer.
- Returns:
Minimal realization of this quantizer.
- Return type:
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> Q = nqlib.DynamicQuantizer(1, 1, 1, q) >>> Q2 = Q.minreal >>> Q2.N 1
- objective_function(system, *, steptime_gain_wv=InfInt.Value, steptime_E=InfInt.Value, max_gain_wv=inf, obj_type='exp')¶
Objective function designed for numerical optimization.
If this value is less than 0, the quantizer satisfies the stability and max_gain_wv constraints. The less this value is, the better the quantizer (i.e., the less system.E(Q)).
- Parameters:
system (System) – The system for which the quantizer is being optimized. Must be stable and SISO.
steptime_gain_wv (int or InfInt, optional) – The number of time steps for calculating max_gain_wv. steptime_gain_wv >= 1 (default: infint, which means until convergence).
steptime_E (int or InfInt, optional) – The number of time steps for calculating system.E(Q). steptime_E >= 1 (default: infint, which means until convergence).
max_gain_wv (float, optional) – Upper limit for the w->v gain. max_gain_wv >= 0 (default: np.inf).
obj_type (str, optional) – Objective function type. Must be one of [‘exp’, ‘atan’, ‘1.1’, ‘100*1.1’] (default: ‘exp’).
- Returns:
Objective value. If the value is less than 0, the quantizer satisfies the constraints. Otherwise, the value is max(eig_max(A + B @ C) - 1, Q.gain_wv() - max_gain_wv).
- Return type:
float
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> Q = nqlib.DynamicQuantizer(1, 0.1, 0.1, q) >>> Q.is_stable False >>> system = nqlib.System(0, 0, 0, 0, 0, 0, 0) >>> Q.objective_function( ... system, ... steptime_gain_wv=10, ... steptime_E=10, ... max_gain_wv=1.0, ... obj_type="exp", ... ) > 0 # because unstable np.True_
References
[5] Y. Minami and T. Muromaki: Differential evolution-based synthesis of dynamic quantizers with fixed-structures; International Journal of Computational Intelligence and Applications, Vol. 15, No. 2, 1650008 (2016)
- order_reduced(new_N)¶
Returns a reduced-order quantizer.
- Parameters:
new_N (int) – Desired order (1 <= new_N < self.N).
- Returns:
Reduced-order quantizer.
- Return type:
- Raises:
ImportError – If slycot is not installed.
ValueError – If new_N is not in the valid range.
Notes
Note that the quantizer with the reduced order will generally have larger E(Q) and a larger gain_wv than those of the original quantizer. You should check the performance and gain yourself.
This function requires slycot. Please install it.
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> import numpy as np >>> Q = nqlib.DynamicQuantizer(np.eye(2)*0.5, np.eye(2, 1), np.eye(1, 2), q) >>> Q.N # Original order 2 >>> Q2 = Q.order_reduced(1) # Reduce the order to 1 >>> Q2.N 1
- property q¶
Static quantizer which is used in this dynamic quantizer.
- quantize(u)¶
Quantize the input signal using this dynamic quantizer.
- Parameters:
u (NDArrayNum) – Input signal. Shape: (m, length).
- Returns:
Quantized signal. Shape: (1, length).
- Return type:
NDArrayNum
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.3) >>> Q = nqlib.DynamicQuantizer(1, 1, 1, q) >>> Q.quantize([[0.2, 0.4]]) array([[0.3, 0.6]])
- spec(steptime=InfInt.Value, show=True)¶
Returns a string summary of the quantizer’s specification.
- Parameters:
steptime (int or InfInt, optional) – Number of steps (default: infint, which implies that this function calculates until convergence). steptime >= 1.
show (bool, optional) – If True, print the summary (default: True).
- Returns:
Specification summary.
- Return type:
str
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> Q = nqlib.DynamicQuantizer(1, 1, 1, q) >>> Q.spec(show=False) 'The specs of ...'
- to_parameters(*, minreal=False)¶
Convert the dynamic quantizer to a 1D array of parameters.
Parameters here means the elements of the A and C matrices of a reachable canonical form. This quantizer must be SISO.
The form of the parameters is as follows:
| A = [[ 0, 1, 0, ..., 0] | [ 0, 0, 1, ..., 0] | : | [ 0, 0, 0, ..., 1] | [ -a[0], -a[1], -a[2], ...,-a[N-1]]] | B = [ [0], [0], [0], ..., [1]] | C = [ c[0], c[1], c[2], ..., c[N-1]] | parameters = [*a, *c]
- Parameters:
minreal (bool, optional) – If True, return the parameters of the minimal realization of this quantizer (default: False).
- Returns:
parameters – 1D array of parameters, concatenating a and c.
- Return type:
NDArrayNum
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> Q = nqlib.DynamicQuantizer(-1, 1, 0.33, q) >>> Q.to_parameters() array([1. , 0.33])
- class nqlib.Plant(A, B, C1, C2)¶
Bases:
object
State-space model of a plant P.
The plant P is given by:
- P{ x(t+1) = A x(t) + B u(t)
{ z(t) = C1 x(t) { y(t) = C2 x(t)
Example
>>> import nqlib >>> import numpy as np >>> P = nqlib.Plant(A=[[1.15, 0.05], ... [0, 0.99]], ... B=[[0.004], ... [0.099]], ... C1=[1, 0], ... C2=np.eye(2)) >>> P.A array([[1.15, 0.05], [0. , 0.99]])
- __init__(A, B, C1, C2)¶
Initialize a Plant instance.
- Parameters:
A (array_like) – State matrix (n x n), real.
B (array_like) – Input matrix (n x m), real.
C1 (array_like) – Output matrix for z (l1 x n), real.
C2 (array_like) – Output matrix for y (l2 x n), real.
- Raises:
TypeError – If any argument cannot be interpreted as a matrix.
ValueError – If matrix dimensions are inconsistent.
References
[5] Y. Minami and T. Muromaki: Differential evolution-based synthesis of dynamic quantizers with fixed-structures; International Journal of Computational Intelligence and Applications, Vol. 15, No. 2, 1650008 (2016)
Example
>>> import nqlib >>> import numpy as np >>> P = nqlib.Plant(A=[[1.15, 0.05], ... [0, 0.99]], ... B=[[0.004], ... [0.099]], ... C1=[1, 0], ... C2=np.eye(2)) >>> P.A array([[1.15, 0.05], [0. , 0.99]])
- static from_TF(tf)¶
Create a Plant instance from a transfer function.
- Parameters:
tf (control.TransferFunction) – Transfer function from input u to output z.
- Returns:
Plant instance with C2 set to zero.
- Return type:
Example
>>> import nqlib >>> import control >>> tf = control.TransferFunction([1], [1, 2, 1], 1) # 1 / (s^2 + 2s + 1) >>> P = nqlib.Plant.from_TF(tf) >>> P.A.shape[0] 2
- class nqlib.StaticQuantizer(function, delta, *, error_on_excess=True)¶
Bases:
object
Static quantizer.
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> q([0.04, 0.16]) array([0. , 0.2])
- __init__(function, delta, *, error_on_excess=True)¶
Initialize a StaticQuantizer q.
- Parameters:
function (Callable[[NDArrayNum], NDArrayNum]) – Quantization function. Must be callable.
delta (float) – The maximum allowed quantization error. Declares that for any real vector u, max(abs(q(u)-u)) <= delta. delta > 0.
error_on_excess (bool, optional) – If True, raises an error when the error exceeds delta (default: True). That is, whether to raise an error when max(abs(q(u)-u)) > delta becomes True.
- Raises:
TypeError – If function is not callable.
ValueError – If quantization error exceeds delta and error_on_excess is True.
Example
>>> import nqlib >>> import numpy as np >>> q = nqlib.StaticQuantizer(lambda u: np.round(u), 1.0) >>> q([1.2, 2.3]) array([1., 2.])
- property delta¶
The maximum allowed quantization error. Declares that for any real vector u, max(abs(q(u)-u)) <= delta. delta > 0.
- static mid_riser(d, bit=InfInt.Value, *, error_on_excess=True)¶
Create a mid-riser uniform StaticQuantizer.
- Parameters:
d (float) – Quantization step size. For a real vector u, max(abs(q(u)-u)) <= d/2. delta > 0.
bit (int or InfInt, optional) – Number of bits. Must satisfy bit >= 1 (default: infint). That is, the returned function can take 2**n values.
error_on_excess (bool, optional) – If True, raises an error when the error exceeds delta (=d/2) (default: True). That is, whether to raise an error when max(abs(q(u)-u)) > delta becomes True. This error should not occur, but for numerical safety, set this to True.
- Returns:
Mid-riser quantizer instance.
- Return type:
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_riser(0.5) >>> q([0.2, 0.7, 1.1, 0, -1]) array([ 0.25, 0.75, 1.25, 0.25, -0.75])
- static mid_tread(d, bit=InfInt.Value, *, error_on_excess=True)¶
Create a mid-tread uniform StaticQuantizer.
- Parameters:
d (float) – Quantization step size. For a real vector u, max(abs(q(u)-u)) <= d/2. delta > 0.
bit (int or InfInt, optional) – Number of bits. Must satisfy bit >= 1 (default: infint). That is, the returned function can take 2**n values.
error_on_excess (bool, optional) – If True, raises an error when the error exceeds delta (=d/2) (default: True). That is, whether to raise an error when max(abs(q(u)-u)) > delta becomes True. This error should not occur, but for numerical safety, set this to True.
- Returns:
q – Mid-tread quantizer instance.
- Return type:
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.5) >>> q([0.2, 0.7, 1.1, 0, -1]) array([ 0. , 0.5, 1. , 0. , -1. ])
- quantize(u)¶
Quantize the input signal.
- Parameters:
u (NDArrayNum) – Input signal.
- Returns:
Quantized signal.
- Return type:
NDArrayNum
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.5) >>> u = [0, 0.32, 0.44] >>> all(q.quantize(u) == q(u)) True >>> q.quantize(u) array([0. , 0.5, 0.5])
- class nqlib.System(A, B1, B2, C1, C2, D1, D2)¶
Bases:
object
State-space model of an ideal system. Ideal here means that the system does not have a quantizer.
The system is given by:
- G{ x(t+1) = A x(t) + B1 r(t) + B2 v(t)
{ z(t) = C1 x(t) + D1 r(t) { u(t) = C2 x(t) + D2 r(t)
Example
>>> import nqlib >>> G = nqlib.System( ... A=[[1.15, 0.05], ... [0.00, 0.99]], ... B1=[[0.], ... [0.]], ... B2=[[0.004], ... [0.099]], ... C1=[1., 0.], ... C2=[-15., -3.], ... D1=0, ... D2=1, ... ) >>> G.A array([[1.15, 0.05], [0. , 0.99]])
- E(Q, steptime=InfInt.Value, _check_stability=True, verbose=False)¶
Estimate E(Q) for the system and quantizer.
- Parameters:
Q (DynamicQuantizer) – Dynamic quantizer instance. The quantizer whose performance is evaluated.
steptime (int or InfInt, optional) – Evaluation time. Must be a natural number (steptime >= 1). Default: infint.
_check_stability (bool, optional) – If True, check stability (default: True). This shouldn’t be changed.
verbose (bool, optional) – If True, print progress (default: False).
- Returns:
Estimated value of E(Q) in the given steptime.
- Return type:
float
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> import numpy as np >>> G = nqlib.System( ... A=[[1.15, 0.05], ... [0.00, 0.99]], ... B1=[[1], ... [1]], ... B2=[[0.004], ... [0.099]], ... C1=[1., 0.], C2=[-15., -3.], ... D1=0, D2=0, ... ) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design_AG( ... system=G, ... q=q, ... ) >>> np.isclose(E, G.E(Q)) np.True_
- __init__(A, B1, B2, C1, C2, D1, D2)¶
Initialize a System instance (ideal system without quantizer).
- Parameters:
A (array_like) – State matrix (n x n), real.
B1 (array_like) – Input matrix for r (n x p), real.
B2 (array_like) – Input matrix for v (n x m), real.
C1 (array_like) – Output matrix for z (l x n), real.
C2 (array_like) – Output matrix for u (m x n), real.
D1 (array_like) – Feedthrough matrix for r to z (l x p), real.
D2 (array_like) – Feedthrough matrix for r to u (m x p), real.
- Raises:
TypeError – If any argument cannot be interpreted as a matrix.
ValueError – If matrix dimensions are inconsistent.
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> G = nqlib.System( ... A=[[1.15, 0.05], ... [0.00, 0.99]], ... B1=[[0.], ... [0.]], ... B2=[[0.004], ... [0.099]], ... C1=[1., 0.], ... C2=[-15., -3.], ... D1=0, ... D2=1, ... ) >>> G.A array([[1.15, 0.05], [0. , 0.99]])
- static from_FBIQ(P, K)¶
Alias for from_FB_connection_with_input_quantizer.
- Parameters:
P (Plant) – Plant instance. The plant in the feedback loop.
K (Controller) – Controller instance. The controller in the feedback loop.
- Returns:
System with quantizer inserted at controller input (feedback).
- Return type:
Example
>>> import nqlib >>> P = nqlib.Plant(0.5, 1, 1, 1) >>> K = nqlib.Controller(0, 1, 1, 1, 1, 1) >>> sys = nqlib.System.from_FBIQ(P, K) >>> sys.is_stable False
- static from_FBOQ(P, K)¶
Alias for from_FB_connection_with_output_quantizer.
- Parameters:
P (Plant) – Plant instance. The plant in the feedback loop.
K (Controller) – Controller instance. The controller in the feedback loop.
- Returns:
System with quantizer inserted at controller output (feedback).
- Return type:
Example
>>> import nqlib >>> P = nqlib.Plant(0.5, 1, 1, 1) >>> K = nqlib.Controller(0, 1, 1, 1, 1, 1) >>> sys = nqlib.System.from_FBOQ(P, K) >>> sys.is_stable False
- static from_FB_connection_with_input_quantizer(P, K)¶
Create a System instance from Plant and Controller with input quantizer (feedback connection).
‘from_FB_connection_with_input_quantizer’ means that a quantizer is inserted as shown in the following figure.
| ┌───────┐ ┌───────┐ ┌───────┐ | r ───>│ │ u │ │ v │ ├───> z | │ K ├────>│ Q ├────>│ P │ | ┌─>│ │ │ │ │ ├──┐ | │ └───────┘ └───────┘ └───────┘ │ y | └─────────────────────────────────────────┘
- Parameters:
P (Plant) – Plant instance. The plant in the feedback loop.
K (Controller) – Controller instance. The controller in the feedback loop.
- Returns:
System with quantizer inserted at controller input (feedback).
- Return type:
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> P = nqlib.Plant(0.5, 1, 1, 1) >>> K = nqlib.Controller(0, 1, 1, 1, 1, 1) >>> sys = nqlib.System.from_FB_connection_with_input_quantizer(P, K) >>> sys.is_stable False
- static from_FB_connection_with_output_quantizer(P, K)¶
Create a System instance from Plant and Controller with output quantizer (feedback connection).
‘from_FB_connection_with_output_quantizer’ means that a quantizer is inserted as shown in the following figure.
| ┌───────┐ ┌───────┐ | r ───>│ │ │ ├───> z | │ K ├──────────>│ P │ | ┌─>│ │ │ ├──┐ | v │ └───────┘ ┌─────┐ └───────┘ │ u | └─────────────┤ Q │<────────────┘ | └─────┘
- Parameters:
P (Plant) – Plant instance. The plant in the feedback loop.
K (Controller) – Controller instance. The controller in the feedback loop.
- Returns:
System with quantizer inserted at controller output (feedback).
- Return type:
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> P = nqlib.Plant(0.5, 1, 1, 1) >>> K = nqlib.Controller(0, 1, 1, 1, 1, 1) >>> sys = nqlib.System.from_FB_connection_with_output_quantizer(P, K) >>> sys.is_stable False
- static from_FF(P)¶
Create a System instance from a Plant (feedforward connection).
‘from_FF’ means that a quantizer is inserted as shown in the following figure.
| ┌─────┐ v ┌─────┐ | u ───>│ Q ├────>│ P ├───> z | └─────┘ └─────┘
- Parameters:
P (Plant) – Plant instance. The plant to which the quantizer is connected in feedforward.
- Returns:
System with quantizer inserted before plant (feedforward).
- Return type:
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> P = nqlib.Plant( ... A =[[ 1.8, 0.8], ... [-1.0, 0. ]], ... B =[[1.], ... [0.]], ... C1 =[0.01, -0.09], ... C2 =[0, 0], ... ) >>> G = nqlib.System.from_FF(P) >>> G.is_stable True
- property is_stable¶
Check if the closed-loop system is stable.
- Returns:
True if stable, False otherwise.
- Return type:
bool
Example
>>> import nqlib >>> sys = nqlib.System(0.3, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5) >>> sys.is_stable True
- is_stable_with(Q)¶
Alias for is_stable_with_quantizer.
- Parameters:
Q (DynamicQuantizer or StaticQuantizer) – Quantizer instance. The quantizer to check stability with.
- Returns:
True if stable, False otherwise.
- Return type:
bool
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> G = nqlib.System( ... A=[[1.15, 0.05], ... [0.00, 0.99]], ... B1=[[1], ... [1]], ... B2=[[0.004], ... [0.099]], ... C1=[1., 0.], C2=[-15., -3.], ... D1=0, D2=0, ... ) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design_AG( ... system=G, ... q=q, ... ) >>> G.is_stable_with(Q) True
- is_stable_with_quantizer(Q)¶
Check if the system is stable with the given quantizer.
- Parameters:
Q (DynamicQuantizer or StaticQuantizer) – Quantizer instance. The quantizer to check stability with.
- Returns:
True if stable, False otherwise.
- Return type:
bool
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> G = nqlib.System( ... A=[[1.15, 0.05], ... [0.00, 0.99]], ... B1=[[1], ... [1]], ... B2=[[0.004], ... [0.099]], ... C1=[1., 0.], C2=[-15., -3.], ... D1=0, D2=0, ... ) >>> q = nqlib.StaticQuantizer.mid_tread(d=2) >>> Q, E = nqlib.DynamicQuantizer.design_AG( ... system=G, ... q=q, ... ) >>> G.is_stable_with_quantizer(Q) True
- response(input, x_0)¶
Simulate the system and return results.
- Parameters:
input (array_like) – Input signal (reference r). Shape: (p, length).
x_0 (array_like) – Initial state vector. Shape: (n, 1).
- Returns:
t (np.ndarray) – Time steps. Shape: (1, length).
u (np.ndarray) – Input signal to plant. Shape: (m, length).
z (np.ndarray) – Output signal. Shape: (l, length).
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> import numpy as np >>> sys = nqlib.System(1, 1, 1, 1, 1, 1, 1) >>> t, u, z = sys.response(np.ones((1, 5)), np.zeros((1, 1))) >>> t.shape (1, 5)
- response_with_quantizer(quantizer, input, x_0)¶
Simulate the system with a quantizer and return results.
- Parameters:
quantizer (DynamicQuantizer or StaticQuantizer) – Quantizer to use in the simulation.
input (array_like) – Input signal (reference r). Shape: (p, length).
x_0 (array_like) – Initial state vector. Shape: (n, 1).
- Returns:
t (np.ndarray) – Time steps. Shape: (1, length).
u (np.ndarray) – Input to quantizer. Shape: (m, length).
v (np.ndarray) – Quantized input. Shape: (m, length).
z (np.ndarray) – Output signal. Shape: (l, length).
References
[1] S. Azuma and T. Sugie: Synthesis of optimal dynamic quantizers for discrete-valued input control;IEEE Transactions on Automatic Control, Vol. 53,pp. 2064–2075 (2008)
Example
>>> import nqlib >>> import numpy as np >>> sys = nqlib.System(1, 1, 1, 1, 1, 1, 1) >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> t, u, v, z = sys.response_with_quantizer(q, np.ones((1, 5)), np.zeros((1, 1))) >>> t.shape (1, 5)
- nqlib.installed_solvers()¶
List the installed solvers.
- nqlib.order_reduced(Q, new_N)¶
Returns the quantizer with its order reduced.
Note that the quantizer with the reduced order will generally have larger E(Q) and a larger gain_wv than those of the original quantizer. You should check the performance and gain yourself.
This function requires slycot. Please install it.
- Parameters:
Q (DynamicQuantizer) – The quantizer to be reduced. Must be an instance of DynamicQuantizer.
new_N (int) – Desired order (1 <= new_N < Q.N).
- Returns:
Quantizer with reduced order.
- Return type:
Example
>>> import nqlib >>> q = nqlib.StaticQuantizer.mid_tread(0.1) >>> import numpy as np >>> Q = nqlib.DynamicQuantizer(np.eye(2)*0.4, np.eye(2, 1), np.eye(1, 2), q) >>> Q.N # Original order 2 >>> Q2 = order_reduced(Q, 1) # Reduce the order to 1 >>> Q2.N 1