Skip to content

Commit 7a9ab20

Browse files
committed
Add MIMO K-best Schnorr-Euchner Detection.
Reference: Zhan Guo and P. Nilsson, 'Algorithm and implementation of the K-best sphere decoding for MIMO detection', IEEE Journal on Selected Areas in Communications, vol. 24, no. 3, pp. 491-503, Mar. 2006.
1 parent f39bc48 commit 7a9ab20

File tree

2 files changed

+79
-5
lines changed

2 files changed

+79
-5
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ Modulation/Demodulation
5252
- Phase Shift Keying (PSK)
5353
- Quadrature Amplitude Modulation (QAM)
5454
- OFDM Tx/Rx signal processing
55+
- MIMO Maximum Likelihood (ML) Detection.
56+
- MIMO K-best Schnorr-Euchner Detection.
5557

5658
Sequences
5759
---------

commpy/modulation.py

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,24 @@
1212
1313
PSKModem -- Phase Shift Keying (PSK) Modem.
1414
QAMModem -- Quadrature Amplitude Modulation (QAM) Modem.
15+
ofdm_tx -- OFDM Transmit Signal Generation
16+
ofdm_rx -- OFDM Receive Signal Processing
1517
mimo_ml -- MIMO Maximum Likelihood (ML) Detection.
18+
kbest -- MIMO K-best Schnorr-Euchner Detection.
1619
1720
"""
18-
from numpy import arange, array, zeros, pi, cos, sin, sqrt, log2, argmin, \
19-
hstack, repeat, tile, dot, sum, shape, concatenate, exp, \
20-
log, vectorize
2121
from itertools import product
22-
from commpy.utilities import bitarray2dec, dec2bitarray
22+
23+
from numpy import arange, array, zeros, pi, cos, sin, sqrt, log2, argmin, \
24+
hstack, repeat, tile, dot, sum, shape, concatenate, exp, \
25+
log, vectorize, empty
2326
from numpy.fft import fft, ifft
27+
from numpy.linalg import qr
28+
29+
from commpy.utilities import bitarray2dec, dec2bitarray
30+
31+
__all__ = ['PSKModem', 'QAMModem', 'ofdm_tx', 'ofdm_rx', 'mimo_ml', 'kbest']
2432

25-
__all__ = ['PSKModem', 'QAMModem', 'mimo_ml']
2633

2734
class Modem:
2835

@@ -193,3 +200,68 @@ def mimo_ml(y, h, constellation):
193200
x_r = x_ideal[:, min_idx]
194201

195202
return x_r
203+
204+
205+
def kbest(y, h, constellation, K):
206+
""" MIMO K-best Schnorr-Euchner Detection.
207+
208+
Reference: Zhan Guo and P. Nilsson, 'Algorithm and implementation of the K-best sphere decoding for MIMO detection',
209+
IEEE Journal on Selected Areas in Communications, vol. 24, no. 3, pp. 491-503, Mar. 2006.
210+
211+
parameters
212+
----------
213+
y : 1D ndarray of floats
214+
Received complex symbols (shape: num_receive_antennas x 1)
215+
216+
h : 2D ndarray of floats
217+
Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
218+
219+
constellation : 1D ndarray of floats
220+
Constellation used to modulate the symbols
221+
222+
K : positive integer
223+
Number of candidates kept at each step
224+
"""
225+
# QR decomposition
226+
q, r = qr(h)
227+
yt = q.conj().T.dot(y)
228+
229+
# Initialization
230+
m = len(constellation)
231+
n = len(yt)
232+
nb_can = 1
233+
234+
if isinstance(constellation[0], complex):
235+
const_type = complex
236+
else:
237+
const_type = float
238+
X = empty((n, K * m), dtype=const_type) # Set of current candidates
239+
d = tile(yt[:, None], (1, K * m)) # Corresponding distance vector
240+
d_tot = zeros(K * m, dtype=float) # Corresponding total distance
241+
hyp = empty(K * m, dtype=const_type) # Hypothesis vector
242+
243+
# Processing
244+
for coor in range(n-1, -1, -1):
245+
nb_hyp = nb_can * m
246+
247+
# Copy best candidates m times
248+
X[:, :nb_hyp] = tile(X[:, :nb_can], (1, m))
249+
d[:, :nb_hyp] = tile(d[:, :nb_can], (1, m))
250+
d_tot[:nb_hyp] = tile(d_tot[:nb_can], (1, m))
251+
252+
# Make hypothesis
253+
hyp[:nb_hyp] = repeat(constellation, nb_can)
254+
X[coor, :nb_hyp] = hyp[:nb_hyp]
255+
d[coor, :nb_hyp] -= r[coor, coor] * hyp[:nb_hyp]
256+
d_tot[:nb_hyp] += abs(d[coor, :nb_hyp])**2
257+
258+
# Select best candidates
259+
argsort = d_tot[:nb_hyp].argsort()
260+
nb_can = min(nb_hyp, K) # Update number of candidate
261+
262+
# Update accordingly
263+
X[:, :nb_can] = X[:, argsort[:nb_can]]
264+
d[:, :nb_can] = d[:, argsort[:nb_can]]
265+
d[:coor, :nb_can] -= r[:coor, coor, None] * hyp[argsort[:nb_can]]
266+
d_tot[:nb_can] = d_tot[argsort[:nb_can]]
267+
return X[:, 0]

0 commit comments

Comments
 (0)