View Raw SPL
/*****************************************************************************
*                                                                            *
*   ADDPHASE.SPL Copyright (C) 2015 DSP Development Corporation              *
*                           All Rights Reserved                              *
*                                                                            *
*   Author:      Randy Race                                                  *
*                                                                            *
*   Synopsis:    Adds a constant phase value to a series                     *
*                                                                            *
*   Revisions:   28 Aug 2015  RRR  Creation                                  *
*                                                                            *
*****************************************************************************/


#if @HELP_ADDPHASE

    ADDPHASE

    Purpose: Adds a constant phase value to a series.

    Syntax:  ADDPHASE(s, p)

                 s - A series or array.
 
                 p - A real, the phase value in radians.

    Returns: A series or array

    Example:
             W1: gsin(1000, 1/1000, 3)
             W2: gcos(1000, 1/1000, 3)
             W3: addphase(w1, pi/2)
             W4: w2-w3

             W1 contains a 3 Hz sine wave with a sample rate of 1000 Hz.

             W2 contains a 3 Hz cosine wave with a sample rate of 1000 Hz.

             W3 adds pi/2 radians of phase shift to the sine wave.

             W4 displays the difference between the cosine and the phase
             shifted sine.

    Example:
             W1: 1..10
             W2: -w1
             W3: addphase(w1, pi)
             W4: w2-w3

             W1 contains a linear ramp.

             W2 inverts the ramp.

             W3 adds pi radians of phase shift to the sine wave.

             W4 displays the difference between the inverted ramp and
             the phase shifted ramp.

    Example:
             W1: gsqrwave(1000, 1/1000, 3)
             W2: gtriwave(1000, 1/1000, 3)
             W3: addphase(w1, pi/3)
             W4: addphase(w2, pi/3)

             W1 contains a 3 Hz square wave with a sample rate of 1000 Hz.

             W2 contains a 3 Hz triangle wave with a sample rate of 1000 Hz.

             W3 adds pi/3 radians of phase shift to the square wave
             resulting in significant distortion.

             W4 adds pi/3 radians of phase shift to the triangle wave
             resulting in significant distortion.

    Example:
             W1: gcos(1000, 1/1000, 3)
             W2: gcos(1000, 1/1000, 9)
             W3: w1 + w2
             W4: addphase(w3, pi/4)
             W5: addphase(w1, pi/4) + addphase(w2, pi/4)
             W6: w4 - w5

             W1 and W2 each contain a cosine wave.

             W3 sums the cosines.

             W4 adds pi/4 radians of phase shift to the sum.

             W5 adds pi/4 radians of phase shift to each component and
             then sums.

             W6 shows the results are identical to machine precision.

    Remarks:
             ADDPHASE adds a phase constant to the PHASE of the FFT
             of the input series. The result is transformed back to
             the time domain.

             If the series is purely real, the phase input value is
             converted to an anti-symmetric constant series and added
             to the original phase. The original DC phase value is
             preserved or set to pi if the phase input is an odd
             multiple of pi.  If the series is real and even length,
             the original Nyquist phase value is also preserved or set
             to -pi if the phase input is an odd multiple of phase.
             This handling of DC and Nyquist phase inverts the input
             series for a phase input of +- N*pi for N odd.

    See Also:
             Fft
             Magnitude
             Phase
             Phasediff
#endif


/* add p radians of phase */
ITERATE addphase(s, p)
{
        local f, n, np, p_dc, is_real;

        if (argc < 2)
        {
                if (argc < 1) s = 0;

                p = 0;
        }

        if (not(isarray(s))) error("addphase - input series required");

        /* FFT */
        f = fft(s);

        /* get length to determine even/odd processing */
        n = length(s);

        /* real flag */
        is_real = isreal(s);

        if (is_real)
        {
                /* phase at DC, pi if p odd multiple of pi */
                p_dc = ((abs(p) / pi) % pi == 1.0) ? pi : 0;

                if (n % 2 == 0)
                {
                        /* build antisymmetric even length phase values */
                        np = (n - 2) / 2;

                        /* constant phase series */
                        p  = ones(np, 1) * p;

                        /* handle DC and Nyquist */
                        p = {p_dc, p, -p_dc, -p};
                }
                else
                {
                        /* build antisymmetric odd length phase values */
                        np = (n - 1) / 2;

                        /* constant phase series */
                        p  = ones(np, 1) * p;

                        /* handle DC */
                        p = {p_dc, p, -p};
                }
        }

        /* add phase constant */
        p = phase(f) + p;

        /* recombine with magnitude */
        f = mag(f) * exp(i * p);

        /* untransform */
        s = ifft(f);

        if (is_real)
        {
                s = real(s);
        }

        return(s);
}