I am doing a project in MATLAB about the fractionally spaced equalizer. The method that i have chosen to update the tap weight coefficients is the LMS algorithm. Here is the block scheme that i have tried to follow: enter image description here

  • x(k) are the elements of the received training sequence.
  • p(k) are the tap weight coefficients.

The vectors x(k) and p(k) have the same number of elements as there are tap weights. As it can be seen y(k) is the output of the equalizer. The formulas to calculate the error and then update the tap weights are the following: Training phase

for the training phase and

Tracking phase

for the tracking phase.

This is the MATLAB code:

The training phase

for k = 1:2*length(trainSymtx)

    for i = N+1:2*length(trainSymtx)-N
        currSymbols = train_syms_real(i-N:i+N); 
        y(k) = tapWeights * currSymbols';

        if mod(k, 2) == 0  % considero solo 'k' pari  
           a = k/2;
           error = y(k) - trainSymtx(a);
           x = conj(train_syms_real(i-N:i+N));         
           tapWeights = tapWeights - stepSize * error * x;


The tracking phase

for b = 1:2*length(trainSymtx)

    for m = N+1:2*length(trainSymtx)-N
        currSymbols = train_syms_real(m-N:m+N);
        y(b) = tapWeights * currSymbols';

        if mod(b, 2) == 0  
           w = b/2;
           c_est(w) = y(b);
           error_est = y(b) - c_est(w);
           x = conj(train_syms_real(m-N:m+N));
           tapWeights = tapWeights - stepSize * error_est * x;


My questions are the following:

  1. What are exactly the ĉ symbols? From the scheme it looks like the vector ĉ is just a part of the vector y(k) that we choose via the decision block.

  2. What is the decision block and how it works? How does it decides which symbols to consider and which ones to eliminate?

  3. How to implement this block scheme in MATLAB? I have done most of it but I'm not sure how to implement the switch between training and tracking.

The help will be gratefully appreciated.


1 Answer 1


The way it is drawn suggests that $\hat{c}[k]$ samples are the complex decisions for the demodulated symbols. This assumes correct timing to only use the samples for demodulation. Instead, assuming a training sequence is used, I recommend comparing all samples to the “ideal” waveform given by the training sequence at the same sampling rate as it would appear in this location of the receiver (as then a fractionally spaced equalizer). The switch between training and tracking would then have to change from a fractional spaced equalizer to a baud rate equalizer if implemented as shown.

Below is Python code I have for the implementation of a normalized LMS equalizer:

def LMS(input_signal, desired_signal, num_taps, alpha, shift=0):
    LMS(input_signal, desired_signal, num_taps, alpha, shift=0)
    LMS equalizer implementation  Dan Boschen 10-12-2023
    input parameters:
    input_signal: received signal (1D array like)
    desired_signal: transmitted (reference) signal (1D array like)
    num_taps: length of equalizer (positive integer)
    alpha: damping coefficient, typically < 0.01  (positive float)
    shift: number of samples to shift dominant equalizer tap to the right (signed integer) 
    input_signal and desired_signal should be aligned in time with zero phase
    y: equalized output (1D array)
    coeff: converged channel coefficients (1D array)
    e: error vs iteration (1D array)
    if shift > 0:
        rx_shift = shift
        tx_shift = 0
        tx_shift = -shift
        rx_shift = 0
    # align to delay of equalizer
    input_signal = input_signal[rx_shift + (num_taps-1)//2:]
    desired_signal = desired_signal[tx_shift:]
    num_points = min(len(input_signal), len(desired_signal))
    # normalize signals
    input_signal = input_signal[:num_points]/np.std(input_signal)
    desired_signal = desired_signal[:num_points]/np.std(desired_signal)
    coeff = np.zeros(num_taps, dtype=complex)
    y = np.zeros(num_points, dtype=complex)
    e = np.zeros(num_points, dtype=complex)

    for n in np.arange(num_taps, num_points):
        x = input_signal[n:n-num_taps:-1]
        y[n] = np.dot(np.conj(coeff), x)        # predicted output
        e[n] = y[n] - desired_signal[n]           # error
        coeff =   coeff - alpha * x * np.conj(e[n])  

    return y, np.conj(coeff), e

Please also see DSP.SE #31318 which details the process to find the least squared solution for the coefficients when post processing can be used. For adaptive solutions in addition to the simpler LMS algorithm detailed above (very easy but slow to converge) also consider the Recursive Least Squares (more complex, fast convergence and good tracking).


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.