MATLAB Code for OTFS (Orthogonal Time Frequency Space)
%% Clear workspace
clc; clear; close all;
%% Step 1: OTFS Parameters
N_delay = 4; % Number of delay bins (rows)
N_doppler = 4; % Number of Doppler bins (columns)
N_sym = N_delay * N_doppler;
modOrder = 4; % QPSK
SNR_dB = 20; % Noise level
%% Step 2: Generate random data symbols
data = randi([0 modOrder-1], N_sym, 1);
txSymbols = pskmod(data, modOrder, pi/4);
disp('Transmitted Delay-Doppler symbols:');
disp(reshape(txSymbols, N_delay, N_doppler));
%% Step 3: Map Delay-Doppler → Time-Frequency (ISFFT)
% ISFFT: Inverse Symplectic Finite Fourier Transform
% 1. Take IDFT along Doppler (columns)
% 2. Take DFT along Delay (rows)
ddSymbols = reshape(txSymbols, N_delay, N_doppler);
% Step 3a: IDFT along columns (Doppler)
tfGrid = ifft(ddSymbols, N_doppler, 2);
%IFFT (accross columns) along Doppler → spreads in time (Delay → Time)
%FFT (accross rows)along Delay → spreads in frequency (Delay → Frequency)
% Step 3b: DFT along rows (Delay)
tfGrid = fft(tfGrid, N_delay, 1);
disp('Time-Frequency Grid (TF domain):');
disp(tfGrid);
%% Step 4: Serialize TF grid for transmission
txSerial = tfGrid(:); % Column-wise flatten
disp('Serial transmission stream:');
disp(txSerial);
%% Step 5: Channel Model
% Flat fading for simplicity
h = (randn(size(txSerial)) + 1j*randn(size(txSerial)))/sqrt(2);
rxSerial = txSerial .* h; % Apply channel
rxSerial = awgn(rxSerial, SNR_dB, 'measured'); % Add noise
%% Step 6: Reshape back into TF grid
rxTFGrid = reshape(rxSerial, N_delay, N_doppler);
hTFGrid = reshape(h, N_delay, N_doppler); % Channel coefficients per tile
%% Step 7: Equalization in TF domain
eqTFGrid = rxTFGrid ./ hTFGrid; % Simple one-tap per TF tile
%% Step 8: Map TF → Delay-Doppler (SFFT)
% SFFT: Symplectic Fourier Transform (inverse of ISFFT)
% 1. IDFT along Delay (rows)
% 2. DFT along Doppler (columns)
rxDD = ifft(eqTFGrid, N_delay, 1); % IDFT along rows
rxDD = fft(rxDD, N_doppler, 2); % DFT along columns
%% Step 9: Flatten and demap symbols
rxSymbols = rxDD(:);
rxData = pskdemod(rxSymbols, modOrder, pi/4);
%% Step 10: Display results
disp('Recovered Delay-Doppler symbols:');
disp(reshape(rxSymbols, N_delay, N_doppler));
numErrors = sum(data ~= rxData);
fprintf('Symbol errors: %d out of %d\n', numErrors, N_sym);
%% Optional: Plot constellations
figure;
subplot(1,2,1); plot(txSymbols,'o'); title('Transmitted Symbols'); grid on; axis equal;
subplot(1,2,2); plot(rxSymbols,'o'); title('Received Symbols'); grid on; axis equal;
web('https://www.salimwireless.com/search?q=otfs%20ofdm', '-browser');Output
-0.7071 - 0.7071i -0.7071 + 0.7071i -0.7071 + 0.7071i -0.7071 + 0.7071i
-0.7071 + 0.7071i -0.7071 - 0.7071i -0.7071 - 0.7071i -0.7071 - 0.7071i
-0.7071 - 0.7071i 0.7071 + 0.7071i 0.7071 + 0.7071i -0.7071 - 0.7071i
-0.7071 - 0.7071i 0.7071 - 0.7071i -0.7071 - 0.7071i 0.7071 + 0.7071i
Time-Frequency Grid (TF domain):
-1.4142 - 0.3536i -0.3536 + 0.0000i -0.7071 - 0.3536i -0.3536 - 0.7071i
-0.7071 + 1.0607i 1.0607 - 0.0000i 0.7071 - 1.0607i 0.3536 + 0.0000i
0.0000 + 1.0607i -1.0607 - 0.7071i 0.7071 - 0.3536i 0.3536 - 1.4142i
-0.7071 - 0.3536i 0.3536 - 0.7071i -0.7071 + 0.3536i -0.3536 + 0.7071i
Serial transmission stream:
-1.4142 - 0.3536i
-0.7071 + 1.0607i
0.0000 + 1.0607i
-0.7071 - 0.3536i
-0.3536 + 0.0000i
1.0607 - 0.0000i
-1.0607 - 0.7071i
0.3536 - 0.7071i
-0.7071 - 0.3536i
0.7071 - 1.0607i
0.7071 - 0.3536i
-0.7071 + 0.3536i
-0.3536 - 0.7071i
0.3536 + 0.0000i
0.3536 - 1.4142i
-0.3536 + 0.7071i
Recovered Delay-Doppler symbols:
-0.6366 - 0.6820i -0.7347 + 0.6199i -0.7577 + 0.7180i -0.5586 + 0.8659i
-0.6824 + 0.8404i -0.6304 - 0.9573i -0.5014 - 0.4702i -0.8630 - 0.8956i
-0.7453 - 1.0323i 0.6771 + 1.0969i 0.6840 + 0.4994i -0.5991 - 0.5179i
-0.8816 - 0.4403i 0.7372 - 0.7281i -0.7871 - 0.7687i 0.5789 + 0.7468i
Symbol errors: 0 out of 16