power amplifier characterization -凯发k8网页登录
this example shows how to characterize a power amplifier (pa) using measured input and output signals of an nxp airfast pa. optionally, you can use a hardware test setup including an ni pxi chassis with a vector signal transceiver (vst) to measure the signals at run time.
you can use the characterization results to simulate the pa using the system object™ or block. for a pa model with memory, you can use (rf blockset) block. you can use these models to design digital predistortion (dpd) using and system objects or and blocks. for more information, see .
optional hardware and software
this example can run on an ni pxi chassis with a vst to measure pa input and output signals during run time. the vst is a high-bandwidth rf instrument that combines a vector signal generator (vsg) with a vector signal analyzer (vsa). the following ni pxi chassis configuration was used to capture the saved signal:
ni pxie-5840 vector signal transceiver (vst)
ni pxie-4139 source measure unit (smu)
ni pxie-4145 smu
software
software
software
as the device under test (dut), this example uses an nxp airfast ldmos doherty pa with operating frequency 3.6-3.8 ghz and 29 db gain. this pa requires 29v, 5v, 3 v, 1.6v and 1.4v dc bias, which are provided using pxie-4139 and pxie-4145 smus.
install matlab® on the ni pxi controller to run this example with the hardware setup, which is illustrated in the following figure. matlab, running on the pxi controller, generates test waveform and downloads the waveform to the vsg. the vsg transmits this test waveform to the pa and the vsa receives the impaired waveform at the pa output. matlab collects the pa output from the vsa and performs pa characterization.
set datasource variable to "hardware"
to run a test signal though the pa using the hardware setup described above. the test signal can be either a 5g-like ofdm waveform or two tones, as described in the following section. set datasource variable to "from file"
to use prerecorded data.
datasource = "from file";
generate test signals
to generate a test signal, specify the type of test signal as "ofdm
" or "tones
". specifying the testsignal
as "ofdm
" uses a 5g-like ofdm waveform with 64-qam modulated signals for each subcarrier. "tones
" uses two tones at 1.8 mhz and 2.6 mhz, to test the intermodulation caused by the pa.
the example will use an oversampling factor of 7 to run the grid search up to an expected seventh-order nonlinearity, and normalize the waveform amplitude.
testsignal = "ofdm"; switch testsignal case "ofdm" bw = 100e6; [txwaveform,samplerate,numframes] = helperpachargenerateofdm(bw); case "tones" bw = 3e6; [txwaveform,samplerate,numframes] = helperpachargeneratetones(); end txwaveform = txwaveform/max(abs(txwaveform)); % normalize the waveform
hardware test
if the datasource
variable is set to "from file"
, load the prerecorded data. if the datasource
variable is set to "hardware"
, run the test signal through the pa using the vst. create a helpervstdriver object to communicate with the vst device. set the resource name to the resource name assigned to the vst device. this example uses 'vst_01'
. for ni devices, you can find the resource name using the ni measurement & automation explorer (max) application.
if strcmp(datasource, "hardware") vst = helpervstdriver('vst_01');
set the expected gain values of the dut and the attenuator. since pa output is connected to a 30 db attenuator, set vsa external attenuation to 30. set the expected gain of the dut to 29 db and gain accuracy to 1 db. set the acquisition time to a value that will result in about 40k samples. set the target input power to 8 dbm. you can increase this value to drive the pa more into the non-linear region.
vst.dutexpectedgain = 29; % db vst.externalattenuation = 30; % db vst.acquisitiontime = 0.9e-3*(53.76e6/samplerate); % seconds vst.duttargetinputpower =8; % dbm vst.centerfrequency = 3.7e9 % hz
download the test waveform to the vsg. measure pa output.
writewaveform(vst,txwaveform,samplerate,testsignal) results = runpameasurements(vst); release(vst) else % load the prerecorded results from vst switch testsignal case "ofdm" datafilename = sprintf("helperpacharsaveddata%dmhz",bw/1e6); case "tones" datafilename = "helperpacharsaveddatatones"; end load(datafilename,"results","samplerate","oversamplingrate","testsignal","numframes") end
map results into local variables.
referencepower = results.referencepower; measuredamtoam = results.measuredamtoam; painput = results.inputwaveform; paoutput = results.outputwaveform; lineargaindb = results.lineargain;
plot the spectrum of the test signal using the function.
sainput = helperpacharplotinput(painput, samplerate, testsignal, bw);
plot the am/am characteristics of the pa.
helperpacharplotspecanamam(referencepower, measuredamtoam)
for a better view, focus on gain vs input power instead of output power vs input power and plot again.
helperpacharplotspecangain(referencepower, measuredamtoam)
the pa is mostly linear of the input power range -1 to 17 dbm, with only about 1db variation over that range. the width of the gain curve is due to the memory effects of the pa.
pa characterization
use the measured pa input and output data to model the pa. then, you can use this model to simulate a system that contains this pa and fine tune the parameters. this example considers three models: memoryless nonlinearity, memory polynomial and memory polynomial with cross terms.
memoryless nonlinearity model
memoryless nonlinear impairments distort the input signal amplitude and phase. the amplitude distortion is amplitude-to-amplitude modulation (am/am) and the phase distortion is amplitude-to-phase modulation (am/pm). the system object and block implements several such distortions. use the pa input and output data to create a lookup table to use with this object or block.
to characterize the am/am transfer function, calculate the average output power for a range of input power values. measurements are in volts over an overall 100 ohm impedance, split between the transmitter and receiver. convert the measured baseband samples to power values in dbm. the 30 db term is for dbw to dbm conversion and the -20 db term is for the 100 ohm impedance.
painputdbm = mag2db(abs(painput)) 30 - 20; paoutputdbm = mag2db(abs(paoutput)) 30 - 20;
partition the input power values into bins. the edges
variable contains the bin edges, and the idx
variable contains the index of the bin values for each input power value.
[n,edges,idx] = histcounts(painputdbm, 'binwidth', 0.5);
for each bin, calculate the midpoint of the bin, average output power and average phase shift. do not include any input power value that is less than 20 db below the maximum input power. store the results in a three-column matrix where the first column is the input power in dbm, second column is the output power in dbm and last column is the phase shift.
mininpowerdbm = max(painputdbm) - 20; minidx = find(edges < mininpowerdbm, 1, 'last'); tablelen = length(edges)-minidx-1; inouttable = zeros(tablelen,2); for p = minidx 1:length(edges)-1 inouttable(p-minidx,1) = mean(painputdbm(idx == p)); % average input power for current bin inouttable(p-minidx,2) = mean(paoutputdbm(idx == p)); % average output power for current bin inouttable(p-minidx,3) = mean(angle(paoutput(idx == p)./painput(idx == p))); % average phase shift for current bin end
use the table in the comm.memorylessnonlinearity system object to model the pa. compare the estimated output with the actual output.
pa = comm.memorylessnonlinearity('method','lookup table','table',inouttable,'referenceimpedance',100)
pa = comm.memorylessnonlinearity with properties: method: 'lookup table' table: [40×3 double] referenceimpedance: 100
paoutputfitmemless = pa(painput); err = abs(paoutput - paoutputfitmemless)./abs(paoutput); rmserrormemless = rms(err)*100; disp(['percent rms error in time domain is ' num2str(rmserrormemless) '%'])
percent rms error in time domain is 12.1884%
to visualize both the measured output signal and the fitted output signal, plot the actual and fitted time-domain output voltages.
helperpacharplottime(paoutput, paoutputfitmemless, samplerate)
plot the magnitude of the gain.
helperpacharplotgain(painput, paoutput, paoutputfitmemless)
memory polynomial model
the memory polynomial model includes the memory effects of the pa in addition to the nonlinear gain. use the multipurpose helper function to determine the complex coefficients of a memory polynomial model for the amplifier characteristics. set the model type to 'memory polynomial'
.
modtype = 'mempoly';
perform a grid search as shown in appendix grid search for memory length and polynomial order. based on this grid search results, the best fit is obtained when memory length and polynomial degree values are as follows:
memlen = 5; deglen = 5;
perform the fit and rms error calculation for these values. only half of the data is used to compute the fitting coefficients, as the whole data set will be used to compute the relative error. the helper function calculates the coefficients of the model.
numdatapts = length(painput); halfdatapts = round(numdatapts/2);
the helper function is editable for custom modifications, and to return the desired matrix. the pa model has some zero valued coefficients, which results in a rank deficient matrix.
fitcoefmatmem = helperpacharmempolymodel('coefficientfinder', ... painput(1:halfdatapts),paoutput(1:halfdatapts),memlen,deglen,modtype);
warning: rank deficient, rank = 24, tol = 1.870608e-01.
disp(abs(fitcoefmatmem))
23.1549 8.8540 17.8385 13.3026 3.2168 0 11.7686 26.4685 23.1937 5.5476 20.9745 16.8531 25.7336 22.1925 5.0688 32.6199 8.4042 9.4903 10.6984 2.5613 15.3875 2.3630 2.0867 2.9339 0.7370
to validate the fitting, use the helper function to compute percent rms error with respect to the measured signal.
rmserrortimemem = helperpacharmempolymodel('errormeasure', ... painput, paoutput, fitcoefmatmem, modtype); disp(['percent rms error in time domain is ' num2str(rmserrortimemem) '%'])
percent rms error in time domain is 6.1056%
to visualize both the measured output signal and the fitted output signal, plot the actual and fitted time-domain output voltages.
paoutputfitmem = helperpacharmempolymodel('signalgenerator', ... painput, fitcoefmatmem, modtype); helperpacharplottime(paoutput, paoutputfitmem, samplerate)
plot the magnitude of the gain.
helperpacharplotgain(painput, paoutput, paoutputfitmem)
discussions
the percent rms estimation error in time domain for the memoryless nonlinearity model, which is between 9% and 13%, is about 3 to 4 times more than the error for the memory polynomial model is, which is between 2% and 6%, for the ofdm signals with different bandwidths.
check the estimation error in frequency domain by plotting the spectrum of the actual pa output together with the spectrum of the estimated pa output for all three models. the memoryless nonlinearity table lookup model is not able to simulate the spectral growth seen in the measured pa output. for this pa, memory polynomial model provides a good approximation of the pa characteristics.
sa = helperpacharplotspectrum(... [paoutput paoutputfitmemless paoutputfitmem],... {'actual pa output','memoryless model output', ... 'memory polynomial output'},... samplerate,testsignal);
the helper function can also use the memory polynomial with cross terms model, which includes the leading and lagging memory cross terms in addition to the memory effects of the pa and the nonlinear gain. set the model type to 'cross-term memory'
to explore this model.
for further exploration, try different memory length and polynomial degree combinations. modify the oversampling factor and explore its effect on the pa model performance. modify the helper function to try different pa models.
using pa model for dpd testing
save the coefficient matrix of the pa model to be used in the (rf blockset) block for simulation at the system-level in the .
framesize = floor(length(painput)/numframes); pain.signals.values = double(reshape(painput(1:framesize*numframes,1),numframes,framesize)); pain.signals.dimensions = framesize; pain.time = []; save('pacoefficientsandinput.mat','modtype','fitcoefmatmem','memlen','deglen','pain','lineargaindb')
appendix: grid search for memory length and polynomial order
uncomment following lines to perform the grid search when the cost function is the percent rms error in time. first choose the model type.
modtype = 'mempoly'; % rmserrortime = helperpachargridsearchtime(painput,paoutput,modtype,oversamplingrate)
repeat the search when the cost function is the percent rms error in frequency.
% rmserrorfreq = helperpachargridsearchfrequency(painput,paoutput,modtype,oversamplingrate)