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); }
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(); }