/// <summary>Configures common instrument settings for generation.</summary> /// <param name="rfsgHandle">The open RFSG session to configure.</param> /// <param name="instrConfig">The common instrument settings to configure.</param> public static void ConfigureInstrument(NIRfsg rfsgHandle, InstrumentConfiguration instrConfig) { rfsgHandle.SignalPath.SelectedPorts = instrConfig.SelectedPorts; rfsgHandle.RF.ExternalGain = -instrConfig.ExternalAttenuation_dB; rfsgHandle.RF.Configure(instrConfig.CarrierFrequency_Hz, instrConfig.DutAverageInputPower_dBm); rfsgHandle.FrequencyReference.Source = RfsgFrequencyReferenceSource.FromString(instrConfig.ReferenceClockSource); // Only configure LO settings on supported VSTs if (Regex.IsMatch(rfsgHandle.Identity.InstrumentModel, "NI PXIe-58[34].")) // Matches 583x and 584x VST families { IntPtr rfsgPtr = rfsgHandle.GetInstrumentHandle().DangerousGetHandle(); NIRfsgPlayback.RetrieveAutomaticSGSASharedLO(rfsgPtr, "", out RfsgPlaybackAutomaticSGSASharedLO currentMode); if (instrConfig.LOSharingMode == LocalOscillatorSharingMode.None && currentMode != RfsgPlaybackAutomaticSGSASharedLO.Disabled) { //Setting this property resets other settings, which can create issues. Hence, it is only set if the value //is different than the current mode. NIRfsgPlayback.StoreAutomaticSGSASharedLO(rfsgPtr, "", RfsgPlaybackAutomaticSGSASharedLO.Disabled); } else if (instrConfig.LOSharingMode == LocalOscillatorSharingMode.Automatic && currentMode != RfsgPlaybackAutomaticSGSASharedLO.Enabled) { //Setting this property resets other settings, which can create issues. Hence, it is only set if the value //is different than the current mode. NIRfsgPlayback.StoreAutomaticSGSASharedLO(rfsgPtr, "", RfsgPlaybackAutomaticSGSASharedLO.Enabled); } } //Do nothing; any configuration for LOs with standalone VSGs should be configured manually. //Baseband instruments don't have LOs. Unsupported VSTs must be configured manually. }
public void LoadMultiBurstDataTest() { string filePath = Path.GetFullPath(@"Support Files\LTE TDD Waveform.tdms"); SG.Waveform waveform = SG.LoadWaveformFromTDMS(filePath); double actualLength = waveform.WaveformData.SampleCount / waveform.SampleRate; Assert.AreEqual(waveform.BurstLength_s, actualLength, 1e-9, "Burst length should be properly calculated for multi-burst waveforms."); double papr; NIRfsgPlayback.ReadWaveformFileVersionFromFile(filePath, out string waveformVersion); if (waveformVersion == "1.0.0") { NIRfsgPlayback.ReadPeakPowerAdjustmentFromFile(filePath, 0, out papr); } else { NIRfsgPlayback.ReadPaprFromFile(filePath, 0, out papr); //Version 2.0.0 and later } Assert.AreEqual(waveform.PAPR_dB, papr, .001, "PAPR for a multi-burst waveform should match what is reported by RFmx."); }
public static void DownloadWaveform(NIRfsg rfsgHandle, Waveform waveform) { IntPtr rfsgPtr = rfsgHandle.GetInstrumentHandle().DangerousGetHandle(); rfsgHandle.Abort(); rfsgHandle.RF.PowerLevelType = RfsgRFPowerLevelType.PeakPower; try { rfsgHandle.Arb.ClearWaveform(waveform.WaveformName); //Clear existing waveform to avoid erros } catch (Ivi.Driver.OutOfRangeException) { //Intentionally ignore this exception; clearing the waveform failed because it doesn't exist } rfsgHandle.Arb.WriteWaveform(waveform.WaveformName, waveform.WaveformData); //Store loaded parameters NIRfsgPlayback.StoreWaveformSignalBandwidth(rfsgPtr, waveform.WaveformName, waveform.SignalBandwidth_Hz); NIRfsgPlayback.StoreWaveformPapr(rfsgPtr, waveform.WaveformName, waveform.PAPR_dB); NIRfsgPlayback.StoreWaveformBurstStartLocations(rfsgPtr, waveform.WaveformName, waveform.BurstStartLocations); NIRfsgPlayback.StoreWaveformBurstStopLocations(rfsgPtr, waveform.WaveformName, waveform.BurstStopLocations); NIRfsgPlayback.StoreWaveformSampleRate(rfsgPtr, waveform.WaveformName, waveform.SampleRate); //Manually configure additional settings NIRfsgPlayback.StoreWaveformLOOffsetMode(rfsgPtr, waveform.WaveformName, NIRfsgPlaybackLOOffsetMode.Disabled); NIRfsgPlayback.StoreWaveformRuntimeScaling(rfsgPtr, waveform.WaveformName, -1.5); NIRfsgPlayback.StoreWaveformRFBlankingEnabled(rfsgPtr, waveform.WaveformName, false); }
public override Task <Empty> ReadAndDownloadWaveformFromFile(RfsgServiceWaveformDownloadConfiguration request, ServerCallContext context) { var handle = (IntPtr)request.Session.Handle; NIRfsgPlayback.ReadAndDownloadWaveformFromFile(handle, request.Waveform.FilePath, request.Waveform.Name); return(Task.FromResult(new Empty())); }
void StartGeneration() { string rfsgName = resourceNameComboBox.Text; double freq = (double)frequencyNumeric.Value; double power = (double)powerLevelNumeric.Value; try { rfsgSession = new NIRfsg(rfsgName, true, false); rfsgHandle = rfsgSession.GetInstrumentHandle().DangerousGetHandle(); int i = 0; foreach (string tdmsPath in tdmsFilePaths) { NIRfsgPlayback.ReadAndDownloadWaveformFromFile(rfsgHandle, tdmsPath, tdmsWaveformNames[i]); i++; } //Q: Is it acceptable to utilize mostly private class data and keep prototype empty? I suppose if I don't aniticpate any reuse I can leave it empty... string autoScript = ScriptGen(); NIRfsgPlayback.SetScriptToGenerateSingleRfsg(rfsgHandle, autoScript); rfsgSession.RF.Configure(freq, power); rfsgSession.Initiate(); } catch (Exception uhOh) { ShowError("Start Generation", uhOh); } }
public void LoadSingleBurstDataTest() { string filePath = Path.GetFullPath(@"Support Files\WLAN Single Burst.tdms"); SG.Waveform waveform = SG.LoadWaveformFromTDMS(filePath); //This value is known empirically from the waveform configuration double actualLength = 5.132112e-3; Assert.AreEqual(waveform.BurstLength_s, actualLength, 1e-6, "Burst length should be properly calculated for a single-burst waveforms."); double papr; NIRfsgPlayback.ReadWaveformFileVersionFromFile(filePath, out string waveformVersion); if (waveformVersion == "1.0.0") { NIRfsgPlayback.ReadPeakPowerAdjustmentFromFile(filePath, 0, out papr); } else { NIRfsgPlayback.ReadPaprFromFile(filePath, 0, out papr); //Version 2.0.0 and later } Assert.AreEqual(waveform.PAPR_dB, papr, .001, "PAPR for a single-burst waveform should match what is reported by RFmx."); }
public void EntireWaveformRead() { LoopFiles((fileName, waveform, filePath, fileConfig) => { NIRfsgPlayback.ReadWaveformSizeFromFile(filePath, 0, out int size); waveform.Data.SampleCount.Should().Be(size, $"of loading file \"{fileName}\""); }); }
/// <summary>Calls <see cref="NIRfsgPlayback.SetScriptToGenerateSingleRfsg(IntPtr, string)"/>, which will download the script contained in <paramref name="waveform"/> and apply /// all associated parameters.</summary> /// <param name="rfsgHandle">The open RFSG session to configure.</param> /// <param name="waveform">Specifies the waveform and its associated script that is to be used for generation.</param> public static void ApplyWaveformAttributes(NIRfsg rfsgHandle, Waveform waveform) { if (string.IsNullOrEmpty(waveform.Script)) // default to continuous if no script in waveform { ConfigureContinuousGeneration(rfsgHandle, waveform); } else { IntPtr rfsgPtr = rfsgHandle.GetInstrumentHandle().DangerousGetHandle(); NIRfsgPlayback.SetScriptToGenerateSingleRfsg(rfsgPtr, waveform.Script); } }
public static Waveform LoadWaveformFromTDMS(string filePath, string waveformName = "", bool normalizeWaveform = true) { Waveform waveform = new Waveform(); if (string.IsNullOrEmpty(waveformName)) { waveformName = Path.GetFileNameWithoutExtension(filePath); Utilities.FormatWaveformName(ref waveformName); } waveform.WaveformName = waveformName; NIRfsgPlayback.ReadWaveformFromFileComplex(filePath, ref waveform.WaveformData); NIRfsgPlayback.ReadSignalBandwidthFromFile(filePath, 0, out waveform.SignalBandwidth_Hz); NIRfsgPlayback.ReadWaveformFileVersionFromFile(filePath, out string waveformVersion); if (waveformVersion == "1.0.0") { NIRfsgPlayback.ReadPeakPowerAdjustmentFromFile(filePath, 0, out waveform.PAPR_dB); } else { NIRfsgPlayback.ReadPaprFromFile(filePath, 0, out waveform.PAPR_dB); //Version 2.0.0 and later } NIRfsgPlayback.ReadBurstStartLocationsFromFile(filePath, 0, ref waveform.BurstStartLocations); NIRfsgPlayback.ReadBurstStopLocationsFromFile(filePath, 0, ref waveform.BurstStopLocations); //Statement reads: if NOT BurstStartLocations > 0 AND expression is not null (? operand) //In other words, manually set BurstStartLocations when the length is 0 or less or array is null if (!(waveform.BurstStartLocations?.Length > 0)) { //Set burst start to the first sample(0) waveform.BurstStartLocations = new int[1] { 0 }; } if (!(waveform.BurstStopLocations?.Length > 0)) { //Set burst stop to the last sample (number of samples minus one) waveform.BurstStopLocations = new int[1] { waveform.WaveformData.SampleCount - 1 }; } NIRfsgPlayback.ReadSampleRateFromFile(filePath, 0, out waveform.SampleRate); waveform.BurstLength_s = CalculateWaveformDuration(waveform.BurstStartLocations, waveform.BurstStopLocations, waveform.SampleRate); if (normalizeWaveform) { NormalizeWaveform(waveform); } return(waveform); }
public void PaprCalcAgreesWithCalculated() { LoopFiles((fileName, waveform, filePath, fileConfig) => { System.IntPtr rfsgHandle = sim.GetInstrumentHandle().DangerousGetHandle(); NIRfsgPlayback.DownloadUserWaveform(rfsgHandle, waveform.Name, waveform.Data, true); NIRfsgPlayback.RetrieveWaveformPapr(rfsgHandle, waveform.Name, out double calcPapr); waveform.PAPR_dB.Should().BeApproximately(calcPapr, 0.1, $"of loading file \"{fileName}\""); }); }
public static Waveform GetWaveformParametersByName(NIRfsg rfsgHandle, string waveformName) { IntPtr rfsgPtr = rfsgHandle.GetInstrumentHandle().DangerousGetHandle(); Waveform waveform = new Waveform { WaveformName = waveformName }; NIRfsgPlayback.RetrieveWaveformSignalBandwidth(rfsgPtr, waveformName, out waveform.SignalBandwidth_Hz); NIRfsgPlayback.RetrieveWaveformPapr(rfsgPtr, waveformName, out waveform.PAPR_dB); NIRfsgPlayback.RetrieveWaveformSampleRate(rfsgPtr, waveformName, out waveform.SampleRate); NIRfsgPlayback.RetrieveWaveformBurstStartLocations(rfsgPtr, waveformName, ref waveform.BurstStartLocations); NIRfsgPlayback.RetrieveWaveformBurstStopLocations(rfsgPtr, waveformName, ref waveform.BurstStopLocations); waveform.BurstLength_s = CalculateWaveformDuration(waveform.BurstStartLocations, waveform.BurstStopLocations, waveform.SampleRate); return(waveform); }
public static void ConfigureContinuousGeneration(NIRfsg rfsgHandle, Waveform waveform, string waveformStartTriggerExport = "PXI_Trig0") { //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(waveformStartTriggerExport); //A software trigger is configured that is used in the script below to control generation of //the script. This ensures that a complete packet is always generated before aborting, and //allows all generation functions to share a single abort function. rfsgHandle.Triggers.ScriptTriggers[0].ConfigureSoftwareTrigger(); string script = $@"script REPEAT{waveform.WaveformName} repeat until ScriptTrigger0 generate {waveform.WaveformName} marker0(0) end repeat end script"; //Get the instrument handle to utilize with the RFSGPlayback library IntPtr rfsgPtr = rfsgHandle.GetInstrumentHandle().DangerousGetHandle(); //Download the newly created script for generation when "Initiate" is called NIRfsgPlayback.SetScriptToGenerateSingleRfsg(rfsgPtr, script); }
public void LoadNoBurstDataTest() { string filePath = Path.GetFullPath(@"Support Files\BT No Burst.tdms"); SG.Waveform waveform = SG.LoadWaveformFromTDMS(filePath, "", true); Assert.IsTrue(waveform.BurstStartLocations[0] == 0, "Burst start set to 0"); Assert.IsTrue(waveform.BurstStopLocations[0] == waveform.WaveformData.SampleCount - 1, "Burst stop set to last sample"); double papr; NIRfsgPlayback.ReadWaveformFileVersionFromFile(filePath, out string waveformVersion); if (waveformVersion == "1.0.0") { NIRfsgPlayback.ReadPeakPowerAdjustmentFromFile(filePath, 0, out papr); } else { NIRfsgPlayback.ReadPaprFromFile(filePath, 0, out papr); //Version 2.0.0 and later } Assert.AreEqual(waveform.PAPR_dB, papr, .001, "PAPR for a no-burst waveform should match what is reported by RFmx."); }
/// <summary>Downloads a previously loaded waveform to the instrument and sets associated properties.</summary> /// <param name="rfsgHandle">The open RFSG session to configure.</param> /// <param name="waveform">The waveform data and associated properties to download to the instrument. Use <see cref="LoadWaveformFromTDMS(string, string)"/> to load a waveform from a TDMS file.</param> public static void DownloadWaveform(NIRfsg rfsgHandle, Waveform waveform) { IntPtr rfsgPtr = rfsgHandle.GetInstrumentHandle().DangerousGetHandle(); rfsgHandle.Abort(); try { rfsgHandle.Arb.ClearWaveform(waveform.Name); //Clear existing waveform to avoid erros } catch (Exception ex) { if (ex is Ivi.Driver.OutOfRangeException || ex is Ivi.Driver.IviCDriverException) { } //Intentionally ignore this exception; clearing the waveform failed because it doesn't exist else { throw; } } rfsgHandle.RF.PowerLevelType = RfsgRFPowerLevelType.PeakPower; // set power level to peak before writing so RFSG doesn't scale waveform rfsgHandle.Arb.WriteWaveform(waveform.Name, waveform.Data); //Store loaded parameters NIRfsgPlayback.StoreWaveformSignalBandwidth(rfsgPtr, waveform.Name, waveform.SignalBandwidth_Hz); NIRfsgPlayback.StoreWaveformPapr(rfsgPtr, waveform.Name, waveform.PAPR_dB); NIRfsgPlayback.StoreWaveformBurstStartLocations(rfsgPtr, waveform.Name, waveform.BurstStartLocations); NIRfsgPlayback.StoreWaveformBurstStopLocations(rfsgPtr, waveform.Name, waveform.BurstStopLocations); NIRfsgPlayback.StoreWaveformSampleRate(rfsgPtr, waveform.Name, waveform.SampleRate); NIRfsgPlayback.StoreWaveformRuntimeScaling(rfsgPtr, waveform.Name, waveform.RuntimeScaling); NIRfsgPlayback.StoreWaveformSize(rfsgPtr, waveform.Name, waveform.Data.SampleCount); //Manually configure additional settings NIRfsgPlayback.StoreWaveformLOOffsetMode(rfsgPtr, waveform.Name, NIRfsgPlaybackLOOffsetMode.Auto); NIRfsgPlayback.StoreWaveformRFBlankingEnabled(rfsgPtr, waveform.Name, false); }
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); }
void LoadWaveforms() { //Creates folder selection box FolderBrowserDialog scriptSelect = new FolderBrowserDialog(); scriptSelect.Description = "All your TDMS are belong to us"; try { scriptSelect.ShowDialog(); //tdmsFiles contains the path for all files in the directory selected by the user string[] tdmsFiles = Directory.GetFiles(scriptSelect.SelectedPath, "*.tdms"); //Foreach loop parses and loads waveform names into lsvWaveforms and RFSGplayback library List <string> sampleRates = new List <string>(); int wfmsLoaded = 0; foreach (string tdmsPath in tdmsFiles) { //Split file path, find name. string[] pathComps = tdmsPath.Split('\\', '.'); //If TDMS file extension found if (pathComps[pathComps.Length - 1] == "tdms") { //Try to load wfm into RFSG playback library, read sample rate, and then add name to waveform box try { NIRfsgPlayback.ReadSampleRateFromFile(tdmsPath, 0, out double sampleRate); sampleRates.Add(sampleRate.ToString()); wfmsLoaded++; lsvWaveforms.Items.Add(pathComps[pathComps.Length - 2]); //Adding to list because I don't know how to get items from lsvWaveforms... tdmsWaveformNames.Add(pathComps[pathComps.Length - 2]); tdmsFilePaths.Add(tdmsPath); } catch (Exception er) { //If exception is thrown for invalid TDMS file (error -303804), catch the exception but do nothing if (er.Message.Contains("Error code: -303804")) { //Do nothing } //For any other exception, throw it else { throw (er); } } } } //Check the number of waveforms loaded if (wfmsLoaded == 0) { throw new FileNotFoundException("No valid TDMS files found in specified directory."); } //Check sampleRates for distinct values. If there are more than 1 distinct value, throw exception) if (sampleRates.Distinct().Count() > 1) { throw new Exception("Different sample rates for each file detected. Ensure all TDMS waveforms use same sample rate."); } else { iqRate = double.Parse(sampleRates[0]); } } catch { //Show Error } }
public static Waveform LoadWaveformFromTDMS(ref NIRfsg rfsgHandle, string filePath, string waveformName = "", bool normalizeWaveform = true) { Waveform waveform = new Waveform { WaveformData = new ComplexWaveform <ComplexSingle>(0) }; if (string.IsNullOrEmpty(waveformName)) { waveformName = Path.GetFileNameWithoutExtension(filePath); Utilities.FormatWaveformName(ref waveformName); } waveform.WaveformName = waveformName; NIRfsgPlayback.ReadWaveformFromFileComplex(filePath, ref waveform.WaveformData); NIRfsgPlayback.ReadSignalBandwidthFromFile(filePath, 0, out waveform.SignalBandwidth_Hz); NIRfsgPlayback.ReadWaveformFileVersionFromFile(filePath, out string waveformVersion); if (waveformVersion == "1.0.0") { NIRfsgPlayback.ReadPeakPowerAdjustmentFromFile(filePath, 0, out waveform.PAPR_dB); } else { NIRfsgPlayback.ReadPaprFromFile(filePath, 0, out waveform.PAPR_dB); //Version 2.0.0 and later } NIRfsgPlayback.ReadBurstStartLocationsFromFile(filePath, 0, ref waveform.BurstStartLocations); NIRfsgPlayback.ReadBurstStopLocationsFromFile(filePath, 0, ref waveform.BurstStopLocations); // If the waveform does not have burst start or stop locations stored, then we will set the burst start to // the first sample (0) and the stop to the last sample (number of samples minus one if (waveform.BurstStartLocations == null) { waveform.BurstStartLocations = new int[1] { 0 } } ; //Separate checks because null array throws exception when checking length else if (waveform.BurstStopLocations.Length <= 0) { waveform.BurstStartLocations = new int[1] { 0 } } ; if (waveform.BurstStopLocations == null) { waveform.BurstStopLocations = new int[1] { waveform.WaveformData.SampleCount - 1 } } ; //Separate checks because null array throws exception when checking length else if (waveform.BurstStopLocations.Length <= 0) { waveform.BurstStopLocations = new int[1] { waveform.WaveformData.SampleCount - 1 } } ; waveform.SampleRate = 1 / waveform.WaveformData.PrecisionTiming.SampleInterval.FractionalSeconds; //Seconds per sample waveform.BurstLength_s = (waveform.BurstStopLocations[0] - waveform.BurstStartLocations[0]) / waveform.SampleRate; // no. samples / (samples/s) = len_s if (normalizeWaveform) { NormalizeWaveform(ref waveform); } return(waveform); }
/// <summary>Loads a waveform and relevant properties from a TDMS file.</summary> /// <param name="filePath">Specifies the absolute path to the .TDMS waveform file on disk.</param> /// <param name="waveformName">(Optional) Specifies the name to use to represent the waveform. The file name will be used by default.</param> /// <returns>The waveform data and associated properties represented in the Waveform type.</returns> public static Waveform LoadWaveformFromTDMS(string filePath, string waveformName = "") { Waveform waveform = new Waveform(); if (string.IsNullOrEmpty(waveformName)) { waveformName = Path.GetFileNameWithoutExtension(filePath); waveformName = FormatWaveformName(waveformName); } waveform.Name = waveformName; NIRfsgPlayback.ReadWaveformFromFileComplex(filePath, ref waveform.Data); NIRfsgPlayback.ReadWaveformFileVersionFromFile(filePath, out string waveformVersion); if (waveformVersion == "1.0.0") { // 1.0.0 waveforms use peak power adjustment = papr + runtime scaling // we will scale the waveform and calculate papr and runtime scaling manually float peak = ComplexSingle.GetMagnitudes(waveform.Data.GetRawData()).Max(); waveform.RuntimeScaling = 20.0 * Math.Log10(peak); NIRfsgPlayback.ReadPeakPowerAdjustmentFromFile(filePath, 0, out double peakPowerAdjustment); waveform.PAPR_dB = peakPowerAdjustment + waveform.RuntimeScaling; // scale the waveform to full scale WritableBuffer <ComplexSingle> waveformBuffer = waveform.Data.GetWritableBuffer(); ComplexSingle scale = ComplexSingle.FromPolar(1.0f / peak, 0.0f); for (int i = 0; i < waveform.Data.SampleCount; i++) { waveformBuffer[i] = waveformBuffer[i] * scale; // multiplication is faster than division } } else { NIRfsgPlayback.ReadPaprFromFile(filePath, 0, out waveform.PAPR_dB); //Version 2.0.0 and later NIRfsgPlayback.ReadRuntimeScalingFromFile(filePath, 0, out waveform.RuntimeScaling); } NIRfsgPlayback.ReadSampleRateFromFile(filePath, 0, out waveform.SampleRate); NIRfsgPlayback.ReadSignalBandwidthFromFile(filePath, 0, out waveform.SignalBandwidth_Hz); if (waveform.SignalBandwidth_Hz == 0.0) { waveform.SignalBandwidth_Hz = 0.8 * waveform.SampleRate; } NIRfsgPlayback.ReadBurstStartLocationsFromFile(filePath, 0, ref waveform.BurstStartLocations); NIRfsgPlayback.ReadBurstStopLocationsFromFile(filePath, 0, ref waveform.BurstStopLocations); //Statement reads: if NOT BurstStartLocations > 0 AND expression is not null (? operand) //In other words, manually set BurstStartLocations when the length is 0 or less or array is null if (!(waveform.BurstStartLocations?.Length > 0)) { waveform.BurstStartLocations = new int[1] { 0 } } ; //Set burst start to the first sample(0) if (!(waveform.BurstStopLocations?.Length > 0)) { waveform.BurstStopLocations = new int[1] { waveform.Data.SampleCount - 1 } } ; //Set burst stop to the last sample (number of samples minus one) // calculating IdleDurationPresent like this also accounts for tools like wlan sfp that put in burst start and stop locations even if there is no idle time in the waveform waveform.IdleDurationPresent = waveform.BurstStopLocations.First() - waveform.BurstStartLocations.First() < waveform.Data.SampleCount - 1; waveform.BurstLength_s = CalculateWaveformDuration(waveform.BurstStartLocations, waveform.BurstStopLocations, waveform.SampleRate); return(waveform); }