Ejemplo n.º 1
0
        Drivers drivers = new Drivers(); // Need driver objects for the setup of targets

        public WinFilters()
        {
            Targets targets = new Targets();

            FilterSPL.Initialize();

            InitializeComponent();

            Version version      = Assembly.GetExecutingAssembly().GetName().Version;
            string  assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

            this.Text = string.Format("{0} Version {1}.{2}.{3} Revision {4} - Windows Acoustic Filter Graphing Tool",
                                      assemblyName, version.Major, version.Minor, version.Build, version.Revision);

            systemGraph.GraphPane.Title.Text = "Magnitude and Phase";
            InitGraph.SetZedgraphFormat(systemGraph);

            // Remove the default option from all graphs
            systemGraph.ContextMenuBuilder += new ZedGraphControl.ContextMenuBuilderEventHandler(WinFilters.ContextMenuRemoveDefault);

            // Add the save options to the specific graphs
            systemGraph.ContextMenuBuilder += new ZedGraphControl.ContextMenuBuilderEventHandler(WinFilters.ContextMenuSaveLPFilterWfr);

            // Add the save options to the specific graphs
            systemGraph.ContextMenuBuilder += new ZedGraphControl.ContextMenuBuilderEventHandler(WinFilters.ContextMenuSaveHPFilterTwtr);

            ExportSPL.Instance.nominal = Convert.ToDouble(splNumeric.Value);

            Refresh(); // Refresh to paint the graph components

            // Create the frequency range array for use throughout the program.
//            frequencies.InitFrequencyRange();
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Calculates the response for a theoretical filter. These are used for design acoustic filter targets, not electrical.
        /// </summary>
        /// <param name="driver"></param>
        /// <param name="frequencyRange"></param>
        /// <param name="phaseAtFc"></param>
        /// <param name="hpIsInverted"></param>
        /// <returns>besselFactoredFc, but only if it is for a Bessel.</returns>
        public static void Calculate(DriverCore.DriverCore driver, double[] frequencyRange
                                     , double FcLP, out double splAtFcLP, out double phaseAtFcLP
                                     , double FcHP, out double splAtFcHP, out double phaseAtFcHP
                                     , out double factoredFcLP, out double factoredFcHP
                                     , bool hpIsInverted = false, double offsetMm = 0.0, bool lpIsOffset = false, bool hpIsOffset = false)
        {
            double gain            = 1;                                         // Epsilon - This allows change in gain later
            double minInterpFreq   = frequencyRange[0];
            int    rangeUpperLimit = frequencyRange.Count() - 1;                // Count of the frequency specified range
            double maxInterpFreq   = frequencyRange[rangeUpperLimit];           // Upper frequency limit of the interpolations to be made
            double interpFreq;                                                  // Used for iterations

            double[,] interpMagPhaseLP = new double[frequencyRange.Count(), 3]; // LP mag and phase.
            double[,] interpMagPhaseHP = new double[frequencyRange.Count(), 3]; // HP mag and phase.
            double[,] interpMagPhase   = new double[frequencyRange.Count(), 3]; // Array to hold interp mag and phase.
            double gainLP     = 1.0;
            double gainHP     = 1.0;
            double gainAtFcLP = 0.0;
            double gainAtFcHP = 0.0;
            double phaseLP    = 0.0;
            double phaseHP    = 0.0;

            // These are calculated on each loop, but it was needed to be able to locate the specific set of two
            // frequencies between which the Fc is located.
            splAtFcLP    = 0.0;
            splAtFcHP    = 0.0;
            phaseAtFcLP  = 0.0;
            phaseAtFcHP  = 0.0;
            factoredFcLP = 1.0;
            factoredFcHP = 1.0;

            for (int i = 0; i < rangeUpperLimit; i++)
            {
                interpFreq           = frequencyRange[i]; // Interpolation frequency points to use from the range specified.
                interpMagPhase[i, 0] = interpFreq;
                interpMagPhase[i, 1] = 1;                 // SPL default
                interpMagPhase[i, 2] = 0;                 // Phase default

                interpMagPhaseLP[i, 0] = interpMagPhase[i, 0];
                interpMagPhaseLP[i, 1] = interpMagPhase[i, 1];
                interpMagPhaseLP[i, 2] = interpMagPhase[i, 2];
                interpMagPhaseHP[i, 0] = interpMagPhase[i, 0];
                interpMagPhaseHP[i, 1] = interpMagPhase[i, 1];
                interpMagPhaseHP[i, 2] = interpMagPhase[i, 2];

                double s;
                double besselFactor = 1.0; // Multiply the Fc (divide into s)
                // Add offset to LP or HP based on user input
                double offsetDelay = (2 * Math.PI * interpMagPhase[i, 0] * (offsetMm / 344000));
                double offsetDelayAtFcLP = (2 * Math.PI * FcLP * (offsetMm / 344000));
                double offsetDelayAtFcHP = (2 * Math.PI * FcHP * (offsetMm / 344000));
                double offsetLP = 0, offsetHP = 0;
                double offsetLpAtFc = 0, offsetHpAtFc = 0;
                if (lpIsOffset)
                {
                    offsetLP = offsetDelay; offsetLpAtFc = offsetDelayAtFcLP;
                }
                if (hpIsOffset)
                {
                    offsetHP = offsetDelay; offsetHpAtFc = offsetDelayAtFcHP;
                }

                driver.target.splInterpolated[i, 1] = 0;
                driver.target.splInterpolated[i, 2] = 0;

                if ((driver.target.section == FilterCore.Section.LP) || (driver.target.section == FilterCore.Section.BP))
                {
                    s = interpFreq / driver.target.frequencyLP;

                    switch (driver.target.nameLP)
                    {
                    case AcousticTargets.FilterName.Butterworth:
                    {
                        factoredFcLP = driver.target.frequencyLP;
                        gainLP       = FilterSPL.ButterworthSPL(driver.target, driver.target.nameLP, driver.target.orderLP, gain, s);
                        phaseLP      = FilterPhase.ButterworthPhase(driver.target.orderLP, s) + offsetLP;
                        phaseLP      = FilterCore.RotatePhase(phaseLP);
                        phaseAtFcLP  = FilterPhase.ButterworthPhase(driver.target.orderLP, s = 1) + offsetLpAtFc;
                        phaseAtFcLP  = (FilterCore.RotatePhase(phaseAtFcLP) * 180.0) / Math.PI;
                        gainAtFcLP   = FilterSPL.ButterworthSPL(driver.target, driver.target.nameLP, driver.target.orderLP, gain, s = 1);
                        break;
                    }

                    case AcousticTargets.FilterName.LinkwitzRiley:
                    {
                        if (driver.target.fullTypeLP == null)
                        {
                            return;
                        }                                                         // Handle odd-order values not permissible for L-R

                        factoredFcLP = driver.target.frequencyLP;
                        gainLP       = Math.Pow(FilterSPL.ButterworthSPL(driver.target, driver.target.nameLP, driver.target.orderLP, gain, s), 2);
                        phaseLP      = FilterPhase.LinkwitzRileyPhase(driver.target.orderLP, s) + offsetLP;
                        phaseLP      = FilterCore.RotatePhase(phaseLP);
                        phaseAtFcLP  = FilterPhase.LinkwitzRileyPhase(driver.target.orderLP, s = 1) + offsetLpAtFc;
                        phaseAtFcLP  = FilterCore.RotatePhase(phaseAtFcLP) * 180 / Math.PI;
                        gainAtFcLP   = Math.Pow(FilterSPL.ButterworthSPL(driver.target, driver.target.nameLP, driver.target.orderLP, gain, s = 1), 2);
                        break;
                    }

                    case AcousticTargets.FilterName.Bessel:
                    {
                        factoredFcLP = driver.target.frequencyLP;
                        gainLP       = FilterSPL.BesselSPL(driver.target.orderLP, gain, s);
                        phaseLP      = FilterPhase.BesselPhase(driver.target.orderLP, s) + offsetLP;
                        phaseLP      = FilterCore.RotatePhase(phaseLP);
                        phaseAtFcLP  = FilterPhase.BesselPhase(driver.target.orderLP, s = 1) + offsetLpAtFc;
                        phaseAtFcLP  = FilterCore.RotatePhase(phaseAtFcLP) * 180 / Math.PI;
                        gainAtFcLP   = FilterSPL.BesselSPL(driver.target.orderLP, gain, s = 1);
                        break;
                    }

                    case AcousticTargets.FilterName.BesselPhaseMatch:
                    {
                        switch (driver.target.orderLP)
                        {
                        case 2:
                        { besselFactor = 0.58;  break; }

                        case 3:
                        { besselFactor = 1.0;   break; }

                        case 4:
                        { besselFactor = 0.31;  break; }
                        }
                        s           /= besselFactor;
                        factoredFcLP = driver.target.frequencyLP * besselFactor;
                        gainLP       = FilterSPL.BesselSPL(driver.target.orderLP, gain, s);
                        phaseLP      = FilterPhase.BesselPhase(driver.target.orderLP, s) + offsetLP;
                        phaseLP      = FilterCore.RotatePhase(phaseLP);
                        phaseAtFcLP  = FilterPhase.BesselPhase(driver.target.orderLP, s = 1 / besselFactor) + offsetLpAtFc;
                        phaseAtFcLP  = FilterCore.RotatePhase(phaseAtFcLP) * 180 / Math.PI;
                        gainAtFcLP   = FilterSPL.BesselSPL(driver.target.orderLP, gain, s = 1 / besselFactor);
                        break;
                    }

                    case AcousticTargets.FilterName.BesselFlattest:
                    {
                        switch (driver.target.orderLP)
                        {
                        case 2:
                        { besselFactor = 0.51;  break; }

                        case 3:
                        { besselFactor = 1.0;   break; }

                        case 4:
                        { besselFactor = 0.40;  break; }
                        }
                        s           /= besselFactor;
                        factoredFcLP = driver.target.frequencyLP * besselFactor;
                        gainLP       = FilterSPL.BesselSPL(driver.target.orderLP, gain, s);
                        phaseLP      = FilterPhase.BesselPhase(driver.target.orderLP, s) + offsetLP;
                        phaseLP      = FilterCore.RotatePhase(phaseLP);
                        phaseAtFcLP  = FilterPhase.BesselPhase(driver.target.orderLP, s = 1 / besselFactor) + offsetLpAtFc;
                        phaseAtFcLP  = FilterCore.RotatePhase(phaseAtFcLP) * 180 / Math.PI;
                        gainAtFcLP   = FilterSPL.BesselSPL(driver.target.orderLP, gain, s = 1 / besselFactor);
                        break;
                    }

                    case AcousticTargets.FilterName.Bessel3db:
                    {
                        switch (driver.target.orderLP)
                        {
                        case 2:
                        { besselFactor = 0.73;  break; }

                        case 3:
                        { besselFactor = 1.0;   break; }

                        case 4:
                        { besselFactor = 0.48;  break; }
                        }
                        s           /= besselFactor;
                        factoredFcLP = driver.target.frequencyLP * besselFactor;
                        gainLP       = FilterSPL.BesselSPL(driver.target.orderLP, gain, s);
                        phaseLP      = FilterPhase.BesselPhase(driver.target.orderLP, s) + offsetLP;
                        phaseLP      = FilterCore.RotatePhase(phaseLP);
                        phaseAtFcLP  = FilterPhase.BesselPhase(driver.target.orderLP, s = 1 / besselFactor) + offsetLpAtFc;
                        phaseAtFcLP  = FilterCore.RotatePhase(phaseAtFcLP) * 180 / Math.PI;
                        gainAtFcLP   = FilterSPL.BesselSPL(driver.target.orderLP, gain, s = 1 / besselFactor);
                        break;
                    }

                    case AcousticTargets.FilterName.None:
                    {
                        break;
                    }

                    default: { MessageBox.Show("Section.LP (.typeLP) is not correct."); break; }
                    }
                }

                if ((driver.target.section == FilterCore.Section.HP) || (driver.target.section == FilterCore.Section.BP))
                {
                    s = interpFreq / driver.target.frequencyHP; // f/Fc

                    switch (driver.target.nameHP)
                    {
                    case AcousticTargets.FilterName.Butterworth:
                    {
                        factoredFcHP  = driver.target.frequencyHP;
                        gainHP        = FilterSPL.ButterworthSPL(driver.target, driver.target.nameHP, driver.target.orderHP, gain, 1 / s);
                        phaseHP       = FilterPhase.ButterworthPhase(driver.target.orderHP, s, true) + offsetHP;
                        offsetHpAtFc *= factoredFcHP;         // Determine the offset using the factored Fc.
                        phaseAtFcHP   = FilterPhase.ButterworthPhase(driver.target.orderHP, s = 1, true) + offsetHpAtFc;
                        if (hpIsInverted)
                        {
                            phaseHP = FilterCore.InvertPhase(phaseHP); phaseAtFcHP = FilterCore.InvertPhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        else
                        {
                            phaseHP = FilterCore.RotatePhase(phaseHP); phaseAtFcHP = FilterCore.RotatePhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        gainAtFcHP = FilterSPL.ButterworthSPL(driver.target, driver.target.nameHP, driver.target.orderHP, gain, s = 1);
                        break;
                    }

                    case AcousticTargets.FilterName.LinkwitzRiley:
                    {
                        if (driver.target.fullTypeHP == null)
                        {
                            return;
                        }                                                         // Handle odd-order values not permissible for L-R

                        factoredFcHP = driver.target.frequencyHP;
                        if (null == driver.target.fullTypeHP)
                        {
                            return;
                        }                                                         // Handle odd-order values not permissible for L-R
                        gainHP        = Math.Pow(FilterSPL.ButterworthSPL(driver.target, driver.target.nameHP, driver.target.orderHP, gain, 1 / s), 2);
                        phaseHP       = FilterPhase.LinkwitzRileyPhase(driver.target.orderHP, s, true) + offsetHP;
                        offsetHpAtFc *= factoredFcHP;         // Determine the offset using the factored Fc.
                        phaseAtFcHP   = FilterPhase.LinkwitzRileyPhase(driver.target.orderHP, s = 1, true) + offsetHpAtFc;
                        if (hpIsInverted)
                        {
                            phaseHP = FilterCore.InvertPhase(phaseHP); phaseAtFcHP = FilterCore.InvertPhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        else
                        {
                            phaseHP = FilterCore.RotatePhase(phaseHP); phaseAtFcHP = FilterCore.RotatePhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        gainAtFcHP = Math.Pow(FilterSPL.ButterworthSPL(driver.target, driver.target.nameHP, driver.target.orderHP, gain, s = 1), 2);
                        break;
                    }

                    case AcousticTargets.FilterName.Bessel:
                    {
                        factoredFcHP  = driver.target.frequencyHP;
                        gainHP        = FilterSPL.BesselSPL(driver.target.orderHP, gain, 1 / s);
                        phaseHP       = FilterPhase.BesselPhase(driver.target.orderHP, s, true) + offsetHP;
                        offsetHpAtFc *= factoredFcHP;         // Determine the offset using the factored Fc.
                        phaseAtFcHP   = FilterPhase.BesselPhase(driver.target.orderHP, s = 1, true) + offsetHpAtFc;
                        if (hpIsInverted)
                        {
                            phaseHP = FilterCore.InvertPhase(phaseHP); phaseAtFcHP = FilterCore.InvertPhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        else
                        {
                            phaseHP = FilterCore.RotatePhase(phaseHP); phaseAtFcHP = FilterCore.RotatePhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        gainAtFcHP = FilterSPL.BesselSPL(driver.target.orderHP, gain, s = 1);
                        break;
                    }

                    case AcousticTargets.FilterName.BesselPhaseMatch:
                    {
                        switch (driver.target.orderHP)
                        {
                        case 2:
                        { besselFactor = 1 / 0.58;  break; }

                        case 3:
                        { besselFactor = 1.0;       break; }

                        case 4:
                        { besselFactor = 1 / 0.31;  break; }
                        }
                        s            /= besselFactor;
                        factoredFcHP  = driver.target.frequencyHP * besselFactor;
                        gainHP        = FilterSPL.BesselSPL(driver.target.orderHP, gain, 1 / s);
                        phaseHP       = FilterPhase.BesselPhase(driver.target.orderHP, s, true) + offsetHP;
                        offsetHpAtFc *= factoredFcHP;         // Determine the offset using the factored Fc.
                        phaseAtFcHP   = FilterPhase.BesselPhase(driver.target.orderHP, s = 1 / besselFactor, true) + offsetHpAtFc;
                        if (hpIsInverted)
                        {
                            phaseHP = FilterCore.InvertPhase(phaseHP); phaseAtFcHP = FilterCore.InvertPhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        else
                        {
                            phaseHP = FilterCore.RotatePhase(phaseHP); phaseAtFcHP = FilterCore.RotatePhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        gainAtFcHP = FilterSPL.BesselSPL(driver.target.orderHP, gain, s = 1 * besselFactor);
                        break;
                    }

                    case AcousticTargets.FilterName.BesselFlattest:
                    {
                        switch (driver.target.orderHP)
                        {
                        case 2:
                        { besselFactor = 1 / 0.51;  break; }

                        case 3:
                        { besselFactor = 1.0;       break; }

                        case 4:
                        { besselFactor = 1 / 0.40;  break; }
                        }
                        s            /= besselFactor;
                        factoredFcHP  = driver.target.frequencyHP * besselFactor;
                        gainHP        = FilterSPL.BesselSPL(driver.target.orderHP, gain, 1 / s);
                        phaseHP       = FilterPhase.BesselPhase(driver.target.orderHP, s, true) + offsetHP;
                        offsetHpAtFc *= factoredFcHP;         // Determine the offset using the factored Fc.
                        phaseAtFcHP   = FilterPhase.BesselPhase(driver.target.orderHP, s = 1 / besselFactor, true) + offsetHpAtFc;
                        if (hpIsInverted)
                        {
                            phaseHP = FilterCore.InvertPhase(phaseHP); phaseAtFcHP = FilterCore.InvertPhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        else
                        {
                            phaseHP = FilterCore.RotatePhase(phaseHP); phaseAtFcHP = FilterCore.RotatePhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        gainAtFcHP = FilterSPL.BesselSPL(driver.target.orderHP, gain, s = 1 * besselFactor);
                        break;
                    }

                    case AcousticTargets.FilterName.Bessel3db:
                    {
                        switch (driver.target.orderHP)
                        {
                        case 2:
                        { besselFactor = 1 / 0.73;  break; }

                        case 3:
                        { besselFactor = 1.0;       break; }

                        case 4:
                        { besselFactor = 1 / 0.48;  break; }
                        }
                        s            /= besselFactor;
                        factoredFcHP  = driver.target.frequencyHP * besselFactor;
                        gainHP        = FilterSPL.BesselSPL(driver.target.orderHP, gain, 1 / s);
                        phaseHP       = FilterPhase.BesselPhase(driver.target.orderHP, s, true) + offsetHP;
                        offsetHpAtFc *= factoredFcHP;         // Determine the offset using the factored Fc.
                        phaseAtFcHP   = FilterPhase.BesselPhase(driver.target.orderHP, s = 1 / besselFactor, true) + offsetHpAtFc;
                        if (hpIsInverted)
                        {
                            phaseHP = FilterCore.InvertPhase(phaseHP); phaseAtFcHP = FilterCore.InvertPhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        else
                        {
                            phaseHP = FilterCore.RotatePhase(phaseHP); phaseAtFcHP = FilterCore.RotatePhase(phaseAtFcHP) * 180 / Math.PI;
                        }
                        gainAtFcHP = FilterSPL.BesselSPL(driver.target.orderHP, gain, s = 1 * besselFactor);
                        break;
                    }

                    case AcousticTargets.FilterName.None:
                    {
                        break;
                    }

                    default: { MessageBox.Show("Section.HP (.typeHP) is not correct. Must be null."); break; }
                    }
                }

                double  factorLP   = 0.0;
                double  factorFcLP = 0.0;
                Complex complexLP  = 0.0;

                double  factorHP   = 0.0;
                double  factorFcHP = 0.0;
                Complex complexHP  = 0.0;

                interpMagPhase[i, 0] = interpFreq;

                switch (driver.target.section)
                {
                case FilterCore.Section.LP:
                {
                    factorLP = 20 * Math.Log10(gainLP);
                    interpMagPhaseLP[i, 1] = driver.target.targetMag + factorLP;         // Subtract filter factorLP (in db) from maximum gain (sensitivity)
                    interpMagPhaseLP[i, 2] = phaseLP;
                    complexLP = Complex.FromPolarCoordinates(factorLP, phaseLP);

                    factorFcLP = 20 * Math.Log10(gainAtFcLP);
                    splAtFcLP  = driver.target.targetMag + factorFcLP;

                    interpMagPhase[i, 1] = interpMagPhaseLP[i, 1];
                    interpMagPhase[i, 2] = interpMagPhaseLP[i, 2] * 180 / Math.PI;
                    break;
                }

                case FilterCore.Section.HP:
                {
                    factorHP = 20 * Math.Log10(gainHP);
                    interpMagPhaseHP[i, 1] = driver.target.targetMag + factorHP;         // Subtract filter factorHP (in db) from maximum gain (sensitivity)
                    interpMagPhaseHP[i, 2] = phaseHP;
                    complexHP = Complex.FromPolarCoordinates(factorHP, phaseHP);

                    factorFcHP = 20 * Math.Log10(gainAtFcHP);
                    splAtFcHP  = driver.target.targetMag + factorFcHP;

                    interpMagPhase[i, 1] = interpMagPhaseHP[i, 1];
                    interpMagPhase[i, 2] = interpMagPhaseHP[i, 2] * 180 / Math.PI;
                    break;
                }

                case FilterCore.Section.BP:
                {
                    // Update the out arguments
                    factorFcLP = 20 * Math.Log10(gainAtFcLP);
                    factorFcHP = 20 * Math.Log10(gainAtFcHP);
                    splAtFcLP  = driver.target.targetMag + factorFcLP;
                    splAtFcHP  = driver.target.targetMag + factorFcHP;

                    // Calculate the bandpass
                    //Complex target        = Complex.FromPolarCoordinates(driver.target.targetMag, 0.0);
                    Complex complexGainLP = Complex.FromPolarCoordinates(gainLP, phaseLP);
                    Complex complexGainHP = Complex.FromPolarCoordinates(gainHP, phaseHP);

                    Complex complexGainSum = complexGainLP * complexGainHP;
                    double  totalGainDb    = driver.target.targetMag + (20 * Math.Log10(complexGainSum.Magnitude));

                    interpMagPhase[i, 1] = totalGainDb;
                    interpMagPhase[i, 2] = complexGainSum.Phase * 180 / Math.PI;
                    break;
                }
                }
            }

            driver.target.splInterpolated = interpMagPhase;

            return;
        }