public static void ConfigureBurstedGeneration(NIRfsg rfsgHandle, Waveform waveform, WaveformTimingConfiguration waveTiming,
                                                      PAENConfiguration paenConfig, out double period, out double idleTime)
        {
            IntPtr rfsgPtr = rfsgHandle.GetInstrumentHandle().DangerousGetHandle();

            rfsgHandle.Arb.GenerationMode = RfsgWaveformGenerationMode.Script;

            string scriptName = String.Format("{0}{1}", waveform.WaveformName, waveTiming.DutyCycle_Percent);

            if (waveTiming.DutyCycle_Percent <= 0)
            {
                throw new System.ArgumentOutOfRangeException("DutyCycle_Percent", waveTiming.DutyCycle_Percent, "Duty cycle must be greater than 0 %");
            }

            //Calculate various timining information
            double dutyCycle      = waveTiming.DutyCycle_Percent / 100;
            double totalBurstTime = waveTiming.PreBurstTime_s + waveform.BurstLength_s + waveTiming.PostBurstTime_s;

            idleTime = (totalBurstTime / dutyCycle) - totalBurstTime;
            period   = totalBurstTime + idleTime;

            //Convert all time based values to sample based values
            long preBurstSamp, postBurstSamp, idleSamp, enableSamples, disableSamples;

            preBurstSamp   = TimeToSamples(waveTiming.PreBurstTime_s, waveform.SampleRate);
            postBurstSamp  = TimeToSamples(waveTiming.PostBurstTime_s, waveform.SampleRate);
            idleSamp       = TimeToSamples(idleTime, waveform.SampleRate);
            enableSamples  = TimeToSamples(paenConfig.CommandEnableTime_s, waveform.SampleRate);
            disableSamples = TimeToSamples(paenConfig.CommandDisableTime_s, waveform.SampleRate);

            //RFSG enforces a minimum wait time of 8 samples, so ensure that the minimum pre/post burst time
            // and idle time are at least 8 samples long
            if (preBurstSamp < 8)
            {
                preBurstSamp = 8;
            }
            if (postBurstSamp < 8)
            {
                postBurstSamp = 8;
            }
            if (idleSamp < 8)
            {
                idleSamp = 8;
            }

            //Initialize the script StringBuilder with the first line of the script (name)
            StringBuilder sb = new StringBuilder($"script {scriptName}");

            sb.AppendLine();

            #region Script Building
            //If we have a static PA Enable mode, ensure that we trigger at the beginning of the script prior to looping.
            if (paenConfig.PAEnableMode == PAENMode.Static)
            {
                sb.AppendLine("wait 8 marker1(7)");
            }

            //Configure for endless repeating
            sb.AppendLine("Repeat until scriptTrigger0");

            //Configure the idle time prior to each packet generation
            sb.Append($"wait {idleSamp}");

            //If PAEN Mode is dynamic we need to trigger the PA to enable
            if (paenConfig.PAEnableMode == PAENMode.Dynamic)
            {
                //PA Enable is triggered at or before the last sample of the wait period
                long PAEnableTriggerLoc = idleSamp - enableSamples - 1;
                sb.Append($" marker1({PAEnableTriggerLoc})");
            }

            sb.AppendLine();

            //Configure waiting for the pre-burst time
            sb.AppendLine($"wait {preBurstSamp}");

            //Configure generation of the selected waveform but only for the burst length; send a trigger at the beginning of each burst
            sb.Append($"generate {waveform.WaveformName} subset({waveform.BurstStartLocations[0]},{waveform.BurstStopLocations[0]}) marker0(0)");

            //Check to see if the command time is longer than the post-burst time, which determines when the PA disable command needs sent
            bool LongCommand = waveTiming.PostBurstTime_s <= paenConfig.CommandDisableTime_s;

            if (paenConfig.PAEnableMode == PAENMode.Dynamic && LongCommand)
            {
                //Trigger is placed a number of samples from the end of the burst corresponding with
                //how much longer than the post burst time it is
                long PADisableTriggerLoc = waveform.BurstStopLocations[0] - (disableSamples - postBurstSamp) - 1;
                sb.Append($" marker1({PADisableTriggerLoc})");
            }
            sb.AppendLine();

            //Configure waiting for the post-burst time
            sb.Append($"wait {postBurstSamp}");

            //If the ommand time is shorter than the post-burst time, the disable trigger must be sent
            //during the post-burst time
            if (paenConfig.PAEnableMode == PAENMode.Dynamic && !LongCommand)
            {
                long PADisableTriggerLoc = postBurstSamp - disableSamples - 1;
                sb.Append($" marker1({PADisableTriggerLoc})");
            }
            sb.AppendLine();
            //Close out the script
            sb.AppendLine("end repeat");

            //If we have a static PA Enable mode, ensure that we trigger at the end of the script prior to concluding.
            if (paenConfig.PAEnableMode == PAENMode.Static)
            {
                sb.AppendLine("wait 10 marker1(0)");
            }

            sb.AppendLine("end script");
            #endregion

            //Download the generation script to the generator for later initiation
            NIRfsgPlayback.SetScriptToGenerateSingleRfsg(rfsgPtr, sb.ToString());

            //Configure the triggering for PA enable if selected
            if (paenConfig.PAEnableMode != PAENMode.Disabled)
            {
                rfsgHandle.DeviceEvents.MarkerEvents[1].ExportedOutputTerminal = RfsgMarkerEventExportedOutputTerminal.FromString(
                    paenConfig.PAEnableTriggerExportTerminal);
                rfsgHandle.DeviceEvents.MarkerEvents[1].OutputBehaviour = paenConfig.PAEnableTriggerMode;

                //Configure scriptTrigger0 for software triggering. This way, when it is time to abort we can stop
                //the loop and trigger the appropriate off command if PAEN mode is Static
                rfsgHandle.Triggers.ScriptTriggers[0].ConfigureSoftwareTrigger();
            }

            //Configure the trigger to be generated on the first sample of each waveform generation,
            //denoted in the script below as "marker0"
            rfsgHandle.DeviceEvents.MarkerEvents[0].ExportedOutputTerminal =
                RfsgMarkerEventExportedOutputTerminal.FromString(waveTiming.BurstStartTriggerExport);
        }
