1
$\begingroup$

I am trying to send QAM data through AWGN channel and I have 256 samples/symbol, I have the following code:

data = randi([0 3], 1, 2^12); % Generate data
dataMod = qammod(data, 4);  % Modulate data
dataMod_u = upsample(dataMod,256); % Upsample
b = rcosdesign(0.25,8,256,'sqrt');
dataMod_f = filter(b, 1, dataMod_u); % Tx Filter 

channel2 = comm.AWGNChannel('EbNo',15,'BitsPerSymbol',2,'SamplesPerSymbol',256);
ch_out2 = step(channel2, dataMod_f); % Pass through channel
ch_out_f2 = filter(b,1,ch_out2);    % RX Filter
ch_out_f2 = downsample(ch_out_f2,256); % Downsample
scatterplot(ch_out_f2)

I get the following scatter plot after passing through channel:

enter image description here

Why I don't see the modulated output, what am I doing wrong?

$\endgroup$
1
$\begingroup$

UPDATE: Scaling was not adjust for upsample/downsample.

data = randi([0 3], 1, 2^12); % Generate data
dataMod = qammod(data, 4);  % Modulate data
dataMod_u = 16*upsample(dataMod,256); % Upsample
b = rcosdesign(0.25,8,256,'sqrt');
dataMod_f = filter(b, 1, dataMod_u); % Tx Filter 

channel2 = comm.AWGNChannel('EbNo',15,'BitsPerSymbol',2,'SamplesPerSymbol',256);
ch_out2 = step(channel2, dataMod_f); % Pass through channel
ch_out_f2 = filter(b,1,ch_out2);    % RX Filter
ch_out_f2 = (1/16)*downsample(ch_out_f2,256); % Downsample
scatterplot(ch_out_f2)

enter image description here

$\endgroup$
7
  • $\begingroup$ Thank -you very much! $\endgroup$ – sarthak Apr 17 '20 at 10:04
  • $\begingroup$ There is still some extra scaling happening. I am working on it. $\endgroup$ – jithin Apr 17 '20 at 10:06
  • 1
    $\begingroup$ Could you please also explain why we need this normalization and what it does? $\endgroup$ – sarthak Apr 17 '20 at 10:08
  • $\begingroup$ I have updated the scaling. For upsampling/downsampling you have to compensate for the gain/loss of energy. That is I multiplied by 16 (sqrt(256)) while upsampling and (1/16) while downsampling. It was not the RRC filter problem! $\endgroup$ – jithin Apr 17 '20 at 10:21
  • 2
    $\begingroup$ When you upsample by 256, you are filling with 255 zeros. This causes drop in overall signal energy by 256. So to compensate for this you need scale amplitude (volts) by 16 so that energy (V^2) is scaled by 256. Similarly for down-sampling you need to compensate. $\endgroup$ – jithin Apr 17 '20 at 10:29
1
$\begingroup$

Scaling and de-scaling is just covering up the real problem here. When you multiply each symbol by $\sqrt{\text{sps}}$ you are setting the signal power equal to the symbol energy (var(modData) == var(modData_f)). You also un-do this in the end so from transmitted symbol to received symbol it is fine, but if you want to do anything with the signal in between the power will be off!

We know that the signal to noise ratio (SNR), in dB, can be found by: $\text{SNR}=\frac{E_b}{N_0}+10\log_{10}(k)-10\log_{10}(\text{sps})$, where $k$ is the number of bits per symbol. Using this, insert the following check code in:

% ===== MY CHECK CODE =====
noise = ch_out2 - dataMod_f;
snrFromData = pow2db(var(dataMod_f)/var(noise))
snrFromEquation = 15 + 10*log10(2) - 10*log10(256)

You will find that the SNR is off by $3 \text{ dB}$. This comes from the fact that the average symbol energy for 4-QAM is $E_s=2$. The comm.AWGNChannel expects the input signal to have unit power by default (expects $\text{Signal Power}=1$, but by multiplying by $\sqrt{\text{sps}}$ you ended up setting $\text{Signal Power}=2(=E_s)$). There is a property SignalPower which needs to be set, see the documentation page (https://uk.mathworks.com/help/comm/ref/comm.awgnchannel-system-object.html). You can add this to your command: comm.AWGNChannel(..., 'SignalPower', var(dataMod_f)), or you can normalize the symbols to have $E_s=1$ to begin with by adding this: dataMod = dataMod ./ sqrt(var(dataMod)).

To see a situation where this problem is more dramatic, try a modulation where with a higher $E_s$, try changing qammod to pammod.

Full code comparing the accepted answer and my check code showing the discrepancy:

%% Accepted answer code
data = randi([0 3], 1, 2^12); % Generate data
dataMod = qammod(data, 4);  % Modulate data
dataMod_u = sqrt(256)*upsample(dataMod,256); % Upsample
b = rcosdesign(0.25,8,256,'sqrt');
dataMod_f = filter(b, 1, dataMod_u); % Tx Filter 

channel2 = comm.AWGNChannel('EbNo',15,'BitsPerSymbol',2,'SamplesPerSymbol',256);
ch_out2 = step(channel2, dataMod_f); % Pass through channel

% ===== MY CHECK CODE =====
noise = ch_out2 - dataMod_f;
snrFromData = pow2db(var(dataMod_f)/var(noise))
snrFromEquation = 15 + 10*log10(2) - 10*log10(256)


%% My answer code
data = randi([0 3], 1, 2^12); % Generate data
dataMod = qammod(data, 4);  % Modulate data
dataMod_u = upsample(dataMod, 256); % Upsample
b = rcosdesign(0.25,8,256,'sqrt');
dataMod_f = filter(b, 1, dataMod_u); % Tx Filter 

channel2 = comm.AWGNChannel('EbNo', 15, 'BitsPerSymbol', 2, 'SamplesPerSymbol', 256, 'SignalPower', var(dataMod_f));
ch_out2 = step(channel2, dataMod_f); % Pass through channel
noise = ch_out2 - dataMod_f;

% ===== MY CHECK CODE =====
snrFromData2 = pow2db(var(dataMod_f)/var(noise))

$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.