Пример #1
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        //  Function:       calculateAmplitudeAndPhase
        //
        //  Arguments:      response:     Pointer to the response structure.
        //                  R1:           The resister 1 value in Ohms.
        //                  Rf:           The feedback resistor value in Ohms.
        //                  C1:           The capacitor value in Farads.
        //
        //  Returns:        void
        //
        //  Description:    The function calculates the amplitude response (both linear
        //                  and dB) of the ideal de-emphasis filter. It also calculates
        //                  the phase response (in radians), phase delay (in seconds),
        //                  and group delay (in seconds) of the ideal filter. Note that
        //                  this function assumes that the frequency and complex
        //                  response vectors have already been calculated.
        //
        ////////////////////////////////////////////////////////////////////////////////

        private static void calculateAmplitudeAndPhase(IdealResponse response, double R1, double Rf,
                                                       double C1)
        {
            // Make sure we have a valid pointer
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            // Calculate the magnitude of the frequency response
            for (int i = 0; i < response.complexResponse.Length; i++)
            {
                // Isolate the real and imaginary parts of the complex response
                double a = response.complexResponse[i].Real;
                double b = response.complexResponse[i].Imaginary;

                // Calculate the linear amplitude
                response.amplitudeLinear[i] = Math.Sqrt((a * a) + (b * b));

                // Calculate the dB-scaled amplitude from the linear amplitude
                response.amplitudeDB[i] =
                    FourierAnalysis.convertToDB(response.amplitudeLinear[i]);

                // Calculate the phase response (in radians)
                response.phaseRadians[i] = Math.Atan(b / a);

                // Calculate the phase delay (in seconds)
                if (response.frequency[i] == 0.0)
                {
                    // The phase delay at f = 0 is a special case: it is C1 * Rf
                    response.phaseDelay[i] = C1 * Rf;
                }
                else
                {
                    // The phase delay is phi(f) = - phase(f) / (2 * Pi * f)
                    response.phaseDelay[i] =
                        response.phaseRadians[i] /
                        (-Constants.TAU * response.frequency[i]);
                }

                // Calculate the group delay (in seconds)
                response.groupDelay[i] =
                    groupDelayFunc(response.frequency[i], R1, Rf, C1);
            }
        }
Пример #2
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        //  Function:       createFilterKernel
        //
        //  Arguments:      idealResponse:     Pointer to the ideal filter response.
        //
        //  Returns:        A pointer to the newly-created filter kernel.
        //
        //  Description:    This function creates a real-valued filter kernel whose
        //                  response closely matches the response of the ideal
        //                  de-emphasis filter, including phase correction.
        //
        ////////////////////////////////////////////////////////////////////////////////

        private static double[] createFilterKernel(IdealResponse idealResponse,
                                                   bool correctPhase)
        {
            int    i, j;
            double a, b, magnitude;


            // Make sure we have a valid pointer
            if (idealResponse == null)
            {
                throw new ArgumentNullException("idealResponse");
            }

            // Create a complex vector to hold the rotated complex filter response
            Complex[] complexFilterKernel = new Complex[idealResponse.complexResponse.Length];

            // Calculate the number of (positive or negative) harmonics. Since the
            // complex response contains both positive and negative frequencies, this
            // will be 1/2 its length.
            int numberHarmonics = complexFilterKernel.Length / 2;

            // Calculate the position of the DC component
            int DCIndex = numberHarmonics - 1;

            // Rotate and copy the complex response into the vector. We rotate so that
            // the harmonics are ordered as follows:
            //    0 (DC), 1, 2, 3, ..., N-1, N (nyquist), -(N-1), ..., -3, -2, -1
            // First copy from the harmonics ranging from 0 (DC) to N (nyquist)
            // into the vector
            for (i = 0, j = DCIndex; j < complexFilterKernel.Length; i++, j++)
            {
                complexFilterKernel[i] =
                    idealResponse.complexResponse[j];
            }

            // Make note of the position of the sample at the Nyquist frequency
            int nyquistPosition = i - 1;

            // And then copy the harmonics ranging from -(N-1) to -1 into the vector.
            // Note that we assume the value of i is carried over from previous loop.
            for (j = 0; j < DCIndex; i++, j++)
            {
                complexFilterKernel[i] =
                    idealResponse.complexResponse[j];
            }

            // If we are NOT doing phase correction, then we are creating a filter
            // with linear phase. We must use the magnitude for the real part of the
            // complex response, and set the imaginary part to zero.
            if (correctPhase == false)
            {
                for (i = 0; i < complexFilterKernel.Length; i++)
                {
                    a         = complexFilterKernel[i].Real;
                    b         = complexFilterKernel[i].Imaginary;
                    magnitude = Math.Sqrt((a * a) + (b * b));
                    complexFilterKernel[i] = magnitude + Complex.ImaginaryOne * 0;
                }
            }

            // Correct the complex filter kernel by setting the phase at the nyquist
            // frequency to zero. The imaginary part is zeroed, and the real part
            // is given the full magnitude of the original complex value.
            a         = complexFilterKernel[nyquistPosition].Real;
            b         = complexFilterKernel[nyquistPosition].Imaginary;
            magnitude = Math.Sqrt((a * a) + (b * b));
            complexFilterKernel[nyquistPosition] = magnitude + Complex.ImaginaryOne * 0;

            // Perform a complex scaled in-place IFFT on the complex response. The
            // result is a complex vector, where all the imaginary components should be
            // 0.0. Note that the IFFT gives imaginary components very close to 0.0,
            // while the IDFT gives a noisier result.
            FourierAnalysis.complexScaledIFFT(complexFilterKernel);

            // Copy the real part of the complex vector into a newly-created real vector
            double[] temp = new double[complexFilterKernel.Length];
            for (i = 0; i < temp.Length; i++)
            {
                temp[i] = complexFilterKernel[i].Real;
            }

            // Rotate the vector by N/2 to create the unwindowed filter kernel
            double[] kernel   = new double[temp.Length];
            int      midpoint = temp.Length / 2;

            for (i = 0, j = midpoint; j < temp.Length; i++, j++)
            {
                kernel[i] = temp[j];
            }
            for (j = 0; j < midpoint; i++, j++)
            {
                kernel[i] = temp[j];
            }

            // Apply the Blackman-Harris window to the kernel, to reduce aliasing
            // which shows up as ripples in the filter's response
            applyHarrisWindow(kernel);

            // Return a pointer to the newly-calculated filter kernel
            return(kernel);
        }