One raised cosine filter vs two cascaded root raised cosine filters
Started by 4 years ago●12 replies●latest reply 4 years ago●669 viewsIf I send a random series of symbol impulses (+3.0, +1.0, -1.0, -3.0) through a raised cosine filter (alpha = 0.2, 31 taps), the output contains a filtered, delayed stream of samples that includes the undistorted impulse values at the center of each filtered bit cell. This makes sense.
If I send the same series of symbol impulses through a root raised cosine filter (beta = 0.2, 31 taps), and then send the output of that filter through a second, identical root raised cosine filter, the output is a badly distorted mess.
From my understanding of these filters, y=rc(x) should be the same as y=rrc(rrc(x)) if taps and rolloff are all the same. However, that's not what I'm seeing. Is there a decimation step that I'm missing? Or, should the second filter be constructed differently because there is no decimation? Or, I'm off base in another way?
(This is the same basic setup as a similar question I posted here a week ago)
You have the idea correct, as far as I can tell. Think of it in the frequency domain, where a frequency-selective filter is just multiplying the input frequencies by some attenuation value to achieve the desired spectral shaping. That multiplication can split into the square roots of the frequency-domain coefficients, so multiplying by the same values twice, in the frequency domain, provides exactly the same frequency response as doing it once with the original values.
So, yes, two properly-configured rrc filters back to back provide an rc response.
If you're getting something else, there's definitely an issue somewhere. Hard to say where it might be though.
I think I have a fundamental misunderstanding, because the first rrc filter interpolates while the second does not. Every time I input a symbol impulse followed by 9 zeros to the first filter, it outputs a filtered 10-sample long shaped symbol. It seems like the second rrc filter would need to be designed very differently from the first one to accept that type of input.
Jon,
Actually, the 2nd filter should be identical to the first one. you are correct to upsample before filtering on the transmit side. Are you viewing an eyeplot of the output on the receive side?
I have an example of RRC filtering at my post at:
https://www.dsprelated.com/showarticle/1312.php
regards,
Neil
There is just something I don't understand here. I have an raised cosine filter with 31 taps, and a root raised cosine filter with 31 taps. If I send a single impulse through either one, I get an impulse response which is 31 samples wide. If I then send the 31-sample impulse response from the root raised cosine filter through an identical root raised cosine filter, the overall response will be 62 samples wide. I just don't see how two cascaded 31-tap filters could ever have the same impulse response as 1 31-tap filter. What on earth am I missing?
Yes, the two cases you mentioned won't be the same length. However, there will be samples at either end of the cascaded root-Nyquist response that are close to zero. So the responses will be approximately the same over the samples that matter.
regards,
Neil
Jon,
Here is an example of random symbols of value +.5/-.5 filtered by cascaded root-Nyquist filters. The m-file eye1.m calls the function eyeplot.m. Both mfile and function are listed here.
The plot is shown below the mfiles.
% eye1.m
% eyeplot of cascaded root-nyquist filters 4 samples/symbol
% root-nyquist FIR with alpha = .25 and fs= 4*fsymbol from root_nyq3.m
b1= [12 -1 -10 -18 -17 -1 20 34 25 -7 -46 -62 -36 27 92 108 46 ...
-77 -192 -206 -53 260 643 958];
b_nyq= [b1 1079 fliplr(b1)]/4096;
N= 1024; % number of symbols
u= round(rand(1,N));
x= u -1/2; % symbols at 1 sample/symbol
x_up= zeros(1,4*N);
x_up(1:4:4*N)= x; % upsample to 4 samples/symbol
x1= 4*filter(b_nyq,1,x_up); % root-nyquist filter
x2= filter(b_nyq,1,x1); % root-nyquist filter
% eyeplot of x2 (4 samples/symbol)
eyeplot(x2(49:end),4)
xlabel('symbols')
_______________________________________________________
%eyeplot.m 10/29/19 Neil Robertson
% Plot eye diagram of vector x
% fs = samples per symbol (integer)
% A = matrix with each column containing 2*fs + 1 samples.
% Each column is a trace in the plot.
% Last element of column j = first element of column j+1
%
function eyeplot(x,fs)
L= 2*fs;
cols= fix(length(x)/L -1);
x= x(1:L*(cols+1)); % truncate x to an integer multiple of L
for j= 1:cols % column index
k= j-1;
A(:,j)= x(k*L+1:(k+1)*L+1); % column= one trace of length 2*fs +1
end
t= 0:1/fs:2;
plot(t,A,'color',[0 .447 .741]),grid
axis([0 2 -1.5 1.5])
This was very informative. Thanks!
Playing around with RC and RRC filters, I have found two things: First, I am not using enough taps for this application, and second, cascaded RRC filters need a lot more taps than the single RC filter they're supposed to approximate. For instance, a 41-tap RC filter looks like this:
while two cascaded 41-tap RRC filters look like this:
To get two cascaded RRC filters to start looking like a serviceable replacement for one 41-tap RC filter, I have to go up to 81 taps:
or to 101 taps:
So my main problem (I think) was that the filters I was playing around with just weren't accurate enough. When I add fading and jitter, I suspect I'll need more taps. I'm going to have to rethink a few things concerning processing power and a 4-5 symbol pipeline delay.
Hi Jon,
Looks like progress! You could of course reduce the number of taps by reducing the number of samples per symbol in the RRC filters. It is common to use 2 or 4 samples per symbol for RRC filters. You then use an interpolator on the transmit side to increase the sample rate and use a decimator on the receive side to reduce the sample rate. The interpolator and decimator need to be flat over (1 + alpha)*fc, where fc is the -3 dB frequency of the RRC filter.
Neil
Neil, this is the Scilab script I hacked up from your script above. Thanks!
// //eyeplot.m 10/29/19 Neil Robertson // Plot eye diagram of vector x // fs = samples per symbol (integer) // A = matrix with each column containing 2*fs + 1 samples. // Each column is a trace in the plot. // Last element of column j = first element of column j+1 // function eyeplot(x, fs) L= 2*fs; cols= fix(length(x)/L -1); x= x(1:L*(cols+1)); //% truncate x to an integer multiple of L for j= 1:cols //% column index k= j-1; A(:,j)= x(k*L+1:(k+1)*L+1); //% column= one trace of length 2*fs +1 end t= 0:1/fs:2; plot(t,A/*,'color',[0 .447 .741]*/),xgrid; mtlb_axis([0 2 -6 6]); endfunction // // Filter coefficients, all for Fs=48000, 4800 symbols/second, // alpha(beta)=0.2. All filter coefficients were generated using // https://www-users.cs.york.ac.uk/~fisher/mkfilter/racos.html // // rc81 -- 81-tap raised cosine // rrc31 -- 31-tap root raised cosine // rrc41 -- 41-tap root raised cosine // rrc81 -- 81-tap root raised cosine // rrc101 -- 101-tap root raised cosine // b_rc31 = ... [ ... -0.1948935699 -0.2008073622 -0.1858588307 -0.1476834708 ... -0.0854418459 -0.0000002748 +0.1060183670 +0.2283240326 ... +0.3611874154 +0.4977925441 +0.6306889295 +0.7523088221 ... +0.8555086925 +0.9340911232 +0.9832642151 +1.0000003401 ... +0.9832642151 +0.9340911232 +0.8555086925 +0.7523088221 ... +0.6306889295 +0.4977925441 +0.3611874154 +0.2283240326 ... +0.1060183670 -0.0000002748 -0.0854418459 -0.1476834708 ... -0.1858588307 -0.2008073622 -0.1948935699 ... ]; gain_rc31 = 1.006899792e+01; b_rc41 = ... [ ... +0.0000001040 -0.0451178627 -0.0918953878 -0.1357451216 ... -0.1717174097 -0.1948935699 -0.2008073622 -0.1858588307 ... -0.1476834708 -0.0854418459 -0.0000002748 +0.1060183670 ... +0.2283240326 +0.3611874154 +0.4977925441 +0.6306889295 ... +0.7523088221 +0.8555086925 +0.9340911232 +0.9832642151 ... +1.0000003401 +0.9832642151 +0.9340911232 +0.8555086925 ... +0.7523088221 +0.6306889295 +0.4977925441 +0.3611874154 ... +0.2283240326 +0.1060183670 -0.0000002748 -0.0854418459 ... -0.1476834708 -0.1858588307 -0.2008073622 -0.1948935699 ... -0.1717174097 -0.1357451216 -0.0918953878 -0.0451178627 ... +0.0000001040 ... ]; gain_rc41 = 9.180046559e+00; b_rc81 = ... [ ... -0.0000002772 -0.0135558765 -0.0273900580 -0.0400237301 ... -0.0499275270 -0.0556838388 -0.0561547723 -0.0506383724 ... -0.0389949939 -0.0217271925 +0.0000001070 +0.0244073198 ... +0.0492175718 +0.0718384353 +0.0895956345 +0.0999999558 ... +0.1010236544 +0.0913597531 +0.0706372006 +0.0395671028 ... +0.0000001040 -0.0451178627 -0.0918953878 -0.1357451216 ... -0.1717174097 -0.1948935699 -0.2008073622 -0.1858588307 ... -0.1476834708 -0.0854418459 -0.0000002748 +0.1060183670 ... +0.2283240326 +0.3611874154 +0.4977925441 +0.6306889295 ... +0.7523088221 +0.8555086925 +0.9340911232 +0.9832642151 ... +1.0000003401 +0.9832642151 +0.9340911232 +0.8555086925 ... +0.7523088221 +0.6306889295 +0.4977925441 +0.3611874154 ... +0.2283240326 +0.1060183670 -0.0000002748 -0.0854418459 ... -0.1476834708 -0.1858588307 -0.2008073622 -0.1948935699 ... -0.1717174097 -0.1357451216 -0.0918953878 -0.0451178627 ... +0.0000001040 +0.0395671028 +0.0706372006 +0.0913597531 ... +0.1010236544 +0.0999999558 +0.0895956345 +0.0718384353 ... +0.0492175718 +0.0244073198 +0.0000001070 -0.0217271925 ... -0.0389949939 -0.0506383724 -0.0561547723 -0.0556838388 ... -0.0499275270 -0.0400237301 -0.0273900580 -0.0135558765 ... -0.0000002772 ... ]; gain_rc81 = 9.747146752e+00; b_rrc31 = ... [ ... -0.1847425896 -0.2073523972 -0.2086782295 -0.1845719273 ... -0.1326270847 -0.0525370892 +0.0537187153 +0.1818868577 ... +0.3256572849 +0.4770745929 +0.6271117870 +0.7663588857 ... +0.8857664963 +0.9773779594 +1.0349835419 +1.0546365475 ... +1.0349835419 +0.9773779594 +0.8857664963 +0.7663588857 ... +0.6271117870 +0.4770745929 +0.3256572849 +0.1818868577 ... +0.0537187153 -0.0525370892 -0.1326270847 -0.1845719273 ... -0.2086782295 -0.2073523972 -0.1847425896 ... ]; gain_rrc31 = 9.773490154e+00; b_rrc41 = ... [ ... +0.0465831968 +0.0037187043 -0.0460635022 -0.0979622825 ... -0.1462501260 -0.1847425896 -0.2073523972 -0.2086782295 ... -0.1845719273 -0.1326270847 -0.0525370892 +0.0537187153 ... +0.1818868577 +0.3256572849 +0.4770745929 +0.6271117870 ... +0.7663588857 +0.8857664963 +0.9773779594 +1.0349835419 ... +1.0546365475 +1.0349835419 +0.9773779594 +0.8857664963 ... +0.7663588857 +0.6271117870 +0.4770745929 +0.3256572849 ... +0.1818868577 +0.0537187153 -0.0525370892 -0.1326270847 ... -0.1845719273 -0.2086782295 -0.2073523972 -0.1847425896 ... -0.1462501260 -0.0979622825 -0.0460635022 +0.0037187043 ... +0.0465831968 ... ]; gain_rrc41 = 9.293542135e+00; b_rrc81= ... [ ... +0.0273676736 +0.0190682959 +0.0070661879 -0.0075385898 ... -0.0231737159 -0.0379433607 -0.0498333862 -0.0569528373 ... -0.0577853377 -0.0514204905 -0.0377352004 -0.0174982391 ... +0.0076217868 +0.0351552125 +0.0620353691 +0.0848941519 ... +0.1004237235 +0.1057694293 +0.0989127431 +0.0790009892 ... +0.0465831968 +0.0037187043 -0.0460635022 -0.0979622825 ... -0.1462501260 -0.1847425896 -0.2073523972 -0.2086782295 ... -0.1845719273 -0.1326270847 -0.0525370892 +0.0537187153 ... +0.1818868577 +0.3256572849 +0.4770745929 +0.6271117870 ... +0.7663588857 +0.8857664963 +0.9773779594 +1.0349835419 ... +1.0546365475 +1.0349835419 +0.9773779594 +0.8857664963 ... +0.7663588857 +0.6271117870 +0.4770745929 +0.3256572849 ... +0.1818868577 +0.0537187153 -0.0525370892 -0.1326270847 ... -0.1845719273 -0.2086782295 -0.2073523972 -0.1847425896 ... -0.1462501260 -0.0979622825 -0.0460635022 +0.0037187043 ... +0.0465831968 +0.0790009892 +0.0989127431 +0.1057694293 ... +0.1004237235 +0.0848941519 +0.0620353691 +0.0351552125 ... +0.0076217868 -0.0174982391 -0.0377352004 -0.0514204905 ... -0.0577853377 -0.0569528373 -0.0498333862 -0.0379433607 ... -0.0231737159 -0.0075385898 +0.0070661879 +0.0190682959 ... +0.0273676736 ... ]; gain_rrc81 = 9.868410946e+00; b_rrc101= ... [ ... -0.0169879130 -0.0153668622 -0.0111893237 -0.0047295201 ... +0.0033820246 +0.0122072472 +0.0205959659 +0.0273195507 ... +0.0312286896 +0.0314167215 +0.0273676736 +0.0190682959 ... +0.0070661879 -0.0075385898 -0.0231737159 -0.0379433607 ... -0.0498333862 -0.0569528373 -0.0577853377 -0.0514204905 ... -0.0377352004 -0.0174982391 +0.0076217868 +0.0351552125 ... +0.0620353691 +0.0848941519 +0.1004237235 +0.1057694293 ... +0.0989127431 +0.0790009892 +0.0465831968 +0.0037187043 ... -0.0460635022 -0.0979622825 -0.1462501260 -0.1847425896 ... -0.2073523972 -0.2086782295 -0.1845719273 -0.1326270847 ... -0.0525370892 +0.0537187153 +0.1818868577 +0.3256572849 ... +0.4770745929 +0.6271117870 +0.7663588857 +0.8857664963 ... +0.9773779594 +1.0349835419 +1.0546365475 +1.0349835419 ... +0.9773779594 +0.8857664963 +0.7663588857 +0.6271117870 ... +0.4770745929 +0.3256572849 +0.1818868577 +0.0537187153 ... -0.0525370892 -0.1326270847 -0.1845719273 -0.2086782295 ... -0.2073523972 -0.1847425896 -0.1462501260 -0.0979622825 ... -0.0460635022 +0.0037187043 +0.0465831968 +0.0790009892 ... +0.0989127431 +0.1057694293 +0.1004237235 +0.0848941519 ... +0.0620353691 +0.0351552125 +0.0076217868 -0.0174982391 ... -0.0377352004 -0.0514204905 -0.0577853377 -0.0569528373 ... -0.0498333862 -0.0379433607 -0.0231737159 -0.0075385898 ... +0.0070661879 +0.0190682959 +0.0273676736 +0.0314167215 ... +0.0312286896 +0.0273195507 +0.0205959659 +0.0122072472 ... +0.0033820246 -0.0047295201 -0.0111893237 -0.0153668622 ... -0.0169879130 ... ]; gain_rrc101 = 1.002416411e+01; // // Select the filter, whether to cascade it, and // the number of symbols // gain = gain_rc41; b = b_rc41; cascade = 0; N = 10000; // // Generate random symbols // x_3 = rand(1, N); x_2 = round(x_3 * 3); x_1 = x_2 * 2; x = x_1 - 3; // // Interpolate the symbols // x_up = zeros(1,10*N); x_up(1:10:10*N) = x; // // Pass the symbols through the first filter // x_filt_1 = filter(b,1,x_up); delay = ((length(b) - 1) / 2) + 1; // // If requested, pass the symbols through the second filter // if (cascade == 1) then delay = length(b); x_filt_2 = (1/gain) * filter(b,1,x_filt_1); else x_filt_2 = x_filt_1; end // // Show the eye diagram // eyeplot(x_filt_2(delay:N),10);
Two filters of (h1 = 31 taps, h2 = 31 taps) cascaded is same as one filter whose taps are h = conv(h1,h2) hence h = 61 taps single filter.
Basically any two filters...
The filters need to be compatible from a sampling perspective. One way to think of it is that the filter is designed assuming a certain number of samples per symbol, say four samples per symbol. If the sampled stream has some other sampling rate then the filter response will not be correct.
The sample rates of the rrc filters can be different, they just need to match whatever the oversample rate of the signal happens to be at that point.
I hope that makes sense.