WARP Project Forums - Wireless Open-Access Research Platform

You are not logged in.

#1 2015-Jul-19 20:06:29

JayG8027
Member
Registered: 2015-Mar-05
Posts: 33

siso OFDM Example questions.

Hi, I am using WARP v3 and WARPLab 7.5.0.
I am studying wl_example_siso_ofdm_txrx example code.

when a source node send packet to a destination node, a packet is linear data.
wl_basebandCmd(node_tx,[RF_TX], 'write_IQ', tx_vec_air(:));
In this part, I want to know how to operate each subcarrier.

Subcarriers have different channel information each other.
I understand rx_H_est parameter has channel information of 64 subcarriers.

when I calculated below code, result is similar with syms_f_mat.
but as the number of column increased, result is not similar with syms_f_mat.

result = ifft_in_mat .* repmat(rx_H_est.', 1, N_OFDM_SYMS);

Although a packet is transmitted with linearity, does this code operate like real OFDM way?
and I want to know why result and syms_f_mat are similar only in the fore number column.

Offline

 

#2 2015-Jul-19 23:00:57

murphpo
Administrator
From: Mango Communications
Registered: 2006-Jul-03
Posts: 5159

Re: siso OFDM Example questions.

tx_vec_air is a vector of complex samples. This vector is the result of all the Tx PHY processing. If you want to operate on subcarriers you should look above this in the code. tx_syms_mat is a matrix with one complex value for each data-bearing subcarrier for each OFDM symbol. This matrix is merged with pilots_mat (pilot tone subcarriers) to form the input matrix for the IFFT.

syms_f_mat is the matrix output of the FFT in the Rx processing. The dimensions of the matrix are N_OFDM_SYMS by N_SUBCARRIERS. The raw FFT output must be equalized before demod/detection. syms_eq_mat is the matrix of equalized values (includes data-bearing subcarriers, pilot tones and empty subcarriers). payload_syms_mat is the matrix of just the data-bearing subcarriers. rx_syms is the vector version of payload_syms_mat.

Offline

 

#3 2015-Jul-22 08:18:32

JayG8027
Member
Registered: 2015-Mar-05
Posts: 33

Re: siso OFDM Example questions.

I am using WARP v3 and WARPLab 7.5.0.
I am studying wl_example_siso_ofdm_txrx example code.

Code:

    NUMNODES = 3;

    % Create a vector of node objects
    nodes = wl_initNodes(NUMNODES);

    % Create a UDP broadcast trigger and tell each node to be ready for it
    eth_trig = wl_trigger_eth_udp_broadcast;
    wl_triggerManagerCmd(nodes, 'add_ethernet_trigger', [eth_trig]);
    
    % Read Trigger IDs into workspace
    [T_IN_ETH_A, T_IN_ENERGY, T_IN_AGCDONE, T_IN_REG, T_IN_D0, T_IN_D1, T_IN_D2, T_IN_D3, T_IN_ETH_B] =  wl_getTriggerInputIDs(nodes(1));
    [T_OUT_BASEBAND, T_OUT_AGC, T_OUT_D0, T_OUT_D1, T_OUT_D2, T_OUT_D3] = wl_getTriggerOutputIDs(nodes(1));

    % For both nodes, we will allow Ethernet to trigger the buffer baseband and the AGC
    wl_triggerManagerCmd(nodes, 'output_config_input_selection', [T_OUT_BASEBAND, T_OUT_AGC], [T_IN_ETH_A, T_IN_REG]);

    % Set the trigger output delays. 
    nodes.wl_triggerManagerCmd('output_config_delay', [T_OUT_BASEBAND], 0);      
    nodes.wl_triggerManagerCmd('output_config_delay', [T_OUT_AGC], 3000);     %3000 ns delay before starting the AGC

    % Get IDs for the interfaces on the boards. Since this example assumes each
    % board has the same interface capabilities, we only need to get the IDs
    % from one of the boards
    [RFA,RFB] = wl_getInterfaceIDs(nodes(1));

    % Set up the interface for the experiment
    wl_interfaceCmd(nodes, 'RF_ALL', 'tx_gains', 3, 30);
    wl_interfaceCmd(nodes, 'RF_ALL', 'channel', 2.4, 4);

    if(USE_AGC)
        wl_interfaceCmd(nodes, 'RF_ALL', 'rx_gain_mode', 'automatic');
        wl_basebandCmd(nodes, 'agc_target', -13);        
    else
        wl_interfaceCmd(nodes, 'RF_ALL', 'rx_gain_mode', 'manual');
        RxGainRF = 1;                  % Rx RF Gain in [1:3]
        RxGainBB = 1;                 % Rx Baseband Gain in [0:31]
        wl_interfaceCmd(nodes, 'RF_ALL', 'rx_gains', RxGainRF, RxGainBB);
    end

    % Set up the TX / RX nodes and RF interfaces    
    node1 = nodes(1);
    node2 = nodes(2);
    node3 = nodes(3);
    
    RF_TX   = RFB;
    RF_RX   = RFA;

    % Get parameters from the node
    SAMP_FREQ    = wl_basebandCmd(nodes(1),'tx_buff_clk_freq'); 

    
    % We will read the transmitter's maximum I/Q buffer length
    % and assign that value to a temporary variable.
    %
    % node2 - WARPLab node object for the transmitter
    % RF_TX - index of RF interface used for transmission

    maximum_buffer_len = wl_basebandCmd(node2, RF_TX, 'tx_buff_max_num_samples');

    % Our transmission length for this example does not need
    % to fill the entire transmit buffer, so we will use the smaller
    % of two values: the maximum buffer length the board
    % can support or an arbitrary value defined by this script

    TX_NUM_SAMPS = min(MAX_TX_LEN, maximum_buffer_len);
         
    
    % Set up the baseband for the experiment
    wl_basebandCmd(nodes, 'tx_delay', 0);
    wl_basebandCmd(nodes, 'tx_length', TX_NUM_SAMPS);      % Number of samples to send
    wl_basebandCmd(nodes, 'rx_length', TX_NUM_SAMPS);      % Number of samples to receive
    example_mode_string = 'hw';

    
 
%%  transmission tx_vec_air2
wl_basebandCmd(node2,[RFB], 'write_IQ', tx_vec_air2(:));

% Enable the Tx and Rx radios
wl_interfaceCmd(node2,RFB, 'tx_en');
wl_interfaceCmd(node2,RFA, 'rx_en');

% Enable the Tx and Rx buffers
wl_basebandCmd(node2,RFB, 'tx_buff_en');
wl_basebandCmd(node2,RFA, 'rx_buff_en');

eth_trig.send();
pause(TX_NUM_SAMPS * 1/(40e6));
rx_vec_airA = wl_basebandCmd(node2,[RFA], 'read_IQ', 0, TX_NUM_SAMPS);  
rx_vec_airA = rx_vec_airA(:).';

wl_basebandCmd(nodes, 'RF_ALL', 'tx_rx_buff_dis');
wl_interfaceCmd(nodes, 'RF_ALL', 'tx_rx_dis');

%% transmission tx_vec_air
wl_basebandCmd(node1,[RFA], 'write_IQ', tx_vec_air(:));

% Enable the Tx and Rx radios
wl_interfaceCmd(node1,RFA, 'tx_en');
wl_interfaceCmd(node2,RFA, 'rx_en');

% Enable the Tx and Rx buffers
wl_basebandCmd(node1,RFA, 'tx_buff_en');
wl_basebandCmd(node2,RFA, 'rx_buff_en');

eth_trig.send();
pause(TX_NUM_SAMPS * 1/(40e6));
rx_vec_airtB = wl_basebandCmd(node2,[RFA], 'read_IQ', 0, TX_NUM_SAMPS);  
rx_vec_airtB = rx_vec_airtB(:).';
wl_basebandCmd(nodes, 'RF_ALL', 'tx_rx_buff_dis');
wl_interfaceCmd(nodes, 'RF_ALL', 'tx_rx_dis'); 
%%  simultaneously transmit above two transmissions 
    % Write the Tx waveform to the Tx node
    wl_basebandCmd(node1,[RFA], 'write_IQ', tx_vec_air(:));

    % Enable the Tx and Rx radios
    wl_interfaceCmd(node1,RFA, 'tx_en');
    wl_interfaceCmd(node2,RFA, 'rx_en');

    % Enable the Tx and Rx buffers
    wl_basebandCmd(node1,RFA, 'tx_buff_en');
    wl_basebandCmd(node2,RFA, 'rx_buff_en');

    
    %%%%%%%%%%%%%%%%%%%%%%%
    wl_basebandCmd(node2,[RFB], 'write_IQ', tx_vec_air2(:));

    %Enable the Tx and Rx radios
    wl_interfaceCmd(node2,RFB, 'tx_en');
    wl_interfaceCmd(node2,RFA, 'rx_en');

    %Enable the Tx and Rx buffers
    wl_basebandCmd(node2,RFB, 'tx_buff_en');
    wl_basebandCmd(node2,RFA, 'rx_buff_en');
    %%%%%%%%%%%%%%%%%%%%%%%    
       
    % Trigger the Tx/Rx cycle at both nodes
    eth_trig.send();

    % Pause for the samples to be processed at the node
    pause(TX_NUM_SAMPS * 1/(40e6));
    
    
    

    % Retrieve the received waveform from the Rx node
    rx_vec_air = wl_basebandCmd(node2,[RFA], 'read_IQ', 0, TX_NUM_SAMPS);  
    
    
    rx_vec_air = rx_vec_air(:).';
    
    
    % Disable the Tx/Rx radios and buffers
    wl_basebandCmd(nodes, 'RF_ALL', 'tx_rx_buff_dis');
    wl_interfaceCmd(nodes, 'RF_ALL', 'tx_rx_dis');
    
    syms_f_mat = Rx_processing(rx_vec_air);
    syms_f_matA = Rx_processing(rx_vec_airA);
    syms_f_matB = Rx_processing(rx_vec_airB);  
    syms_f_mat_sum = syms_f_matA + syms_f_matB;

Rx_processing function calculates syms_f_mat which is the matrix output of the FFT.
I think syms_f_mat and syms_f_mat_sum will be same but there are some difference between them.
I want to remove this difference and know why the difference occur.

Last edited by JayG8027 (2015-Jul-22 08:22:02)

Offline

 

#4 2015-Jul-22 09:55:24

chunter
Administrator
From: Mango Communications
Registered: 2006-Aug-24
Posts: 1212

Re: siso OFDM Example questions.

For us to provide the most help, you need to describe what exactly you are trying to do, what you are trying to measure, and what you expect to see. I'm skeptical that the code you pasted is doing what you think its doing. But without knowing what you think its doing (since you provided no description), I can't address any discrepancy there. Please provide a detailed description of what you are trying to measure and what you expect to see.

Observations from your script:

- rx_vec_air is captured from a trial consisting of the transmission of tx_vec_air2 from node1 RFA -> node2 RFA
- rx_vec_airA is captured from a different trial consisting of the transmission of tx_vec_air2 from node2 RFB -> node2 RFA
- rx_vec_airB is not defined in the above script. rx_vec_airtB is defined and appears to be a typo of rx_vec_airB. The script shouldn't even run unless you have some stale variable in your workspace for rx_vec_airB
- rx_vec_airtB is captured from a third trial consisting of the transmission of tx_vec_air from node1 RFA -> node2 RFB
- You have not provided code that defines tx_vec_air or tx_vec_air2.


Even assuming that rx_vec_airtB  is actually rx_vec_airB, I can't see any way that syms_f_mat and syms_f_mat_sum would ever be exactly equal to one another. Why do you expect that they should be? Here are a few reasons of why they might be different:

1. The three relevant Rx vectors (rx_vec_air, rx_vec_airA, rx_vec_airB) all come from independent trials. Every time you run a trial, you are exposing a transmission to new random perturbations like the wireless channel and noise.
2. syms_f_mat is based on a trial consisting of the transmission of tx_vec_air2 while syms_f_mat_sum is based on multiple trials consisting of the transmissions of tx_vec_air and tx_vec_air2.
3. I don't know what Rx_processing is doing since you didn't provide that function. Even if rx_vec_air = rx_vec_airA+ rx_vec_airB (which they don't for the above reasons), you can only expect the output of those functions to equal one another if Rx_processing exhibits additivity. Does it?

Offline

 

#5 2015-Jul-22 20:28:33

JayG8027
Member
Registered: 2015-Mar-05
Posts: 33

Re: siso OFDM Example questions.

rx_vec_airB is same with rx_vec_airtB. this is typing error.

below is code to produce  tx_vec_air and tx_vec_air2
tx_data = randi(MOD_ORDER, 1, N_DATA_SYMS) - 1;
[tx_vec_air, pilots_mat, tx_syms, tx_syms_mat] = tx_processing(tx_data, preamble, TX_NUM_SAMPS, interp_filt2);

tx_data2 = randi(MOD_ORDER, 1, N_DATA_SYMS) - 1;
[tx_vec_air2, pilots_mat2, tx_syms2, tx_syms_mat2] = tx_processing(tx_data2, preamble, TX_NUM_SAMPS, interp_filt2);

and below code is tx_processing function.

Code:

%% Generate a payload


% Functions for data -> complex symbol mapping (avoids comm toolbox requirement for qammod)
modvec_bpsk   =  (1/sqrt(2))  .* [-1 1];
modvec_16qam  = (1/sqrt(10)) .* [-3 -1 +3 +1];

mod_fcn_bpsk  = @(x) complex(modvec_bpsk(1+x),0);
mod_fcn_qpsk  = @(x) complex(modvec_bpsk(1+bitshift(x, -1)), modvec_bpsk(1+mod(x, 2)));
mod_fcn_16qam = @(x) complex(modvec_16qam(1+bitshift(x, -2)), modvec_16qam(1+mod(x,4)));

% Map the data values on to complex symbols
switch MOD_ORDER
    case 2         % BPSK
        tx_syms = arrayfun(mod_fcn_bpsk, tx_data);
    case 4         % QPSK
        tx_syms = arrayfun(mod_fcn_qpsk, tx_data);
    case 16        % 16-QAM
        tx_syms = arrayfun(mod_fcn_16qam, tx_data);      
    otherwise
        fprintf('Invalid MOD_ORDER (%d)!  Must be in [2, 4, 16]\n', MOD_ORDER);
        return;
end

% Reshape the symbol vector to a matrix with one column per OFDM symbol
tx_syms_mat = reshape(tx_syms, length(SC_IND_DATA), N_OFDM_SYMS);

% Define the pilot tones
if(USE_PILOT_TONES)
    pilots = [1 1 -1 1].';
else
    pilots = [0 0 0 0].';
end

% Repeat the pilots across all OFDM symbols
pilots_mat = repmat(pilots, 1, N_OFDM_SYMS);

%% IFFT

% Construct the IFFT input matrix
ifft_in_mat = zeros(N_SC, N_OFDM_SYMS);

% Insert the data and pilot values; other subcarriers will remain at 0
ifft_in_mat(SC_IND_DATA, :)   = tx_syms_mat;
ifft_in_mat(SC_IND_PILOTS, :) = pilots_mat;

%Perform the IFFT
tx_payload_mat = ifft(ifft_in_mat, N_SC, 1);

% Insert the cyclic prefix
if(CP_LEN > 0)
    tx_cp = tx_payload_mat((end-CP_LEN+1 : end), :);
    tx_payload_mat = [tx_cp; tx_payload_mat];
end

% Reshape to a vector
tx_payload_vec = reshape(tx_payload_mat, 1, numel(tx_payload_mat));

% Construct the full time-domain OFDM waveform
tx_vec = [preamble tx_payload_vec];

% Pad with zeros for transmission
tx_vec_padded = [tx_vec zeros(1,(TX_NUM_SAMPS/INTERP_RATE)-length(tx_vec))];

%% Interpolate
if(INTERP_RATE == 1)
    tx_vec_air = tx_vec_padded;
elseif(INTERP_RATE == 2)
    tx_vec_2x = zeros(1, 2*numel(tx_vec_padded));
    tx_vec_2x(1:2:end) = tx_vec_padded;
    tx_vec_air = filter(interp_filt2, 1, tx_vec_2x);
end

% Scale the Tx vector
tx_vec_air = TX_SCALE .* tx_vec_air ./ max(abs(tx_vec_air));


end

and below code is RX_processing function code.

Code:

 
%% Decimate
if(DECIMATE_RATE == 1)
    raw_rx_dec = rx_vec_air;
elseif(DECIMATE_RATE == 2)  
    raw_rx_dec = filter(interp_filt2, 1, rx_vec_air);
    raw_rx_dec = raw_rx_dec(1:2:end);
end

%% Correlate for LTS

% Complex cross correlation of Rx waveform with time-domain LTS 
lts_corr = abs(conv(conj(fliplr(lts_t)), sign(raw_rx_dec)));

% Skip early and late samples
lts_corr = lts_corr(32:end-32);

% Find all correlation peaks
lts_peaks = find(lts_corr > LTS_CORR_THRESH*max(lts_corr));

% Select best candidate correlation peak as LTS-payload boundary
[LTS1, LTS2] = meshgrid(lts_peaks,lts_peaks);
[lts_second_peak_index,y] = find(LTS2-LTS1 == length(lts_t));

% Stop if no valid correlation peak was found
if(isempty(lts_second_peak_index))
    fprintf('No LTS Correlation Peaks Found!\n');
    return;
end

% Set the sample indices of the payload symbols and preamble
payload_ind = lts_peaks(max(lts_second_peak_index))+32;
lts_ind = payload_ind-160;

if(DO_APPLY_CFO_CORRECTION)
    %Extract LTS (not yet CFO corrected)
    rx_lts = raw_rx_dec(lts_ind : lts_ind+159);
    rx_lts1 = rx_lts(-64+-FFT_OFFSET + [97:160]);
    rx_lts2 = rx_lts(-FFT_OFFSET + [97:160]);

    %Calculate coarse CFO est
    rx_cfo_est_lts = mean(unwrap(angle(rx_lts1 .* conj(rx_lts2))));
    rx_cfo_est_lts = rx_cfo_est_lts/(2*pi*64);
else
    rx_cfo_est_lts = 0;
end

% Apply CFO correction to raw Rx waveform
rx_cfo_corr_t = exp(1i*2*pi*rx_cfo_est_lts*[0:length(raw_rx_dec)-1]);
rx_dec_cfo_corr = raw_rx_dec .* rx_cfo_corr_t;

% Re-extract LTS for channel estimate
rx_lts = rx_dec_cfo_corr(lts_ind : lts_ind+159);
rx_lts1 = rx_lts(-64+-FFT_OFFSET + [97:160]);
rx_lts2 = rx_lts(-FFT_OFFSET + [97:160]);

rx_lts1_f = fft(rx_lts1);
rx_lts2_f = fft(rx_lts2);

% Calculate channel estimate
rx_H_est = lts_f .* (rx_lts1_f + rx_lts2_f)/2;


%% Rx payload processing

% Extract the payload samples (integral number of OFDM symbols following preamble)
payload_vec = rx_dec_cfo_corr(payload_ind : payload_ind+N_OFDM_SYMS*(N_SC+CP_LEN)-1);
payload_mat = reshape(payload_vec, (N_SC+CP_LEN), N_OFDM_SYMS);

% Remove the cyclic prefix, keeping FFT_OFFSET samples of CP (on average)
payload_mat_noCP = payload_mat(CP_LEN-FFT_OFFSET+[1:N_SC], :);

% Take the FFT
syms_f_mat = fft(payload_mat_noCP, N_SC, 1);

rx_vec_air received two signals from path node2 RFB -> node2 RFA and node1 RFA -> node2 RFB at the same time.
rx_vec_airA received a signal from path node2 RFB -> node2 RFA
rx_vec_airB received a signal from path node1 RFA -> node2 RFB

they are operated in one program, so their channel information are similar each other.
therefore I think that rx_vec_air and rx_vec_airA+ rx_vec_airB are similar each other.

But they have some differences, I want to know way to minimize this difference.

Offline

 

#6 2015-Jul-23 08:24:58

murphpo
Administrator
From: Mango Communications
Registered: 2006-Jul-03
Posts: 5159

Re: siso OFDM Example questions.

Two vectors of Rx samples captured at different times on one interface, or at any time on different RF interfaces, will never be identical. Random noise is inherent in the Rx circuitry and unique noise will always be present in any vector of Rx samples. Further, propagation channel fluctuations are random and constantly changing. Finally two nodes will have sampling and carrier frequency offsets (unless they're sharing a clock signal).

I would strongly encourage you to study the setup you're building in simulation. You can add realistic hardware and propagation effects to the simulation (carrier frequency offset, random channel fading, additive random noise) and observe how these impact your Rx processing. The OFDM example has a section of code specifically for this purpose, where you can modify the vector of samples passed from Tx -> Rx in simulation. You should start with the sim, applying realistic effects and convince yourself your Tx and Rx processing is working before introducing actual hardware.

Offline

 

#7 2015-Jul-24 03:24:39

JayG8027
Member
Registered: 2015-Mar-05
Posts: 33

Re: siso OFDM Example questions.

If a signal A and a signal B mixed signal and A is much stronger than a signal B, can I subtract signal A?
More details, I estimate the signal A and adjust delay by using correlation A and the mixed signal.
And then I subtract the signal A from the mixed signal. In this way, can I obtain the signal B?

Offline

 

#8 2015-Jul-24 06:36:51

murphpo
Administrator
From: Mango Communications
Registered: 2006-Jul-03
Posts: 5159

Re: siso OFDM Example questions.

Yes, a receiver observes the superposition of simultaneously transmitted signals. However you must account for all the phase and amplitude variations that occur between your Tx DAC and Rx ADC. This includes the 3 Tx amplifiers (Tx baseband VGA , Tx RF VGA, Tx PA), 2 Rx amplifiers (Rx RF LNA, Rx baseband VGA), phase/frequency offsets due to carrier and sampling frequency offsets, and the wireless propagation channel itself (i.e. random amplitude and phase). Your Rx code must estimate the overall phase/frequency/amplitude change experienced along each Tx-Rx path and use this estimate to separate the superimposed Rx signals. Melissa's thesis on building a full duplex system describes the processing she implemented in detail.

Offline

 

#9 2015-Jul-30 08:17:04

JayG8027
Member
Registered: 2015-Mar-05
Posts: 33

Re: siso OFDM Example questions.

Thank you for your answer.

I am using WARP v3 and WARPLab 7.5.0 and I have another question in wl_example_siso_ofdm_txrx example.
I obtained two rx_H_est values continuously by same way in one program.  rx_H_est is channel estimation value in wl_example_siso_ofdm_txrx.
If tx and rx antenna connect one board, two rx_H_est values are same each other. But tx and rx antenna connect different board each other, two rx_H_est value are different.
maybe there are many cause such as amplifiers and wireless propagation channel information.
can I make different two rx_H_est values to be same?

Offline

 

#10 2015-Jul-30 09:18:18

chunter
Administrator
From: Mango Communications
Registered: 2006-Aug-24
Posts: 1212

Re: siso OFDM Example questions.

Again, two independent measurements of rx_H_est will never be exactly the same. When using a single board for both Tx and Rx, you have a fixed carrier frequency and sampling frequency between your transmitter and receiver. Absent OTA channel effects (e.g., the experiment is over an attenuated coax cable), rx_H_est should be similar between runs. When you use two different boards that each have their own independent clocks, CFO and SFO will make it so that rx_H_est won't be the same between two runs. There will be an arbitrary phase offset in rx_H_est at the beginning of time as well as a time-varying phase rotation.

Making rx_H_est "the same" is thinking of it backwards. rx_H_est is the independent and uncontrollable channel and the goal is to work around it. A classic way to deal with differences in rx_H_est is the general principle of precoding at your transmitter, where you modify your transmission taking the expected rx_H_est into account so that the received signal has an effective (rx_H_est = 1).

Offline

 

#11 2015-Jul-30 21:21:37

JayG8027
Member
Registered: 2015-Mar-05
Posts: 33

Re: siso OFDM Example questions.

chunter wrote:

A classic way to deal with differences in rx_H_est is the general principle of precoding at your transmitter, where you modify your transmission taking the expected rx_H_est into account so that the received signal has an effective (rx_H_est = 1).

Could you explain in detail?

Offline

 

#12 2015-Jul-30 22:20:27

murphpo
Administrator
From: Mango Communications
Registered: 2006-Jul-03
Posts: 5159

Re: siso OFDM Example questions.

Could you explain in detail?

You will need to do explore this topic on your own. Tx precoding is a complex topic, with many approaches and nuances. Our forums are meant to answer questions about WARP hardware and the WARP reference designs. We cannot provide instruction on fundamentals of wireless comm. There are many excellent resources online and in print that are better places for this.

Offline

 

Board footer