def apply_filter_py(E, os, wxy): """ Apply the equaliser filter taps to the input signal. Parameters ---------- E : array_like input signal to be equalised os : int oversampling factor wxy : tuple(array_like, array_like,optional) filter taps for the x and y polarisation Returns ------- Eest : array_like equalised signal """ # equalise data points. Reuse samples used for channel estimation # this seems significantly faster than the previous method using a segment axis E = np.atleast_2d(E) pols = E.shape[0] Ntaps = wxy[0].shape[1] X1 = segment_axis(E[0], Ntaps, Ntaps - os) X = X1 ww = wxy[0].flatten() # Case for a butterfly-configured EQ if pols > 1: for pol in range(1, pols): X_P = segment_axis(E[pol], Ntaps, Ntaps - os) X = np.hstack([X, X_P]) ww = np.vstack([ww, wxy[pol].flatten()]) # Compute the output Eest = np.dot(X, ww.transpose()) # Extract the error (per butterfly entry) Eest_tmp = Eest[:, 0] for pol in range(1, pols): Eest_tmp = np.vstack([Eest_tmp, Eest[:, pol]]) Eest = Eest_tmp # Single mode EQ else: Eest = np.dot(X, ww.transpose()) Eest = np.atleast_2d(Eest) return Eest
def viterbiviterbi(E, N, M): """ Viterbi-Viterbi blind phase recovery for an M-PSK signal Parameters ---------- E : array_like the electric field of the signal N : int number of samples to average over M : int order of the M-PSK Returns ------- Eout : array_like Field with compensated phases """ E2d = np.atleast_2d(E) Eout = np.zeros_like(E2d) L = E2d.shape[1] for i in range(E2d.shape[0]): Et = E2d[i] L = len(Et) phi = np.angle(Et) E_raised = np.exp(1.j * phi)**M sa = segment_axis(E_raised, N, N - 1) phase_est = np.sum(sa, axis=1) phase_est = np.unwrap(np.angle(phase_est)) phase_est = (phase_est - np.pi) / M if N % 2: Eout[i, (N - 1) // 2:L - (N - 1) // 2] = E2d[i, (N - 1) // 2:L - (N - 1) // 2] * np.exp(-1.j * phase_est) else: Eout[i, N // 2 - 1:L - (N // 2)] = E2d[i, N // 2 - 1:L - (N // 2)] * np.exp(-1.j * phase_est) #if M == 4: # QPSK needs pi/4 shift # need a shift by pi/M for constellation points to not be on the axis if E.ndim == 1: return Eout.flatten(), phase_est.flatten() else: return Eout, phase_est
def apply_filter_py(E, os, wxy, modes=None): """ Apply the equaliser filter taps to the input signal. Parameters ---------- E : array_like input signal to be equalised os : int oversampling factor wxy : tuple(array_like, array_like,optional) filter taps for the x and y polarisation modes : array_like, optional mode numbers over which to apply the filters Returns ------- Eest : array_like equalised signal """ # equalise data points. Reuse samples used for channel estimation # this seems significantly faster than the previous method using a segment axis # TODO something fails still in this function E = np.atleast_2d(E) Ntaps = wxy.shape[-1] nmodes_max = wxy.shape[0] if modes is None: modes = np.arange(nmodes_max) nmodes = nmodes_max else: modes = np.atleast_1d(modes) assert np.max( modes ) < nmodes_max, "largest mode number is larger than shape of signal" nmodes = modes.sizeX = X1 X = segment_axis(E[modes[0]], Ntaps, Ntaps - os) ww = wxy[0].flatten() # Case for a butterfly-configured EQ if nmodes_max > 1: for pol in range(1, nmodes): X_P = segment_axis(E[modes[pol]], Ntaps, Ntaps - os) X = np.hstack([X, X_P]) ww = np.vstack([ww, wxy[modes[pol]].flatten()]) # Compute the output Eest = np.dot(X, ww.transpose()) # Extract the error (per butterfly entry) Eest_tmp = Eest[:, 0] for pol in range(1, nmodes): Eest_tmp = np.vstack([Eest_tmp, Eest[:, modes[pol]]]) Eest = Eest_tmp # Single mode EQ else: Eest = np.dot(X, ww.transpose()) Eest = np.atleast_2d(Eest) return Eest