View Raw SPL
/*****************************************************************************
*                                                                            *
*   FFTSHIFT.SPL Copyright (C) 1997-2005 DSP Development Corporation         *
*                           All Rights Reserved                              *
*                                                                            *
*   Author:      Randy Race                                                  *
*                                                                            *
*   Synopsis:    Flips FFT so zero frequency is the middle point             *
*                                                                            *
*   Revisions:   18 Aug 1997  RRR  Creation                                  *
*                21 Jan 1998  RRR  Odd length fixup for rows                 *
*                 8 Jul 1999  RRR  don't reverse halves                      *
*                19 May 2000  RRR  optimize buffering for arrays             *
*                 9 Feb 2005  RRR  buffering now internally optimized        *
*                                                                            *
*****************************************************************************/


#if @HELP_FFTSHIFT

    FFTSHIFT

    Purpose: Shifts a 1D or 2D FFT so the 0 frequency is the midpoint

    Syntax:  FFTSHIFT(ser, dim)

               ser - A series or array.

               dim - Optional. An integer, the shift dimension.

                      -1: Shift rows and columns for arrays (default).
                       0: Do not shift quadrants for arrays (same as 1).
                       1: Shift rows only.
                       2: Shift columns only.

    Returns: A series or array.

    Example:
             W1: {1, 2, 3, 2, 1}
             W2: fft(W1)
             W3: fftshift(W2)

             The zero frequency (i.e. DC) value of W2 is the first point.
             The zero frequency of W3 is the 3rd point and appears in the
             middle of the resulting graph.

    Example:
             W1: ravel(1..16, 4)
             W2: fftshift(W1)
             W3: fftshift(W1, 1)
             W4: fftshift(W1, 2)

             W1 == {{1, 5,  9, 13},
                    {2, 6, 10, 14},
                    {3, 7, 11, 15},
                    {4, 8, 12, 16}}

             W2 == {{11, 15,  3,  7},
                    {12, 16,  4,  8},
                    { 9, 13,  1,  5},
                    {10, 14,  2,  6}}

             W3 == {{ 3,  7, 11, 15},
                    { 4,  8, 12, 16},
                    { 1,  5,  9, 13},
                    { 2,  6, 10, 14}}

             W4 == {{ 9, 13,  1,  5},
                    {10, 14,  2,  6},
                    {11, 15,  3,  7},
                    {12, 16,  4,  8}}

             W1 contains a 4x4 array.
             
             W2 shifts the rows and columns of the array. The result is
             the upper left and lower right quadrants are swapped and
             the upper right and lower left quadrands are swapped.

             W3 shifts the rows of the array only.

             W4 shifts the columns of the array only.

    Remarks:
             FFTSHIFT also works on 2D FFT array.

             By default, FFTSHIFT flips the quadrants of an array. Set
             dim to 0 or 1 to shift rows only and not shift the quadrants.

             See IFFTSHIFT to undo the shift of FFTSHIFT.

    See Also:
             Fft
             Fft2
             Ifftshift
#endif


/* shift mid point of series or array */
fftshift(s, dim)
{
        local rmid, rodd, cmid, codd, t, xv;
        local nr, nc, r1, r2, c1, c2, bufsize;

        if (argc < 2)
        {
                if (argc < 1) error(sprintf("%s - input series required", __FUNC__));

                dim = -1;
        }

        /* numrows and numcols */
        (nr, nc) = size(s);

        /* get row midpoints */
        rmid = ceil(nr / 2);
        rodd = nr % 2;

        if (nc > 1 && (dim == 2 || dim < 0) && not(isxy(s)))
        {
                /* array - get col midpoints */
                cmid = ceil(nc / 2 + 1);
                codd = (nc % 2);

                /* array indices */
                if (dim == 2)
                {
                        r1 = 1..rmid;
                        r2 = (rmid + 1)..nr;
                }
                else
                {
                        r1 = (rmid + 1)..nr;
                        r2 = 1..rmid;
                }

                c1 = cmid..nc;
                c2 = 1..(cmid - 1);

                /* flip rows and columns in one operation */
                t = {ravel(s[r1, c1], s[r1, c2]), ravel(s[r2, c1], s[r2, c2])};

                /* fixup offset for even or odd columns */
                setdeltay(t, deltay(s));
                setyoffset(t, yoffset(s) + ((codd - nc) / 2) * deltay(t));
        }
        else if (dim == 1 || dim <= 0)
        {
                /* series - flip each half of all the rows */
                t = concat(extract(s, rmid + 1, -1), extract(s, 1, rmid));

                if (isxy(s))
                {
                        xv = xvals(s);
                        xv = concat(extract(xv, rmid + 1, -1) - deltax(s) * length(s), extract(xv, 1, rmid));
                        t = xy(xv, t);
                }
        }
        else
        {
                t = s;
        }

        /* fixup offset for even or odd rows */
        if (dim <= 2 && not(isxy(s)))
        {
                setdeltax(t, deltax(s));
                setxoffset(t, xoffset(s) + ((rodd - nr) / 2) * deltax(t));
        }

        return(t);
}