Source code for cbadc.digital_control.utilities

"""Convenience functions for digital control design."""
import numpy as np
import itertools
import scipy.optimize


[docs]def overcomplete_set(Gamma: np.ndarray, M: int): """ Construct a overcomplete set of normalized column vectors Parameters ---------- Gamma: array_like the initial set of vectors M : `int` the desired number of column vectors Returns ------- array_like the resulting set of column vectors. """ T = np.copy(Gamma.transpose()) for dim in range(T.shape[0]): T[dim, :] /= np.linalg.norm(T[dim, :], ord=2) number_of_candidates_per_new_vector = 100 while T.shape[0] < M: candidate_set = np.random.randn(T.shape[1], number_of_candidates_per_new_vector) candidate_set /= np.linalg.norm(candidate_set, ord=2, axis=0) cost = np.zeros(number_of_candidates_per_new_vector) def cost_function(alpha): return np.linalg.norm(np.dot(T, alpha), ord=2) / np.linalg.norm( alpha, ord=2 ) for index in range(number_of_candidates_per_new_vector): sol = scipy.optimize.minimize(cost_function, candidate_set[:, index]) cost[index] = sol.fun candidate_set[:, index] = sol.x / np.linalg.norm(sol.x, ord=2) best_candidate_index = np.argmax(cost) T = np.vstack( (T, candidate_set[:, best_candidate_index].reshape((1, T.shape[1]))) ) return T.transpose()
[docs]def unit_element_set(N: int, M: int, candidates=[-1, 1, 0]): """ Construct an overcomplete set of vectors only using a single element, i.e., :math:`\mathbf{v} \in \\{ - \\alpha, \\alpha , 0 \\}^{N \\times M}` where duplicates and the :math:`\\begin{pmatrix}0, \dots, 0 \\end{pmatrix}` is excluded from the set. Parameters ---------- N: `int` the length of the vectors M: `int` the number of unique vectors candidates: `list[int]`, `optional` candidates to permute, defaults to [-1, 1, 0]. Returns ------- array_like, shape=(N, M) a matrix containing the unique vectors as column vectors. """ candidate_set = [] for item in itertools.product(*[candidates for _ in range(N)]): duplicate = False sum = np.sum(np.abs(np.array(item))) if sum == 0: break candidate = np.array(item) for item in candidate_set: s1 = np.sum(np.abs(np.array(item) - candidate)) s2 = np.sum(np.abs(np.array(item) + candidate)) if s1 == 0 or s2 == 0: duplicate = True if not duplicate: candidate_set.append(candidate) candidate_set = np.array(candidate_set) # [ # np.random.permutation(len(candidate_set)), : # ] if candidate_set.shape[0] < M: raise Exception("Not enough unique combinations; M is set to large.") set = candidate_set[0, :].reshape((N, 1)) candidate_set = np.delete(candidate_set, 0, 0) while set.shape[1] < M: costs = np.linalg.norm( np.dot(candidate_set, set), ord=2, axis=1 ) / np.linalg.norm(candidate_set, axis=1, ord=2) next_index = np.argmin(costs) set = np.hstack((set, candidate_set[next_index, :].reshape((N, 1)))) candidate_set = np.delete(candidate_set, next_index, 0) # return np.array(set)[:, np.random.permutation(set.shape[1])] return np.array(set)