Sign in

username or email:

password:



Not a member?
Forgot your password?

Search code



Search tips


See Also

Embedded SystemsFPGA

DSP Code Sharing > Resampling by Lagrange-polynomial interpolation

Resampling by Lagrange-polynomial interpolation

Language: Matlab

Processor: Not Relevant

Submitted by Markus Nentwig on Aug 17 2011

Licensed under a Creative Commons Attribution 3.0 Unported License

Resampling by Lagrange-polynomial interpolation


 


Calculates Lagrange-resampler coefficients and resamples an example signal.

A Lagrange-resampler evaluates the unique n-th order polynomial that crosses through n+1 input samples.
This code snippet maps it to a generic Farrow structure with n+1 taps and n+1 polynomial coefficients per tap.

Fig. 1 shows the impulse response of a four-point resampler (3rd order polynomial), and a published reference result from literature, which can be found in the code.
The circles illustrate the output [0, 1, 0] from the Lagrange polynomial corresponding to the center FIR tap, when evaluated for an offset x = 0.


Fig. 1: Impulse response for four-point (cubic) Lagrange interpolation

Fig. 2 compares the impulse responses for increasing order with the ideal sinc() response, which is aymptotically approached as the order increases:

Fig. 2: Impulse responses for increasing interpolation order, and sinc() response.

Copy the code snippet into lagrangeResamplingDemo.m and run it by its name in Matlab / Octave.

Update 18.8.2011: Fixed a bug with the final two assert() statements. Now it works in OctaveForge and Matlab.

Update 3.8.2012: An alternative version that resamples an actual signal can be found here. It is related to this discussion on comp.dsp.

 
% Lagrange interpolation for resampling
% References:
% [1] A digital signal processing approach to Interpolation
%     Ronald W. Schafer and Lawrence R. Rabiner
%     Proc. IEEE vol 61, pp.692-702, June 1973
% [2] https://ccrma.stanford.edu/~jos/Interpolation/Lagrange_Interpolation.html
% [3] Splitting the Unit delay: Tools for fractional delay filter design
%     T. I. Laakso, V. Valimaki, M. Karjalainen, and U. K. Laine
%     IEEE Signal Processing Magazine, vol. 13, no. 1, pp. 30..60, January 1996
function lagrangeResamplingDemo()
    originDefinition = 0; % see comment for LagrangeBasisPolynomial() below
   
    % Regarding order: From [1]
    % "Indeed, it is easy to show that whenever Q is odd, none of the
    % impulse responses corresponding to Lagrange interpolation can have
    % linear phase"
    % Here, order = Q+1 => odd orders are preferable
    order = 3;
   
    % *******************************************************************
    % Set up signals
    % *******************************************************************    
    nIn = order + 1;
    nOut = nIn * 5 * 20;

    % Reference data: from [1] fig. 8, linear-phase type
    ref = [-0.032, -0.056, -0.064, -0.048, 0, ...
           0.216, 0.448, 0.672, 0.864, 1, ...
           0.864, 0.672, 0.448, 0.216, 0, ...
           -0.048, -0.064, -0.056, -0.032, 0];
    tRef = (1:size(ref, 2)) / size(ref, 2);
   
    % impulse input to obtain impulse response
    inData = zeros(1, nIn);
    inData(1) = 1;
    outData = zeros(1, nOut);
   
    outTime = 0:(nOut-1);
    outTimeAtInput = outTime / nOut * nIn;
    outTimeAtInputInteger = floor(outTimeAtInput);
    outTimeAtInputFractional = outTimeAtInput - outTimeAtInputInteger;
    evalFracTime = outTimeAtInputFractional - 0.5 + originDefinition;
 
    % odd-order modification
    if mod(order, 2) == 0
        % Continuity of the impulse response is achieved when support points are located at
        % the intersections between adjacent segments "at +/- 0.5"
        % For an even order polynomial (odd number of points), this is only possible with
        % an asymmetric impulse response
       
        offset = 0.5;
        %offset = -0.5; % alternatively, its mirror image
    else
        offset = 0;
    end
   
    % *******************************************************************
    % Apply Lagrange interpolation to input data
    % *******************************************************************    
    for ixTap = 0:order
        % ixInSample is the input sample that appears at FIR tap 'ixTap' to contribute
        % to the output sample
        % Row vector, for all output samples in parallel
        ixInSample = mod(outTimeAtInputInteger + ixTap - order, nIn) + 1;

        % the value of said input sample, for all output samples in parallel
        d = inData(ixInSample);

        % Get Lagrange polynomial coefficients of this tap
        c = lagrangeBasisPolynomial(order, ixTap, originDefinition + offset);

        % Evaluate the Lagrange polynomial, resulting in the time-varying FIR tap weight
        cTap = polyval(c, evalFracTime);

        % FIR operation: multiply FIR tap weight with input sample and add to
        % output sample (all outputs in parallel)
        outData = outData + d .* cTap;
    end

    % *******************************************************************
    % Plot
    % *******************************************************************    
    figure(); hold on;
    h = plot((0:nOut-1) / nOut, outData, 'b-'); set(h, 'lineWidth', 3);
    stem(tRef, ref, 'r'); set(h, 'lineWidth', 3);
    legend('impulse response', 'reference result');
    title('Lagrange interpolation, impulse response');
