1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
2 | % wl_example_8x2_array.m |
---|
3 | % |
---|
4 | % Description: |
---|
5 | % See warpproject.org/trac/wiki/WARPLab/Examples/8x2Array |
---|
6 | % |
---|
7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
8 | clear; |
---|
9 | figure(1);clf; |
---|
10 | |
---|
11 | USE_AGC = true; |
---|
12 | RUN_CONTINOUSLY = false; |
---|
13 | |
---|
14 | MAX_TX_LEN = 32768; |
---|
15 | |
---|
16 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
17 | % Set up the WARPLab experiment |
---|
18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
19 | |
---|
20 | % Create a vector of node objects |
---|
21 | % |
---|
22 | % This experiment uses 3 nodes: 2 will act as a transmitter and 1 will act as a receiver: |
---|
23 | % nodes(1): Primary transmitter |
---|
24 | % nodes(2): Secondary transmitter (receives clocks and triggers from primary transmitter) |
---|
25 | % nodes(3): Receiver |
---|
26 | % |
---|
27 | nodes = wl_initNodes(3); |
---|
28 | |
---|
29 | node_tx1 = nodes(1); |
---|
30 | node_tx2 = nodes(2); |
---|
31 | node_rx = nodes(3); |
---|
32 | |
---|
33 | |
---|
34 | % Create a UDP broadcast trigger and tell each node to be ready for it |
---|
35 | eth_trig = wl_trigger_eth_udp_broadcast; |
---|
36 | wl_triggerManagerCmd(nodes, 'add_ethernet_trigger', [eth_trig]); |
---|
37 | |
---|
38 | % Read Trigger IDs into workspace |
---|
39 | trig_in_ids = wl_getTriggerInputIDs(node_tx1); |
---|
40 | trig_out_ids = wl_getTriggerOutputIDs(node_tx1); |
---|
41 | |
---|
42 | % For the primary transmit node, we will allow Ethernet to trigger the baseband buffers, |
---|
43 | % the AGC, and external output pin 0 (which is mapped to pin 8 on the debug header). We |
---|
44 | % also will allow Ethernet to trigger the same signals for the receiving node. |
---|
45 | % |
---|
46 | wl_triggerManagerCmd([node_tx1, node_rx], 'output_config_input_selection', [trig_out_ids.BASEBAND, trig_out_ids.AGC, trig_out_ids.EXT_OUT_P0], [trig_in_ids.ETH_A]); |
---|
47 | |
---|
48 | % For the secondary transmit node, we will allow external input pin 3 (mapped to pin 15 |
---|
49 | % on the debug header) to trigger the baseband buffers, and the AGC |
---|
50 | % |
---|
51 | % Note that the below line selects both P0 and P3. This will allow the |
---|
52 | % script to work with either the CM-PLL (where output P0 directly |
---|
53 | % connects to input P0) or the CM-MMCX (where output P0 is usually |
---|
54 | % connected to input P3 since both neighbor ground pins). |
---|
55 | wl_triggerManagerCmd(node_tx2, 'output_config_input_selection', [trig_out_ids.BASEBAND, trig_out_ids.AGC], [trig_in_ids.EXT_IN_P0, trig_in_ids.EXT_IN_P3]); |
---|
56 | |
---|
57 | % For the secondary transmit node, we enable the debounce circuity on the external input |
---|
58 | % pin 3 to guard against any noise in the trigger signal. |
---|
59 | % |
---|
60 | wl_triggerManagerCmd(node_tx2, 'input_config_debounce_mode', [trig_in_ids.EXT_IN_P0, trig_in_ids.EXT_IN_P3], false); |
---|
61 | |
---|
62 | % To better align the transmitters, we artificially delay the primary |
---|
63 | % transmitter's trigger outputs that drive the baseband buffers. An |
---|
64 | % external trigger output on the primary transmitter will appear as a |
---|
65 | % trigger input at the secondary transmitter a minimum of 5 clock cycles |
---|
66 | % later (31.25ns). It will appear a minimum of 9 clock cycles later |
---|
67 | % (56.25ns) when the debounce circuitry is enabled. |
---|
68 | % |
---|
69 | wl_triggerManagerCmd(node_tx1, 'output_config_delay', [trig_out_ids.BASEBAND, trig_out_ids.AGC], 31.25); % 31.25ns delay |
---|
70 | |
---|
71 | % Also, we need to delay the AGC on the receiver so that the transmitted waveform has time |
---|
72 | % to begin and propagate to the receiver so it can be sampled appropriately. |
---|
73 | % |
---|
74 | wl_triggerManagerCmd(node_rx, 'output_config_delay', [trig_out_ids.AGC], 3000); % 3000ns delay |
---|
75 | |
---|
76 | % Get IDs for the interfaces on the boards |
---|
77 | % NOTE: This example assumes each board has the same interface capabilities, we only |
---|
78 | % need to get the IDs from one of the boards |
---|
79 | % |
---|
80 | ifc_ids_4RF = wl_getInterfaceIDs(node_tx1); |
---|
81 | ifc_ids_2RF = wl_getInterfaceIDs(node_rx); |
---|
82 | |
---|
83 | % Set up the interface for the experiment |
---|
84 | wl_interfaceCmd([node_tx1, node_tx2], ifc_ids_4RF.RF_ALL, 'tx_gains', 3, 30); |
---|
85 | |
---|
86 | % Set the channel |
---|
87 | % NOTE: Due to the different number of interfaces, we need to issue |
---|
88 | % multiple commands to the differnt types of nodes |
---|
89 | % |
---|
90 | wl_interfaceCmd([node_tx1, node_tx2], ifc_ids_4RF.RF_ALL, 'channel', 2.4, 1); |
---|
91 | wl_interfaceCmd(node_rx, ifc_ids_2RF.RF_ALL, 'channel', 2.4, 1); |
---|
92 | |
---|
93 | if(USE_AGC) |
---|
94 | wl_interfaceCmd(node_rx, ifc_ids_2RF.RF_ALL, 'rx_gain_mode', 'automatic'); |
---|
95 | wl_basebandCmd(node_rx,'agc_target',-8); |
---|
96 | else |
---|
97 | RxGainRF = 1; % Rx RF Gain in [1:3] |
---|
98 | RxGainBB = 4; % Rx Baseband Gain in [0:31] |
---|
99 | |
---|
100 | wl_interfaceCmd(node_rx, ifc_ids_2RF.RF_ALL, 'rx_gain_mode', 'manual'); |
---|
101 | wl_interfaceCmd(node_rx, ifc_ids_2RF.RF_ALL, 'rx_gains', RxGainRF, RxGainBB); |
---|
102 | end |
---|
103 | |
---|
104 | wl_interfaceCmd([node_tx1, node_tx2], ifc_ids_4RF.RF_ALL, 'tx_lpf_corn_freq', 2); % Configure Tx for 36MHz of bandwidth |
---|
105 | wl_interfaceCmd(node_rx, ifc_ids_2RF.RF_ALL, 'rx_lpf_corn_freq', 3); % Configure Rx for 36MHz of bandwidth |
---|
106 | |
---|
107 | % Read the transmitter's maximum I/Q buffer length |
---|
108 | maximum_buffer_len = wl_basebandCmd(node_tx1, ifc_ids_4RF.RF_A, 'tx_buff_max_num_samples'); |
---|
109 | |
---|
110 | % Our transmission length for this example does not need to fill the entire transmit buffer, |
---|
111 | % so we will use the smaller of two values: the maximum buffer length the board can support |
---|
112 | % or an arbitrary value defined by this script. |
---|
113 | % |
---|
114 | txLength = min(MAX_TX_LEN, maximum_buffer_len); |
---|
115 | |
---|
116 | % Set up the baseband for the experiment |
---|
117 | wl_basebandCmd(nodes, 'tx_delay', 0); |
---|
118 | wl_basebandCmd(nodes, 'tx_length', txLength); |
---|
119 | wl_basebandCmd(nodes, 'rx_length', txLength); |
---|
120 | |
---|
121 | |
---|
122 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
123 | % Signal processing to generate transmit signal |
---|
124 | % |
---|
125 | % NOTE: We can send any signal we want out of each of the 8 transmit antennas. |
---|
126 | % For visualization, we'll send "pink" noise of 1MHz out of each, but centered |
---|
127 | % at different parts of the 40MHz band. |
---|
128 | % |
---|
129 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
130 | |
---|
131 | % First generate the preamble for AGC |
---|
132 | % NOTE: The preamble corresponds to the short symbols from the 802.11a PHY standard |
---|
133 | % |
---|
134 | shortSymbol_freq = [0 0 0 0 0 0 0 0 1+i 0 0 0 -1+i 0 0 0 -1-i 0 0 0 1-i 0 0 0 -1-i 0 0 0 1-i 0 0 0 0 0 0 0 1-i 0 0 0 -1-i 0 0 0 1-i 0 0 0 -1-i 0 0 0 -1+i 0 0 0 1+i 0 0 0 0 0 0 0].'; |
---|
135 | shortSymbol_freq = [zeros(32,1);shortSymbol_freq;zeros(32,1)]; |
---|
136 | shortSymbol_time = ifft(fftshift(shortSymbol_freq)); |
---|
137 | shortSymbol_time = (shortSymbol_time(1:32).')./max(abs(shortSymbol_time)); |
---|
138 | shortsyms_rep = repmat(shortSymbol_time,1,30); |
---|
139 | preamble_single = shortsyms_rep; |
---|
140 | preamble_single = preamble_single(:); |
---|
141 | |
---|
142 | shifts = floor(linspace(0,31,8)); |
---|
143 | for k = 1:8 |
---|
144 | % Shift preamble for each antenna so we don't have accidental beamforming |
---|
145 | preamble(:,k) = circshift(preamble_single,shifts(k)); |
---|
146 | end |
---|
147 | |
---|
148 | % Constants for generating the payload |
---|
149 | Ts = 1 / (wl_basebandCmd(node_tx1, 'tx_buff_clk_freq')); |
---|
150 | BW = 1; %MHz |
---|
151 | |
---|
152 | % Generate the payload |
---|
153 | payload = complex(randn(txLength-length(preamble),8),randn(txLength-length(preamble),8)); |
---|
154 | payload_freq = fftshift(fft(payload)); |
---|
155 | freqVec = linspace(-((1/Ts)/2e6),((1/Ts)/2e6), txLength - length(preamble)); |
---|
156 | noise_centerFreqs = linspace(-12,12,8); |
---|
157 | |
---|
158 | for k = 1:8 |
---|
159 | payload_freq((freqVec < (noise_centerFreqs(k) - BW/2)) | (freqVec > (noise_centerFreqs(k) + BW/2)),k)=0; |
---|
160 | end |
---|
161 | |
---|
162 | payload = ifft(fftshift(payload_freq)); |
---|
163 | txData = [preamble;payload]; |
---|
164 | |
---|
165 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
166 | % Transmit and receive signal using WARPLab |
---|
167 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
168 | |
---|
169 | wl_basebandCmd(node_tx1, ifc_ids_4RF.RF_ALL_VEC, 'write_IQ', txData(:,1:4)); % First 4 columns of txData is for primary tx |
---|
170 | wl_basebandCmd(node_tx2, ifc_ids_4RF.RF_ALL_VEC, 'write_IQ', txData(:,5:8)); % Second 4 columns of txData is for secondary tx |
---|
171 | |
---|
172 | wl_basebandCmd([node_tx1, node_tx2], ifc_ids_4RF.RF_ALL, 'tx_buff_en'); |
---|
173 | wl_basebandCmd(node_rx, ifc_ids_2RF.RF_ALL, 'rx_buff_en'); |
---|
174 | |
---|
175 | wl_interfaceCmd([node_tx1, node_tx2], ifc_ids_4RF.RF_ALL, 'tx_en'); |
---|
176 | wl_interfaceCmd(node_rx, ifc_ids_2RF.RF_ALL, 'rx_en'); |
---|
177 | |
---|
178 | |
---|
179 | set(gcf, 'KeyPressFcn','RUN_CONTINOUSLY=0;'); |
---|
180 | fprintf('Press any key to halt experiment\n') |
---|
181 | |
---|
182 | while(1) |
---|
183 | eth_trig.send(); |
---|
184 | |
---|
185 | rx_IQ = wl_basebandCmd(node_rx, ifc_ids_2RF.RF_ALL_VEC, 'read_IQ', 0, txLength); |
---|
186 | |
---|
187 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
188 | % Visualize results |
---|
189 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
190 | t = [0:Ts:(txLength-1)*Ts].'; |
---|
191 | figure(1); |
---|
192 | ax(1) = subplot(2,2,1); |
---|
193 | plot(t,real(rx_IQ(:,1))) |
---|
194 | title('Re\{rx\_IQ_{RFA}\}') |
---|
195 | xlabel('Time (s)') |
---|
196 | axis([0, max(t),-1,1]) |
---|
197 | ax(2) = subplot(2,2,2); |
---|
198 | plot(t,real(rx_IQ(:,2))) |
---|
199 | title('Re\{rx\_IQ_{RFB}\}') |
---|
200 | xlabel('Time (s)') |
---|
201 | %linkaxes(ax,'x') |
---|
202 | axis([0, max(t),-1,1]) |
---|
203 | |
---|
204 | FFTSIZE = 1024; |
---|
205 | |
---|
206 | ax(1) = subplot(2,2,3); |
---|
207 | rx_IQ_slice = rx_IQ(2049:end,1); |
---|
208 | rx_IQ_rs = reshape(rx_IQ_slice,FFTSIZE,length(rx_IQ_slice)/FFTSIZE); |
---|
209 | f = linspace(-20,20,FFTSIZE); |
---|
210 | fft_mag = abs(fftshift(fft(rx_IQ_rs))); |
---|
211 | plot(f,20*log10(mean(fft_mag,2))) |
---|
212 | title('FFT Magnitude of rx\_IQ_{RFA}') |
---|
213 | xlabel('Frequency (MHz)') |
---|
214 | axis([-20, 20,-20,40]) |
---|
215 | |
---|
216 | ax(2) = subplot(2,2,4); |
---|
217 | rx_IQ_slice = rx_IQ(2049:end,2); |
---|
218 | rx_IQ_rs = reshape(rx_IQ_slice,FFTSIZE,length(rx_IQ_slice)/FFTSIZE); |
---|
219 | f = linspace(-20,20,FFTSIZE); |
---|
220 | fft_mag = abs(fftshift(fft(rx_IQ_rs))); |
---|
221 | plot(f,20*log10(mean(fft_mag,2))) |
---|
222 | title('FFT Magnitude of rx\_IQ_{RFB}') |
---|
223 | xlabel('Frequency (MHz)') |
---|
224 | %linkaxes(ax,'x') |
---|
225 | axis([-20, 20,-20,40]) |
---|
226 | |
---|
227 | |
---|
228 | drawnow |
---|
229 | |
---|
230 | if (~RUN_CONTINOUSLY) |
---|
231 | break |
---|
232 | end |
---|
233 | |
---|
234 | end |
---|
235 | |
---|
236 | % Disable the TX / RX on all nodes |
---|
237 | wl_basebandCmd([node_tx1, node_tx2], ifc_ids_4RF.RF_ALL, 'tx_rx_buff_dis'); |
---|
238 | wl_basebandCmd(node_rx, ifc_ids_2RF.RF_ALL, 'tx_rx_buff_dis'); |
---|
239 | |
---|
240 | wl_interfaceCmd([node_tx1, node_tx2], ifc_ids_4RF.RF_ALL, 'tx_rx_dis'); |
---|
241 | wl_interfaceCmd(node_rx, ifc_ids_2RF.RF_ALL, 'tx_rx_dis'); |
---|
242 | |
---|
243 | |
---|