/// <summary>Configures common settings for memory polynomial based DPD.</summary>
        /// <param name="specAn">Specifies the SpecAn signal to configure.</param>
        /// <param name="mpConfig">Specifies the memory polynomial settings to apply.</param>
        /// <param name="selectorString">Pass an empty string. The signal name that is passed when creating the signal configuration is used.
        /// See the RFmx help for more documention of this parameter.</param>
        public static void ConfigureMemoryPolynomial(RFmxSpecAnMX specAn, MemoryPolynomialConfiguration mpConfig, string selectorString = "")
        {
            specAn.Dpd.Configuration.ConfigureDpdModel(selectorString, RFmxSpecAnMXDpdModel.GeneralizedMemoryPolynomial);
            specAn.Dpd.Configuration.ConfigureMemoryPolynomial(selectorString, mpConfig.Order, mpConfig.Depth);
            specAn.Dpd.Configuration.ConfigureGeneralizedMemoryPolynomialCrossTerms(selectorString, mpConfig.LeadOrder,
                                                                                    mpConfig.LagOrder, mpConfig.LeadMemoryDepth, mpConfig.LagMemoryDepth, mpConfig.MaximumLead, mpConfig.MaximumLag);
            RFmxSpecAnMXDpdIterativeDpdEnabled iterativeDpdEnabled = mpConfig.NumberOfIterations > 1 ? RFmxSpecAnMXDpdIterativeDpdEnabled.True : RFmxSpecAnMXDpdIterativeDpdEnabled.False;

            specAn.Dpd.Configuration.ConfigureIterativeDpdEnabled(selectorString, iterativeDpdEnabled);
            specAn.Dpd.ApplyDpd.ConfigureMemoryModelCorrectionType(selectorString, mpConfig.CorrectionType);
        }
        /// <summary>Acquires the incoming signal, trains the DPD model, applies the memory polynomial to the reference waveform, and downloads the predistorted waveform to the generator.
        ///  If generation is in progress when this function is called, generation will resume with the predistorted waveform.</summary>
        /// <param name="specAn">Specifies the SpecAn signal to configure.</param>
        /// <param name="rfsgSession">Specifies the open RFSG session to configure.</param>
        /// <param name="referenceWaveform">Specifies the <see cref="Waveform"/> whose data defines the complex baseband equivalent of the RF signal applied at the input
        /// port of the device under test when performing the measurement. See the RFmx help for more documention of this parameter.</param>
        /// <param name="selectorString">Pass an empty string. The signal name that is passed when creating the signal configuration is used.
        /// See the RFmx help for more documention of this parameter.</param>
        /// <returns>Common results after the application of memory polynomial based DPD.</returns>
        public static MemoryPolynomialResults PerformMemoryPolynomial(RFmxSpecAnMX specAn, NIRfsg rfsgSession, MemoryPolynomialConfiguration mpConfig,
                                                                      Waveform referenceWaveform, string selectorString = "")
        {
            //Instantiate new waveform with reference waveform properties
            MemoryPolynomialResults mpResults = new MemoryPolynomialResults()
            {
                PredistortedWaveform = referenceWaveform
            };

            mpResults.PredistortedWaveform.Data = referenceWaveform.Data.Clone(); // clone waveform so RFmx can't act on reference waveform
            mpResults.PredistortedWaveform.UpdateNameAndScript(referenceWaveform.Name + "postMpDpd");

            RFmxSpecAnMXDpdApplyDpdIdleDurationPresent idlePresent = referenceWaveform.IdleDurationPresent ? RFmxSpecAnMXDpdApplyDpdIdleDurationPresent.True : RFmxSpecAnMXDpdApplyDpdIdleDurationPresent.False;

            RfsgGenerationStatus preDpdGenerationStatus = rfsgSession.CheckGenerationStatus();

            rfsgSession.Abort(); // abort so we don't mess with the loop logic

            for (int i = 0; i < mpConfig.NumberOfIterations; i++)
            {
                specAn.Dpd.Configuration.ConfigurePreviousDpdPolynomial(selectorString, mpResults.Polynomial);
                rfsgSession.Initiate();
                specAn.Initiate(selectorString, "");
                specAn.WaitForMeasurementComplete(selectorString, 10.0); // wait for polynomial coefficients to be calculated
                                                                         //waveform data and PAPR are overwritten in post DPD waveform
                specAn.Dpd.ApplyDpd.ApplyDigitalPredistortion(selectorString, referenceWaveform.Data, idlePresent, 10.0, ref mpResults.PredistortedWaveform.Data,
                                                              out mpResults.PowerResults.WaveformTruePapr_dB, out mpResults.PowerResults.WaveformPowerOffset_dB);
                //Waveform's PAPR is modified to adjust the output power of the waveform on a per waveform basis rather than changing the
                //user's configured output power on the instrument
                mpResults.PredistortedWaveform.PAPR_dB = mpResults.PowerResults.WaveformPowerOffset_dB + mpResults.PowerResults.WaveformTruePapr_dB;
                DownloadWaveform(rfsgSession, mpResults.PredistortedWaveform); // implicit abort
                ApplyWaveformAttributes(rfsgSession, mpResults.PredistortedWaveform);
                specAn.Dpd.Results.FetchDpdPolynomial(selectorString, 10.0, ref mpResults.Polynomial);
            }

            mpResults.PowerResults.TrainingPower_dBm = rfsgSession.RF.PowerLevel;
            if (preDpdGenerationStatus == RfsgGenerationStatus.InProgress)
            {
                rfsgSession.Initiate(); // restart generation if it was running on function call
            }
            return(mpResults);
        }