end

% Returns the coefficients of a Lagrange basis polynomial
% 1 <= order: Polynomial order
% 0 <= evalIx <= order: index of basis function.
%
% At the set of support points, the basis polynomials evaluate as follows:
% evalIx = 1: [1 0 0 ...]
% evalIx = 2: [0 1 0 ...]
% evalIx = 3: [0 0 1 ...]
%
% The support point are equally spaced.
% Example, using originDefinition=0:
% order = 1: [-0.5 0.5]
% order = 2: [-1 0 1]
% order = 3: [-1.5 -0.5 0.5 1.5]
%
% The area around the mid-point corresponds to -0.5 <= x <= 0.5.
% If a resampler implementation uses by convention 0 <= x <= 1 instead, set
% originDefinition=0.5 to offset
% the polynomial.
function polyCoeff = lagrangeBasisPolynomial(order, evalIx, originDefinition)
    assert(evalIx >= 0);
    assert(evalIx <= order);
   
    tapLocations = -0.5*(order) + (0:order) + originDefinition;

    polyCoeff = [1];
    for loopIx = 0:order
        if loopIx ~= evalIx        
            % numerator: places a zero in the polynomial via (x-xTap(k)), with k != evalIx
            % denominator: scales to 1 amplitude at x=xTap(evalIx)
            term = [1 -tapLocations(loopIx+1)] / (tapLocations(evalIx+1)-tapLocations(loopIx+1));

            % multiply polynomials => convolve coefficients
            polyCoeff = conv(polyCoeff, term);
        end
    end

    % TEST:

    % The Lagrange polynomial evaluates to 1 at the location of the tap
    % corresponding to evalIx
    thisTapLocation = tapLocations(evalIx+1);
    pEval = polyval(polyCoeff, thisTapLocation);
    assert(max(abs(pEval) - 1) < 1e6*eps);
   
    % The Lagrange polynomial evaluates to 0 at all other tap locations
    tapLocations(evalIx+1) = [];
    pEval = polyval(polyCoeff, tapLocations);
    assert(max(abs(pEval)) < 1e6*eps);
end
 
 
Rate this code snippet:
5
Rating: 5 | Votes: 1
 
   
 
posted by Markus Nentwig
Markus received his Dipl. Ing. degree in electrical engineering / communications in 1999. Work interests include RF transceiver system design, implementation, modeling and verification. He works as senior architect for Renesas Mobile Europe in Finland.


Comments


No comments yet for this code


Add a Comment
You need to login before you can post a comment (best way to prevent spam). ( Not a member? )