//////////////////////////////////////////////////////////////////////////////// // // Function: createDeemphasisFilter // // Arguments: length: Filter kernel length. // sampleRate: System sample rate in Hertz. Must // be greater than 0. // doAnalysis: If set to true, this function will // calculate and print the filter response. // correctPhase: If set to true, this function corrects the // phase distortion produced by the pre- // emphasis filter. // // Returns: Returns a pointer to a struct containing pointer to the // filter kernel plus other information // // Description: This function creates a filter kernel that implements // the de-emphasis filter needed to compensate for the pre- // emphasis filtering that is present on some CD recordings. // The filter will correct the frequency response of the input // to produce an output that should have a spectrum identical // to the original recording before an emphasis filter was // applied. If the correctPhase switch is set to true, then // the phase is also corrected; if not, a linear phase filter // is created. // //////////////////////////////////////////////////////////////////////////////// public static Deemphasis createDeemphasisFilter(int length, double sampleRate, bool correctPhase, bool doAnalysis) { // Make sure the length of the filter is at least 8 samples if (length < 8) { throw new ArgumentOutOfRangeException("length", "" + length); } // Make sure the length of the filter is power of 2 if (!Utility.isPowerOf2(length)) { throw new ArgumentOutOfRangeException("length", "" + length); } // Make sure the sample rate is greater than 0 if (sampleRate <= 0) { throw new ArgumentOutOfRangeException("sampleRate", "" + sampleRate); } // Calculate the bin size double binSize = sampleRate / (double)length; // Make sure the binsize is > 0 and <= 1/4 of the sample rate. This // guarantees at least 3 data points when calculating the filter // response, i.e. at DC, nyquist/2, and nyquist. if ((binSize <= 0) || (binSize > sampleRate / 4)) { throw new ArgumentOutOfRangeException("binSize", "" + binSize); } // Allocate memory for the deemphasis filter struct Deemphasis deemphasis = new Deemphasis(length, sampleRate, binSize, correctPhase, doAnalysis); // Calculate the ideal frequency response of the de-emphasis filter deemphasis.idealFilterResponse = IdealResponse.calculateIdealResponse(length, sampleRate); // Create the de-emphasis filter kernel, using the ideal filter response deemphasis.filterKernel = createFilterKernel(deemphasis.idealFilterResponse, deemphasis.correctPhase); // If we are doing analysis, then calculate the response and deviation // of this filter kernel, and print out the results if (deemphasis.doAnalysis) { // Calculate the actual filter response //deemphasis.actualFilterResponse = // IdealResponse.calculateIdealResponse(deemphasis.filterKernel, // sampleRate, binSize); // Calculate and print out deviations for // amplitude (dB), phase Delay (s), group delay (s) //deemphasis.deviation = Deviation.calculateDeviation(deemphasis); } // Return a pointer to the newly created deemphasis struct return(deemphasis); }
//////////////////////////////////////////////////////////////////////////////// // // Function: calculateDeviation // // Arguments: deemphasisFilter: A pointer to a calculated deemphasis // filter. // // Returns: A pointer to a deviation struct. // // Description: This function calculates the deviation between the ideal // deemphasis filter response and the actual deemphasis filter // response embodied in the calculated filter kernel. In // particular, the deviation of the amplitude response (in dB), // phase delay (in seconds), and group delay (in seconds) is // calculated. // //////////////////////////////////////////////////////////////////////////////// public static Deviation calculateDeviation(Deemphasis deemphasisFilter) { int length; // Make sure we have valid pointers if (deemphasisFilter == null) { throw new ArgumentNullException("deemphasisFilter"); } if (deemphasisFilter.idealFilterResponse == null) { throw new ArgumentNullException("deemphasisFilter.idealFilterResponse"); } if (deemphasisFilter.actualFilterResponse == null) { throw new ArgumentNullException("deemphasisFilter.actualFilterResponse"); } if (deemphasisFilter.idealFilterResponse.frequency == null) { throw new ArgumentNullException("deemphasisFilter.idealFilterResponse.frequency"); } if (deemphasisFilter.idealFilterResponse.amplitudeDB == null) { throw new ArgumentNullException("deemphasisFilter.idealFilterResponse.amplitudeDB"); } if (deemphasisFilter.idealFilterResponse.phaseDelay == null) { throw new ArgumentNullException("deemphasisFilter.idealFilterResponse.phaseDelay"); } if (deemphasisFilter.idealFilterResponse.groupDelay == null) { throw new ArgumentNullException("deemphasisFilter.idealFilterResponse.groupDelay"); } if (deemphasisFilter.actualFilterResponse.frequency == null) { throw new ArgumentNullException("deemphasisFilter.actualFilterResponse.frequency"); } if (deemphasisFilter.actualFilterResponse.amplitudeDB == null) { throw new ArgumentNullException("deemphasisFilter.actualFilterResponse.amplitudeDB"); } if (deemphasisFilter.actualFilterResponse.phaseDelay == null) { throw new ArgumentNullException("deemphasisFilter.actualFilterResponse.phaseDelay"); } if (deemphasisFilter.actualFilterResponse.groupDelay == null) { throw new ArgumentNullException("deemphasisFilter.actualFilterResponse.groupDelay"); } // Allocate memory for the deviation struct Deviation deviation = new Deviation(); // Calculate the length of the deviation vectors length = deemphasisFilter.actualFilterResponse.frequency.Length; // Copy the frequency vector from the actual filter response deviation.frequency = (double[])deemphasisFilter.actualFilterResponse.frequency.Clone(); // Create the deviation vectors deviation.amplitudeDB = new double[length]; deviation.phaseDelay = new double[length]; deviation.groupDelay = new double[length]; // Calculate the position of the DC component in the ideal filter // response vectors int DCIndex = (deemphasisFilter.idealFilterResponse.amplitudeDB.Length / 2) - 1; // Calculate the amplitude deviation for (int i = 0, j = DCIndex; i < length; i++, j++) { deviation.amplitudeDB[i] = deemphasisFilter.actualFilterResponse.amplitudeDB[i] - deemphasisFilter.idealFilterResponse.amplitudeDB[j]; } // Record the minimum and maximum amplitude deviations deviation.amplitudeDeviationMin = deviation.amplitudeDB.Min(); deviation.amplitudeDeviationMax = deviation.amplitudeDB.Max(); // Calculate the phase delay deviation // First calculate the offset at f = 0 double offset = deemphasisFilter.actualFilterResponse.phaseDelay[0] - deemphasisFilter.idealFilterResponse.phaseDelay[DCIndex]; // Then calculate the deviation for each element for (int i = 0, j = DCIndex; i < length; i++, j++) { deviation.phaseDelay[i] = deemphasisFilter.actualFilterResponse.phaseDelay[i] - deemphasisFilter.idealFilterResponse.phaseDelay[j] - offset; } // Record the minimum and maximum phase delay deviations deviation.phaseDelayDeviationMin = deviation.phaseDelay.Min(); deviation.phaseDelayDeviationMax = deviation.phaseDelay.Max(); // Calculate the group delay deviation // First calculate the offset at f = 0 offset = deemphasisFilter.actualFilterResponse.groupDelay[0] - deemphasisFilter.idealFilterResponse.groupDelay[DCIndex]; // Then calculate the deviation for each element for (int i = 0, j = DCIndex; i < length; i++, j++) { deviation.groupDelay[i] = deemphasisFilter.actualFilterResponse.groupDelay[i] - deemphasisFilter.idealFilterResponse.groupDelay[j] - offset; } // Record the minimum and maximum group delay deviations deviation.groupDelayDeviationMin = deviation.groupDelay.Min(); deviation.groupDelayDeviationMax = deviation.groupDelay.Max(); // Return a pointer to the newly calculated deviation structure return(deviation); }