Example #2
0
      static void Main()
      {
          #region Configure Generation
          string resourceName = "VST2";
          string filePath     = Path.GetFullPath(@"Support Files\80211a_20M_48Mbps.tdms");

          NIRfsg nIRfsg = new NIRfsg(resourceName, false, false);
          InstrumentConfiguration instrConfig = new InstrumentConfiguration();
          instrConfig.SetDefaults();
          instrConfig.CarrierFrequency_Hz = 2.412e9;

          ConfigureInstrument(ref nIRfsg, instrConfig);
          Waveform waveform = LoadWaveformFromTDMS(ref nIRfsg, filePath);

          DownloadWaveform(ref nIRfsg, ref waveform);

          WaveformTimingConfiguration timing = new WaveformTimingConfiguration
          {
              DutyCycle_Percent = 60,
              PreBurstTime_s    = 1e-9,
              PostBurstTime_s   = 1e-9,
          };

          PAENConfiguration paenConfig = new PAENConfiguration
          {
              PAEnableMode = PAENMode.Dynamic,
              PAEnableTriggerExportTerminal = "PFI0",
              PAEnableTriggerMode           = RfsgMarkerEventOutputBehaviour.Toggle
          };

          ConfigureWaveformTimingAndPAControl(ref nIRfsg, ref waveform, timing, paenConfig, out double period, out _);
          nIRfsg.Initiate();
          #endregion

          RFmxInstrMX instr = new RFmxInstrMX("VST2", "");
          RFmxWlanMX  wlan  = instr.GetWlanSignalConfiguration();
          instr.GetWlanSignalConfiguration();


          CommonConfiguration commonConfiguration = new CommonConfiguration();
          commonConfiguration.SetDefaults();
          commonConfiguration.CenterFrequency_Hz = 2.412e9;

          AutoLevelConfiguration autoLevel = new AutoLevelConfiguration
          {
              AutoLevelMeasureTime_s  = period,
              AutoLevelReferenceLevel = true
          };

          SA.RFmxWLAN.ConfigureCommon(ref instr, ref wlan, commonConfiguration, autoLevel);

          SignalConfiguration signal = new SignalConfiguration();
          signal.SetDefaults();
          signal.AutoDetectSignal    = false;
          signal.ChannelBandwidth_Hz = 20e6;
          signal.Standard            = RFmxWlanMXStandard.Standard802_11ag;

          SA.RFmxWLAN.ConfigureSignal(ref wlan, signal);

          TxPConfiguration txpConfig = new TxPConfiguration
          {
              AveragingCount = 10,
              MaximumMeasurementInterval_s = waveform.BurstLength_s,
              AveragingEnabled             = RFmxWlanMXTxpAveragingEnabled.True
          };

          SA.RFmxWLAN.ConfigureTxP(ref wlan, txpConfig);

          OFDMModAccConfiguration modAccConfig = new OFDMModAccConfiguration();
          modAccConfig.SetDefaults();
          modAccConfig.OptimizeDynamicRangeForEvmEnabled = RFmxWlanMXOfdmModAccOptimizeDynamicRangeForEvmEnabled.False;
          modAccConfig.AveragingEnabled = RFmxWlanMXOfdmModAccAveragingEnabled.True;

          SA.RFmxWLAN.ConfigureOFDMModAcc(ref wlan, modAccConfig);

          TxPServoConfiguration servoConfig = new TxPServoConfiguration();
          servoConfig.SetDefaults();
          servoConfig.TargetTxPPower_dBm = 0.5;

          SA.RFmxWLAN.TxPServoPower(ref wlan, ref nIRfsg, servoConfig, autoLevel);

          SEMConfiguration semConfig = new SEMConfiguration();
          semConfig.SetDefaults();
          SA.RFmxWLAN.ConfigureSEM(ref wlan, semConfig);

          wlan.Initiate("", "");

          TxPResults        txpRes        = SA.RFmxWLAN.FetchTxP(ref wlan);
          OFDMModAccResults modAccResults = SA.RFmxWLAN.FetchOFDMModAcc(ref wlan);
          SEMResults        semResults    = SA.RFmxWLAN.FetchSEM(ref wlan);
          Console.WriteLine("TXP Avg Power: {0:N}", txpRes.AveragePowerMean_dBm);
          Console.WriteLine("Composite RMS EVM (dB): {0:N}", modAccResults.CompositeRMSEVMMean_dB);
          Console.WriteLine("\n----------Lower Offset Measurements----------\n");
          for (int i = 0; i < semResults.LowerOffsetMargin_dB.Length; i++)
          {
              Console.WriteLine("Offset {0}", i);
              Console.WriteLine("Measurement Status              :{0}",
                                semResults.lowerOffsetMeasurementStatus[i]);
              Console.WriteLine("Margin (dB)                     :{0}", semResults.LowerOffsetMargin_dB[i]);
              Console.WriteLine("Margin Frequency (Hz)           :{0}", semResults.LowerOffsetMarginFrequency_Hz[i]);
              Console.WriteLine("Margin Absolute Power (dBm)     :{0}\n", semResults.LowerOffsetMarginAbsolutePower_dBm[i]);
          }

          Console.WriteLine("\n----------Upper Offset Measurements----------\n");
          for (int i = 0; i < semResults.UpperOffsetMargin_dB.Length; i++)
          {
              Console.WriteLine("Offset {0}", i);
              Console.WriteLine("Measurement Status              :{0}", semResults.upperOffsetMeasurementStatus[i]);
              Console.WriteLine("Margin (dB)                     :{0}", semResults.UpperOffsetMargin_dB[i]);
              Console.WriteLine("Margin Frequency (Hz)           :{0}", semResults.UpperOffsetMarginFrequency_Hz[i]);
              Console.WriteLine("Margin Absolute Power (dBm)     :{0}\n", semResults.UpperOffsetMarginAbsolutePower_dBm[i]);
          }
          Console.ReadKey();

          wlan.Dispose();
          instr.Close();

          TogglePFILine(ref nIRfsg, RfsgMarkerEventToggleInitialState.DigitalLow);
          CloseInstrument(ref nIRfsg);
      }
        /// <summary>Configures the generator to generate the waveform plus idle time continuously for Dynamic EVM test cases. Also configures triggering or pulsing settings to
        /// control the DUT. Use <see cref="AbortGeneration(NIRfsg, int)"/> to abort generation to always ensure that the DUT state is returned to the initial state.</summary>
        /// <param name="rfsgHandle">The open RFSG session to configure.</param>
        /// <param name="waveform">Specifies the waveform to generate; its burst length will be used in conjuction with the duty cycle to calculate the idle time.
        /// Call <see cref="DownloadWaveform(NIRfsg, Waveform)"/> prior to calling this function.</param>
        /// <param name="waveTiming">Specifies the timing parameters used to configure the bursted generation.</param>
        /// <param name="paenConfig">Specifies parameters pertaining to how the DUT is controlled during generation.</param>
        /// <param name="period">Returns the total generation period, consisting of the waveform burst length, idle time, and any additional pre/post burst time configured.</param>
        /// <param name="idleTime">Returns the computed idle time based upon the requested duty cycle.</param>
        /// <returns>The Waveform with the "Script" parameter set to the newly created generation script.</returns>
        public static Waveform ConfigureBurstedGeneration(NIRfsg rfsgHandle, Waveform waveform, WaveformTimingConfiguration waveTiming,
                                                          PAENConfiguration paenConfig, out double period, out double idleTime)
        {
            // Validate input parameters
            if (waveTiming.DutyCycle_Percent <= 0 || waveTiming.DutyCycle_Percent >= 100)
            {
                throw new ArgumentOutOfRangeException("DutyCycle_Percent", waveTiming.DutyCycle_Percent, "Duty cycle must be greater than 0% and less than 100%. " +
                                                      "For a duty cycle of 100%, use SG.ConfigureContinuous generation instead.");
            }
            if (waveTiming.PreBurstTime_s <= 0 || waveTiming.PostBurstTime_s <= 0)
            {
                throw new ArgumentOutOfRangeException("PreBurstTime | PostBurstTime", "PreBurstTime and PostBurstTime must be greater than 0 seconds");
            }

            //Download the generation script to the generator for later initiation
            waveform.Script = GenerateBurstedScript(paenConfig, waveTiming, waveform, out period, out idleTime);
            ApplyWaveformAttributes(rfsgHandle, waveform);

            //Configure the triggering for PA enable if selected
            if (paenConfig.PAEnableMode != PAENMode.Disabled)
            {
                rfsgHandle.DeviceEvents.MarkerEvents[1].ExportedOutputTerminal = RfsgMarkerEventExportedOutputTerminal.FromString(
                    paenConfig.PAEnableTriggerExportTerminal);
                rfsgHandle.DeviceEvents.MarkerEvents[1].OutputBehaviour = paenConfig.PAEnableTriggerMode;

                // Ensure that the initial state for the digital line is low when using toggle mode to ensure the DUT state is correct
                rfsgHandle.DeviceEvents.MarkerEvents[1].ToggleInitialState = RfsgMarkerEventToggleInitialState.DigitalLow;
            }
            //Configure scriptTrigger0 for software triggering. This way, when it is time to abort we can stop
            //the loop and trigger the appropriate off command if PAEN mode is Static
            rfsgHandle.Triggers.ScriptTriggers[0].ConfigureSoftwareTrigger();

            //Configure the trigger to be generated on the first sample of each waveform generation,
            //denoted in the script below as "marker0"
            rfsgHandle.DeviceEvents.MarkerEvents[0].ExportedOutputTerminal =
                RfsgMarkerEventExportedOutputTerminal.FromString(waveTiming.BurstStartTriggerExport);

            // Return updated waveform struct to caller
            return(waveform);
        }
        /// <summary>Creates the generation script used for bursted generation.</summary>
        /// <param name="waveTiming">Specifies the timing parameters used to configure the bursted generation.</param>
        /// <param name="paenConfig">Specifies parameters pertaining to how the DUT is controlled during generation.</param>
        /// <param name="waveform">Specifies the waveform to generate; its burst length will be used in conjuction with the duty cycle to calculate the idle time.</param>
        /// <param name="generationPeriod_s">Returns the total generation period, consisting of the waveform burst length, idle time, and any additional pre/post burst time configured.</param>
        /// <param name="idleTime_s">Returns the computed idle time based upon the requested duty cycle.</param>
        /// <returns>The script to implement the requested bursted generation timing.</returns>
        private static string GenerateBurstedScript(PAENConfiguration paenConfig, WaveformTimingConfiguration waveTiming, Waveform waveform,
                                                    out double generationPeriod_s, out double idleTime_s)
        {
            string scriptName = string.Format("{0}{1}", waveform.Name, waveTiming.DutyCycle_Percent);

            //Calculate various timining information
            double dutyCycle      = waveTiming.DutyCycle_Percent / 100;
            double totalBurstTime = waveTiming.PreBurstTime_s + waveform.BurstLength_s + waveTiming.PostBurstTime_s;

            idleTime_s         = (totalBurstTime / dutyCycle) - totalBurstTime;
            generationPeriod_s = totalBurstTime + idleTime_s;

            //Convert all time based values to sample based values
            long preBurstSamp, postBurstSamp, idleSamp, enableSamples, disableSamples;

            preBurstSamp   = TimeToSamples(waveTiming.PreBurstTime_s, waveform.SampleRate);
            postBurstSamp  = TimeToSamples(waveTiming.PostBurstTime_s, waveform.SampleRate);
            idleSamp       = TimeToSamples(idleTime_s, waveform.SampleRate);
            enableSamples  = TimeToSamples(paenConfig.CommandEnableTime_s, waveform.SampleRate);
            disableSamples = TimeToSamples(paenConfig.CommandDisableTime_s, waveform.SampleRate);

            //RFSG enforces a minimum wait time of 8 samples, so ensure that the minimum pre/post burst time
            // and idle time are at least 8 samples long
            if (preBurstSamp < 8)
            {
                preBurstSamp = 8;
            }
            if (postBurstSamp < 8)
            {
                postBurstSamp = 8;
            }
            if (idleSamp < 8)
            {
                idleSamp = 8;
            }

            //Initialize the script StringBuilder with the first line of the script (name)
            StringBuilder sb = new StringBuilder($"script {scriptName}");

            sb.AppendLine();

            #region Script Building
            //If we have a static PA Enable mode, ensure that we trigger at the beginning of the script prior to looping.
            if (paenConfig.PAEnableMode == PAENMode.Static)
            {
                sb.AppendLine("wait 8 marker1(7)");
            }

            //Configure for endless repeating
            sb.AppendLine("Repeat until scriptTrigger0");

            //Configure the idle time prior to each packet generation
            sb.Append($"wait {idleSamp}");

            //If PAEN Mode is dynamic we need to trigger the PA to enable
            if (paenConfig.PAEnableMode == PAENMode.Dynamic)
            {
                //PA Enable is triggered at or before the last sample of the wait period
                long PAEnableTriggerLoc = idleSamp - enableSamples - 1;
                sb.Append($" marker1({PAEnableTriggerLoc})");
            }

            sb.AppendLine();

            //Configure waiting for the pre-burst time
            sb.AppendLine($"wait {preBurstSamp}");

            //Configure generation of the selected waveform but only for the burst length; send a trigger at the beginning of each burst
            sb.Append($"generate {waveform.Name} subset({waveform.BurstStartLocations[0]},{waveform.BurstStopLocations[0]}) marker0(0)");

            //Check to see if the command time is longer than the post-burst time, which determines when the PA disable command needs sent
            bool LongCommand = waveTiming.PostBurstTime_s <= paenConfig.CommandDisableTime_s;

            if (paenConfig.PAEnableMode == PAENMode.Dynamic && LongCommand)
            {
                //Trigger is placed a number of samples from the end of the burst corresponding with
                //how much longer than the post burst time it is
                long PADisableTriggerLoc = waveform.BurstStopLocations[0] - (disableSamples - postBurstSamp) - 1;
                sb.Append($" marker1({PADisableTriggerLoc})");
            }
            sb.AppendLine();

            //Configure waiting for the post-burst time
            sb.Append($"wait {postBurstSamp}");

            //If the ommand time is shorter than the post-burst time, the disable trigger must be sent
            //during the post-burst time
            if (paenConfig.PAEnableMode == PAENMode.Dynamic && !LongCommand)
            {
                long PADisableTriggerLoc = postBurstSamp - disableSamples - 1;
                sb.Append($" marker1({PADisableTriggerLoc})");
            }
            sb.AppendLine();
            //Close out the script
            sb.AppendLine("end repeat");

            //If we have a static PA Enable mode, ensure that we trigger at the end of the script prior to concluding.
            if (paenConfig.PAEnableMode == PAENMode.Static)
            {
                sb.AppendLine("wait 10 marker1(0)");
            }

            sb.AppendLine("end script");
            #endregion

            return(sb.ToString());
        }
        static void Main(string[] args)
        {
            #region Station Configuration
            string      sgName      = "VST2";
            string      digitalName = "PXIe-6570";
            DigitalMode desiredMode = DigitalMode.Digital_Enable;
            //To calculate this delay, use the TDR feature of the Digital Pattern Editor (DPE)
            //In the DPE, navigate to Instruments ยป TDR...
            double PFI0CableDelay_s = 11.4e-9;
            #endregion

            #region SG Configuration
            NIRfsg rfsgSession = new NIRfsg(sgName, false, false);

            InstrumentConfiguration instrConfig = new InstrumentConfiguration
            {
                ReferenceClockSource     = RfsgFrequencyReferenceSource.PxiClock,
                CarrierFrequency_Hz      = 2.402e9,
                DutAverageInputPower_dBm = 0,
                ShareLOSGToSA            = false,
            };

            ConfigureInstrument(rfsgSession, instrConfig);

            string waveformPath = Path.GetFullPath(@"TDMS Files\11AC_MCS8_40M.tdms");

            Waveform wave = LoadWaveformFromTDMS(waveformPath, "wave");
            DownloadWaveform(rfsgSession, wave);

            WaveformTimingConfiguration waveTiming = new WaveformTimingConfiguration
            {
                DutyCycle_Percent       = 20,
                PreBurstTime_s          = 2000e-9,
                PostBurstTime_s         = 500e-9,
                BurstStartTriggerExport = "PXI_Trig0"
            };
            PAENConfiguration paenConfig = new PAENConfiguration
            {
                PAEnableMode = PAENMode.Dynamic,
                PAEnableTriggerExportTerminal = "PFI0",
                PAEnableTriggerMode           = RfsgMarkerEventOutputBehaviour.Toggle,
            };

            switch (desiredMode)
            {
            case DigitalMode.RFFE_MIPI:
                //Calculate the command length by multiplying the number of vector cycles (18 for Reg0Write)
                //by the clock rate (currently 52 MHz)
                paenConfig.CommandEnableTime_s  = 18 * (1 / 52e6);
                paenConfig.CommandDisableTime_s = 18 * (1 / 52e6);
                break;

            case DigitalMode.Digital_Enable:
                //For the digital enable case, the command time can be considered to be 0 since the digital
                //line is simply being toggled high/low
                paenConfig.CommandDisableTime_s = 0;
                paenConfig.CommandEnableTime_s  = 0;
                break;
            }
            //Until NI-DIGITAL 19.0 is released, the triggering mechanism used is to trigger using the PFI line
            //and detecting the change with a match opcode. There are a total of 830 cycles of the instrument required
            //before the command is sent from the pattern. Hence, an 830ns delay is added to the command time to account
            //for this.
            paenConfig.CommandEnableTime_s  += 830e-9;
            paenConfig.CommandDisableTime_s += 830e-9;

            ConfigureBurstedGeneration(rfsgSession, wave, waveTiming, paenConfig, out _, out _);
            #endregion

            #region NI Digital Config
            NIDigital digital = new NIDigital(digitalName, false, false);

            ProjectFiles projectFiles = Digital.Utilities.SearchForProjectFiles(Path.GetFullPath(@"Dynamic Digital Control Project"), true);
            LoadProjectFiles(digital, projectFiles);

            ApplyPinTDROffset(digital, "PFI0", PFI0CableDelay_s);

            //Select the appropriate pattern based on the desired control mechanism
            switch (desiredMode)
            {
            case DigitalMode.Digital_Enable:
                digital.PatternControl.BurstPattern("", "Dynamic_Digital_Enable", true, false, TimeSpan.FromSeconds(10));
                break;

            case DigitalMode.RFFE_MIPI:
                digital.PatternControl.BurstPattern("", "Dynamic_RFFE_Control", true, false, TimeSpan.FromSeconds(10));
                break;
            }

            #endregion

            rfsgSession.Initiate();

            Console.WriteLine("Generation on the signal generator and digital pattern instrument has begun. Press any key to abort generation and exit the program.");
            Console.ReadKey();

            AbortGeneration(rfsgSession);

            digital.PatternControl.Abort();

            DisconnectAndClose(digital);
            rfsgSession.Close();
        }