Skip to content

Instantly share code, notes, and snippets.

@kumanna
Created February 4, 2026 10:00
Show Gist options
  • Select an option

  • Save kumanna/3c5061e3f51989a6ca9337203e405fe9 to your computer and use it in GitHub Desktop.

Select an option

Save kumanna/3c5061e3f51989a6ca9337203e405fe9 to your computer and use it in GitHub Desktop.
import numpy as np
import matplotlib.pyplot as plt
T = 1
delta_f = 1 / T
M = 8
N = 8
OVERSAMPLING = 128
t = np.arange(-10 * N * M * T, 10 * N * T * M, 1 / OVERSAMPLING)
def alpha_kl(k, l, t, M, N, T):
s = np.zeros_like(t, dtype='complex')
delta_f = 1 / T
for n in range(N):
EXPPARAM = (t - l * T / M - n * T)
s_ = np.exp(1j * 2 * np.pi * n * k / N) * \
np.exp(1j * np.pi * delta_f * M * EXPPARAM) * \
np.sinc(delta_f * M * EXPPARAM) * M * delta_f
s = s + s_
return np.sqrt(T / M / N) * s
import numpy as np
sample_vector = alpha_kl(0, 0, t, M, N, T)
vector_len = len(sample_vector)
# 2. Initialize a 3D array of zeros
# Shape: (M rows, N columns, vector_len depth)
alpha_array = np.zeros((M, N, vector_len), dtype='complex')
# 3. Populate the array using nested loops
for k in range(M):
for l in range(N):
alpha_array[k, l, :] = alpha_kl(k, l, t, M, N, T)
# Send symbols on these
symbols = np.array([1, 1j, 1+1j, -1j])
waveform = np.zeros_like(alpha_array[0][0], dtype='complex')
waveform += symbols[0] * alpha_array[0][0]
waveform += symbols[1] * alpha_array[0][1]
waveform += symbols[2] * alpha_array[1][0]
waveform += symbols[3] * alpha_array[1][1]
# Recover the symbols
symbols_recovered = np.zeros_like(symbols, dtype='complex')
symbols_recovered[0] = np.trapezoid(waveform * np.conj(alpha_array[0][0]), t)
symbols_recovered[1] = np.trapezoid(waveform * np.conj(alpha_array[0][1]), t)
symbols_recovered[2] = np.trapezoid(waveform * np.conj(alpha_array[1][0]), t)
symbols_recovered[3] = np.trapezoid(waveform * np.conj(alpha_array[1][1]), t)
print(symbols)
print(symbols_recovered)
# Let's delay and frequency offset one of them
waveform = symbols[0] * alpha_array[0][0]
waveform_delay = np.roll(waveform, OVERSAMPLING // M * 2)
print(np.trapezoid(waveform_delay * np.conj(alpha_array[0][2]), t))
waveform_delay_doppler = np.roll(waveform * np.exp(1j * 2 * np.pi * 2 / T / N * t), OVERSAMPLING // M * 2)
print(np.trapezoid(waveform_delay_doppler * np.conj(alpha_array[2][2]), t))
triplets = [
# (gain, normalized time delay, normalized doppler shift)
# normalized means between 0 and M - 1 and 0 and N - 1
(1.0, 2, 2),
(0.0, 2, 3),
]
actual_signal = np.zeros_like(t) * 0.0j
for i in triplets:
gain, time_delay, doppler = i
actual_signal += np.roll(gain * waveform * np.exp(1j * 2 * np.pi * doppler / T / N * t), OVERSAMPLING // N * time_delay)
dd_domain_rx = np.zeros((M, N), dtype='complex')
for k in range(M):
for l in range(N):
dd_domain_rx[k][l] = np.trapezoid(actual_signal * np.conj(alpha_array[k][l]), t)
# plt.imshow(np.abs(dd_domain_rx))
# plt.show()
# We want to do something like Doppler focusing. We will just keep shifting the signal by T / M multiples and just add them all up.
assert(np.max(np.abs((np.roll(actual_signal, -32) * np.exp(-1j * 2 * np.pi * 2 / T / N * t)) - waveform)) < 1e-8)
test_nu = 1 / N / T
PHI = np.zeros_like(actual_signal) * 0.0j
for p in range(M):
PHI += np.roll(actual_signal, -p * OVERSAMPLING // M) * np.exp(-1j * 2 * np.pi * test_nu * (t + p * T))
plt.plot(t, np.abs(PHI))
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment