View Raw SPL
/*****************************************************************************
*                                                                            *
*   FDERIV.SPL   Copyright (C) 2010 DSP Development Corporation              *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:      Randy Race                                                  *
*                                                                            *
*   Synopsis:    frequency domain derivative                                 *
*                                                                            *
*   Revisions:   10 Nov 2010  RRR  Creation                                  *
*                                                                            *
*****************************************************************************/

#if @HELP_FDERIV

    FDERIV

    Purpose: Calculates the frequency domain derivative.

    Syntax:  FDERIV(s, n)

              s  - A series, the input.

              n  - Optional, an integer. The derivative order. Defaults
                   to 1, first derivative.

    Returns: A series or array.

    Example:
             W1: demean(integ(gnorm(1000, 1)))
             W2: finteg(W1)
             W3: deriv(W2)
             W4: fderiv(W2)

             W1 contains zero mean synthesized data that is frequency
             domain integrated W2.  W3 contains a standard time domain
             derivative of W1.  W3 contains the derivative as performed
             in the frequency domain to recover W1.

    Example:
             n = 1000;
             x = extract(linspace(0, 2*pi, n), 1, n-1);

             W1: cos(x + 2*cos(3*x))
             W2: -sin(x + 2*cos(3*x)) * (1-6*sin(3*x))
             W3: fderiv(W1)
             W4: abs(W2 - W3)

             W1 contains 999 samples of the periodic function 

             cos(x + 2*cos(3*x))

             W2 contains the analytic derivative of W1 

             -sin(x + 2*cos(3*x)) * (1-6*sin(3*x))

             W3 computes the frequency domain derivative and W4 displays the
             difference between the analytic and calculated. In this case,
             the difference is negligable.
            
    Remarks:
             FDERIV computes the derivative in the frequency domain
             by calculating:

                  F(f) * (2*pi*f*i)

            where:     F(f) is the FFT of the original series
                       f    is the frequency range of the fft
                       i    = sqrt(-1)

            The result is converted back into the time domain.

            To view the result in the frequency domain, try:

                spectrum(fderiv(s))

            fderiv(s, n) computes the nth derivative with:

                  F(f) * (2*pi*f*i)^n

            where n is a positive integer.

    See Also:
             Deriv
             FFT
             Finteg
             Integ
             Spectrum
#endif


/* frequency domain derivative */
ITERATE fderiv(s, n)
{
        local len, f, y, w, u, j;

        if (argc < 2)
        {
                if (argc < 1) error("fderiv - input series required");
                
                n = 1;
        }

        /* length and delta F */
        len = length(s);
        df  = rate(s) / len;

        /* generate frequency values */
        if (len % 2 == 0)
        {
                /* even */
                f = df * concat(0..len/2, (-len/2 + 1)..-1);
        }
        else
        {
                /* odd */
                f = df * concat(0..(len-1)/2, -(len-1)/2..-1);
        }

        /* set frequency spacing */
        f.deltax = df;

        /* frequency scaling */
        w = (2 * pi * f * i);
        
        if (n != 1) w = w ^ n;

        /* frequency domain derivative */
        y = fft(s) * w;

        /* inverse transform */
        y = ifft(y);

        /* convert to real */
        if (isreal(s))
        {
                y = real(y);
        }

        /* units */
        u = s[1..2];
        
        loop (j = 1..n)
        {
                u = deriv(u);
        }

        y.vunits = u.vunits;

        /* offset */
        y.xoffset = s.xoffset;

        return(y);
}