1 | function [RxData_withoutDCO] = warplab_correctDCO(RxData_withDCO,AGC_Set_Address) |
---|
2 | |
---|
3 | % DC Offset (DCO) removal |
---|
4 | |
---|
5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
6 | % Step 0: Compute the DC offset in the I and Q paths by averaging these |
---|
7 | % signals over the duration of a short symbol. Perform this averaging after |
---|
8 | % the AGC has set its gains, the sample at which the AGC is done setting |
---|
9 | % the gains is given by AGC_Set_Address. |
---|
10 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
11 | % Average I nand Q data over the duration of a short symbol. Lasts 16 |
---|
12 | % samples but for WARPLab we are upsampling by 2 so a short symbol lasts 32 |
---|
13 | % smaples. For WARPLab fs = 40MHz so 32 samples last 0.8us. |
---|
14 | RxData_withDCO_I = real(RxData_withDCO); |
---|
15 | DCO_I = mean(RxData_withDCO_I(AGC_Set_Address+1:AGC_Set_Address+32)); |
---|
16 | RxData_withDCO_Q = imag(RxData_withDCO); |
---|
17 | DCO_Q = mean(RxData_withDCO_Q(AGC_Set_Address+1:AGC_Set_Address+32)); |
---|
18 | |
---|
19 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
20 | % Step 1: Substract the computed I and Q DC offsets from their respective |
---|
21 | % signals for the rest of the samples and store result in |
---|
22 | % RxData_withoutDCO_1. The first 'AGC_Set_Address'+32 samples remain |
---|
23 | % unchanged, these are the samples before the AGC sets the gains and the 32 |
---|
24 | % samples that are used to compute the DC_Offset in step0 above. We leave |
---|
25 | % these samples unchanged so that the user can observe the exact signal |
---|
26 | % output by the ADC's, during the time the AGC is computing the gains, and |
---|
27 | % the 32 samples used to estimate the DCO. |
---|
28 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
29 | % Compute length of vector of received samples |
---|
30 | lenRxData = length(RxData_withDCO); |
---|
31 | % The first 'AGC_Set_Address'+32 samples remain unchanged |
---|
32 | RxData_withoutDCO_I_1 = RxData_withDCO_I(1:AGC_Set_Address+32); |
---|
33 | RxData_withoutDCO_Q_1 = RxData_withDCO_Q(1:AGC_Set_Address+32); |
---|
34 | % Remove DCO |
---|
35 | RxData_withoutDCO_I_1(AGC_Set_Address+32+1:lenRxData) = ... |
---|
36 | RxData_withDCO_I(AGC_Set_Address+32+1:lenRxData)-DCO_I; |
---|
37 | RxData_withoutDCO_Q_1(AGC_Set_Address+32+1:lenRxData) = ... |
---|
38 | RxData_withDCO_Q(AGC_Set_Address+32+1:lenRxData)-DCO_Q; |
---|
39 | |
---|
40 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
41 | % Step 2: Apply a higpass filter to remove any extra DCO. In Step 1 the DCO |
---|
42 | % computed in Step 0 was substracted from the received signal. This |
---|
43 | % porcessing reduces the DCO but the DCO estimated in Step 0 may not be the |
---|
44 | % true DCO, a residual error may remain and it must be removed. This |
---|
45 | % residual error is removed applyig a high pass filter. |
---|
46 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
47 | % The highpass filter is designed offline using MATLAB's fdatool. The |
---|
48 | % filter coefficients are defined below. |
---|
49 | Filter_Num = 0.99843166591671906 * [1,-1]; |
---|
50 | Filter_Den = [1,-0.99686333183343789]; |
---|
51 | % Filter the residual DCO |
---|
52 | RxData_withoutDCO_I = RxData_withoutDCO_I_1; |
---|
53 | RxData_withoutDCO_I(AGC_Set_Address+32+1:lenRxData) = ... |
---|
54 | filter(Filter_Num,Filter_Den,RxData_withoutDCO_I_1(AGC_Set_Address+32+1:lenRxData)); |
---|
55 | RxData_withoutDCO_Q = RxData_withoutDCO_Q_1; |
---|
56 | RxData_withoutDCO_Q(AGC_Set_Address+32+1:lenRxData) = ... |
---|
57 | filter(Filter_Num,Filter_Den,RxData_withoutDCO_Q_1(AGC_Set_Address+32+1:lenRxData)); |
---|
58 | % Create output vector |
---|
59 | RxData_withoutDCO = complex(RxData_withoutDCO_I,RxData_withoutDCO_Q); |
---|
60 | |
---|