Why oversample data before using raised cosine filter?

In the process of creating a baseband signal, the complex symbols are filtered using a raised cosine filter to perform pulse shaping (I'm following some literature as a guide). The pulse shaping is performed with the code:

%Create the filter
over=16;
pulse=rcosine(1,over,'normal',0.35);
[trash, pos]=max(pulse);

%Oversample the symbols
sig=kron(sym,[1 zeros(1,over-1)]);
sig=filter(pulse,1,sig);
sig=sig(pos:end);

So the sampling frequency of the filter is 16, which requires 15 zeros be added between all of the symbols. What is the purpose of this? How does this not introduce "extra data" into the original message?

In digital communications, you can transmit a sequence of numbers using a train of pulses that don't interfere with each other. A given raised cosine pulse $p(t)$ has zero crossings every $T$ seconds around its peak (for a certain $T$). Let's say you want to transmit the number sequence $\lbrace 3, -5 \rbrace$. You can do this with the 2-pulse train $$s(t)=3p(t)-5p(t-T).$$ If you sample $s(t)$ at $t=0$ and $t=T$, you'll get the values 3 and -5.

Your question is related to implementing this idea in Matlab. To do this, you have to solve two different problems: how to create the pulse $p(t)$, and then how to create the train pulse $s(t)$.

Let's start with the pulse $p(t)$. Since you specify Fd=1, then the number of samples in the pulse between the peak and its zero-crossings is given by over. In your case, you can see that the peak occurs at sample 49 and the first zero crossing at sample 65, or 16 samples apart, which is the value of variable over. So, you have defined a pulse $p(t)$ with $T$ equal to 16 sample intervals.

In order to generate the pulse train $s(t)$, you start with the sequence sym. Then you insert 15 zeros between the elements of sym, and finally calculate the convolution of the spaced sequence and the pulse. The result of the convolution will be the addition of pulses $p(t-T)$, scaled with the values of sym.

Let us return to the example of transmitting the sequence $\lbrace 3, -5 \rbrace$. You start with

sym = [3 -5];

from which you generate sig:

sig = [3 0 ... 0 -5 0 ... 0];

The convolution of sig and pulse is the addition of 3*pulse starting at sample 1, and -5*pulse starting at sample 16. The first pulse has a peak equal to 3 at sample number 49, and the second pulse has a peak equal to -5 at sample number 65. The pulses interfere with each other at most sample times but, crucially, the second pulse is zero at sample 50, and the first is zero at sample 66. So, at those precise times, they don't interfere with each other. By sampling the convolution at those times, the receiver can recover the transmitted sequence.

Try this simple code in Matlab:

p=rcosine(1,16,'normal',0.35);
s=[3,-5];
sig=kron(s,[1 zeros(1,15)]);
ss=filter(sig,1,x);
plot(ss);

Using the data cursor, you can verify what I said above. You can also print those values with:

[ss(49) ss(65)]