public void TestConfigureLookUpTable() { LookUpTableConfiguration lutConfig = new LookUpTableConfiguration() { DutAverageInputPower_dBm = 10.0, // results in no scaling of iq data DutInputPower_dBm = new float[] { 1.0f, 3.0f, 2.0f, 4.0f }, SupplyVoltage_V = new float[] { 5.0f, 7.0f, 6.0f, 8.0f } }; Waveform referenceWaveform = new Waveform() { Data = ComplexWaveform <ComplexSingle> .FromArray1D(new ComplexSingle[] { ComplexSingle.FromSingle(0.5f), ComplexSingle.FromSingle(1.5f), ComplexSingle.FromSingle(2.5f), ComplexSingle.FromSingle(3.5f), ComplexSingle.FromSingle(4.5f) }) }; // p = 10log(i^2) + 10 // i = sqrt(10**(p - 10) / 10) var writableBuffer = referenceWaveform.Data.GetWritableBuffer(); for (int i = 0; i < referenceWaveform.Data.SampleCount; i++) { writableBuffer[i] = ComplexSingle.FromSingle((float)Math.Sqrt(Math.Pow(10.0, (writableBuffer[i].Real - 10.0) / 10.0))); } Waveform envelopeWaveform = CreateLookUpTableEnvelopeWaveform(referenceWaveform, lutConfig); ComplexSingle.DecomposeArrayPolar(envelopeWaveform.Data.GetRawData(), out float[] yi, out _); float[] solution = new float[] { 4.5f, 5.5f, 6.5f, 7.5f, 8.5f }; using (new AssertionScope()) { for (int i = 0; i < yi.Length; i++) { yi[i].Should().BeApproximately(solution[i], 0.1f); } } }
/// <summary>Creates an envelope waveform utilizing the lookup table method.</summary> /// <param name="referenceWaveform">Specifies the waveform used for RF signal generation.</param> /// <param name="lookUpTableConfig">Specifies common settings for creating the lookup table envelope waveform.</param> /// <returns>The lookup table envelope waveform.</returns> public static Waveform CreateLookUpTableEnvelopeWaveform(Waveform referenceWaveform, LookUpTableConfiguration lookUpTableConfig) { ComplexSingle[] iq = referenceWaveform.Data.GetRawData(); // get copy of iq samples /// power conversions needed to understand following scaling: /// power_dBW = 20log(V) - 10log(R) - since R is 100 we get power_dBW = 20log(V) - 20 /// if we want to normalize to dbW 1ohm, we would have 20log(V) - 10log(1) = 20log(V) /// power_dBm = power_dBW + 30 therefore power_dBm = 20log(V) + 10 /// therefore, to convert from dBm to dBW 1ohm we subtract 10 from dBm value // scale waveform to have average dBW 1ohm power equal to dut input power normalized to dBW 1ohm ComplexSingle scale = ComplexSingle.FromSingle((float)Math.Pow(10.0, (referenceWaveform.PAPR_dB + lookUpTableConfig.DutAverageInputPower_dBm - 10.0) / 20.0)); for (int i = 0; i < iq.Length; i++) { iq[i] *= scale; } // get 1 ohm power trace in watts of scaled iq data float[] powerTrace_W = new float[iq.Length]; for (int i = 0; i < iq.Length; i++) { powerTrace_W[i] = iq[i].Real * iq[i].Real + iq[i].Imaginary * iq[i].Imaginary; } // get lookup table input power trace in 1ohm watts float[] lutDutInputPowerWattOneOhm = new float[lookUpTableConfig.DutInputPower_dBm.Length]; for (int i = 0; i < lookUpTableConfig.DutInputPower_dBm.Length; i++) { lutDutInputPowerWattOneOhm[i] = (float)Math.Pow(10.0, (lookUpTableConfig.DutInputPower_dBm[i] - 10.0) / 10.0); // V^2 = 10^((Pin - 10.0)/10) } // run the trace through 1D interpolation float[] rawEnvelope = LinearInterpolation1D(lutDutInputPowerWattOneOhm, lookUpTableConfig.SupplyVoltage_V, powerTrace_W); // create waveform to return to the user Waveform envelopeWaveform = CloneAndConditionReferenceWaveform(referenceWaveform); // copy raw envelope data into cloned envelope waveform WritableBuffer <ComplexSingle> envWfmWriteBuffer = envelopeWaveform.Data.GetWritableBuffer(); for (int i = 0; i < rawEnvelope.Length; i++) { envWfmWriteBuffer[i] = ComplexSingle.FromSingle(rawEnvelope[i]); } return(envelopeWaveform); }
/// <summary> /// This example illustrates how to use RFSG drivers and envelope tracking APIs to configure envelope tracking. /// </summary> static void Main(string[] args) { #region Example Settings // Select mode for use in the example EnvelopeMode mode = EnvelopeMode.Detrough; string waveformPath = @"C:\Users\Public\Documents\National Instruments\RFIC Test Software\Waveforms\LTE_FDD_DL_1x20MHz_TM11_OS4.tdms"; #endregion #region Configure RF Generator // Initialize instrument sessions NIRfsg rfVsg = new NIRfsg("5840", true, false); // Load up waveform Waveform rfWfm = LoadWaveformFromTDMS(waveformPath); // Configure RF generator InstrumentConfiguration rfInstrConfig = InstrumentConfiguration.GetDefault(); ConfigureInstrument(rfVsg, rfInstrConfig); DownloadWaveform(rfVsg, rfWfm); ConfigureContinuousGeneration(rfVsg, rfWfm); #endregion #region Configure Tracker Generator NIRfsg envVsg = new NIRfsg("5820", true, false); // Configure envelope generator EnvelopeGeneratorConfiguration envInstrConfig = EnvelopeGeneratorConfiguration.GetDefault(); TrackerConfiguration trackerConfig = TrackerConfiguration.GetDefault(); ConfigureEnvelopeGenerator(envVsg, envInstrConfig, trackerConfig); Waveform envWfm = new Waveform(); switch (mode) { case EnvelopeMode.Detrough: // Create envelope waveform DetroughConfiguration detroughConfig = DetroughConfiguration.GetDefault(); detroughConfig.MinimumVoltage_V = 1.5; detroughConfig.MaximumVoltage_V = 3.5; detroughConfig.Exponent = 1.2; detroughConfig.Type = DetroughType.Exponential; envWfm = CreateDetroughEnvelopeWaveform(rfWfm, detroughConfig); break; case EnvelopeMode.LUT: LookUpTableConfiguration lutConfig = new LookUpTableConfiguration { DutAverageInputPower_dBm = rfInstrConfig.DutAverageInputPower_dBm }; // Todo - initialize lookup table envWfm = CreateLookUpTableEnvelopeWaveform(rfWfm, lutConfig); break; } ScaleAndDownloadEnvelopeWaveform(envVsg, envWfm, trackerConfig); ConfigureContinuousGeneration(envVsg, envWfm, "PFI0"); #endregion // Start envelope tracking SynchronizationConfiguration syncConfig = SynchronizationConfiguration.GetDefault(); InitiateSynchronousGeneration(rfVsg, envVsg, syncConfig); // Wait until user presses a button to stop Console.WriteLine("Press any key to abort envelope tracking.."); Console.ReadKey(); AbortGeneration(envVsg); AbortGeneration(rfVsg); // Close instruments rfVsg.Close(); envVsg.Close(); }