I have a receiver which receives data bits at a rate of 5kbit/s. The number of data bits per burst is low (say, 16 bits). These databits are obtained after despreading the incoming signal using an orthogonal CDMA code (8-bit Walsh Haddamard code). This implies that the incoming chip rate is 5*8=40 kchips/s. The actual signal I get from the ADC is an upsampled I/Q version at complex baseband, sampled at a certain sampling rate (e.g. 5Msps). I implement the system in gnuradio (but the question is general).
I figured that instead of explicitely performing the despreading via multiplication and summing up the values, it is easier to use the cdma_code as a filter. This can be interpreted as a form of matched filtering (I think). However, this simplified version misses an important point: Timing. In the worst case, the downsampling happens at the symbol or bit transitions and the result is garbage. Hence I use clock synchronization based on polyphase filtering (https://wiki.gnuradio.org/index.php/Polyphase_Clock_Sync).
However, I have a multi-stage downconversion system here: I am able time-synchronize the chip stream with the Polyphase Clock Sync block. However, when I apply despreading (by filtering the chip stream with the time-reverse chip sequence and decimating) I again have a time alignment issue: the 8 bit chip code has to be aligned with the input signal.
I tried using the polyphase clock sync block where the matched filter combines the matched filter and the CDMA code as suggested in Marcus Müllers answer below. However, I think such a system is unable to find the correct offset.
Consider this simple MATLAB experiment which generates a sample stream encoding $[1,-1,1,1]$. The receiver simulates the "Polyphase Clock Sync" block in gnuradio by finding the time shift that minimizes $(b\cdot db/dt)_{t=nT}$ where $b$ is a shifted version of the input signal:
fs = 400e3;
fchip = 40e3;
% test bits 1,-1,1,1 and add zero-padding
testdata = [ 0 0 0 0 0 1 -1 1 1 0 0 0 0 0 ]';
% 8-bit Walsh-Haddamard
H = [ 1, -1, 1, -1, -1, 1, -1, 1 ];
SF = size(H,2);
Nbits = size(testdata, 1);
% the test data at the chip rate
testdata_cr = upfirdn(testdata(:,1), ones(1, SF), SF);
% the modulated chip stream
chips = testdata_cr .* repmat(H(1,:)', Nbits, 1);
% upconvert chip stream to sample stream using rrcos (for simplicity)
hup2 = rcosdesign(0.8, 15, fs/fchip);
samples = upfirdn(chips, hup2, fs/fchip);
%% RECEIVER
% define the matched filter (=rrcos + CDMA code) at the receiver
mfilt = upfirdn(H(1,:), hup2, fs/fchip);
x = filter(mfilt, 1, samples);
% This implements a simplified version of the Polyphase Clock Sync block
delays = -fs/(fchip/SF)/2:1:fs/(fchip/SF)/2;
res = zeros(length(delays), 1);
B = zeros(length(x), length(delays));
for m=1:length(delays)
B(:,m) = circshift(x, delays(m)); % works because of zero padding
%plot(b);hold all;
v = B(:,m) .* gradient(B(:,m));
res(m) = sum(v(1:fs/fchip*SF:end)); % sum samples
end
% find the delays where b * db/dt is approximately zero
zeroxing = @(v) find(v(:).*circshift(v(:), [-1 0]) <= 0);
idx = zeroxing(res);
%plot(delays, abs(res), '-', delays(idx), res(idx), 'o');
% plot the candidates
plot(B(1:fs/fchip*SF:end,idx))
Since this block uses $b$ as an objective function (using the delay index that minimizes the sum of the samples of $b\cdot db/dt$), there must be a global optimum which finds the correct sequence $[1,-1,1,1]$. However, there are multiple optimum delays (values close to zero):
Now I plot the resulting bit stream for all the delays where the objective function is close to zero and only one shift gives the correct $[1,-1,1,1]$ pattern:
I can reproduce this experiment with a gnuradio model as well (https://www.dropbox.com/s/48fy30vwkivahqz/test_polyphase_clock_recovery_cdma_direct.grc):
My question is: How to implement such a system and how would one do this in practice?