GNU General Public License v3.0

项目介绍

textremo/Phy_Mod_OTFS 是一个托管在 GitHub 上的开源项目,主要使用 MATLAB 编写,采用 GNU General Public License v3.0 许可证,目前获得 68 个 Star、12 次 Fork。

仓库全名
textremo/Phy_Mod_OTFS
开源许可证
GNU General Public License v3.0
Star 数
68
Fork 数
12

README 摘要

OTFS Modulation This repository is a fundamental toolbox of OTFS modulation crossing matlab and python. If you use our work, you should use the following citation to refer it: X. Qu, A. Kosasih, W. Hardjawana, V. Onasis and B. Vucetic, "Bayesian-based Symbol Detector for Orthogonal Time Frequency Space Modulation Systems," 2021 IEEE 32nd Annual International Symposium on Personal, Indoor and Mobile Radio…

完整内容见 GitHub 原始 README 或本页 。

常见问题

Phy_Mod_OTFS 用什么语言开发?

主要使用 MATLAB 编写,采用 GNU General Public License v3.0 许可证,目前有 68 个 Star。

Phy_Mod_OTFS 可以免费商用吗?

仓库标注的许可证为 GNU General Public License v3.0,商用前请先阅读仓库 LICENSE 文件确认授权范围。

如何获取 Phy_Mod_OTFS 的源码?

可以直接克隆仓库:git clone https://github.com/textremo/Phy_Mod_OTFS.git,默认分支为 main;安装与运行步骤见仓库 README。

Phy_Mod_OTFS 最近还在维护吗?

仓库最近一次更新为 4月27日,当前没有未关闭的 Issue;Star 数为 68,可作为社区活跃度的参考。

关于

This repository is a fundamental toolbox of OTFS modulation crossing multiple platforms.

描述取自 GitHub 官方 API,中文内容由 GitRead 中文社区 编辑团队整理。

简要分析

热度分
93
价值分
44
活跃状态
活跃

README

OTFS Modulation

Github PyPi MathWorks 996.icu

This repository is a fundamental toolbox of OTFS modulation crossing matlab and python. If you use our work, you should use the following citation to refer it:

X. Qu, A. Kosasih, W. Hardjawana, V. Onasis and B. Vucetic, “Bayesian-based Symbol Detector for Orthogonal Time Frequency Space Modulation Systems,” 2021 IEEE 32nd Annual International Symposium on Personal, Indoor and Mobile Radio Communications (PIMRC), Helsinki, Finland, 2021, pp. 1154-1159, doi: 10.1109/PIMRC50174.2021.9569353.

A. Kosasih, X. Qu, W. Hardjawana, C. Yue and B. Vucetic, “Bayesian Neural Network Detector for an Orthogonal Time Frequency Space Modulation,” in IEEE Wireless Communications Letters, vol. 11, no. 12, pp. 2570-2574, Dec. 2022, doi: 10.1109/LWC.2022.3209076.

H. Chang, A. Kosasih, W. Hardjawana, X. Qu and B. Vucetic, “Untrained Neural Network based Bayesian Detector for OTFS Modulation Systems,” IEEE INFOCOM 2023 - IEEE Conference on Computer Communications Workshops (INFOCOM WKSHPS), Hoboken, NJ, USA, 2023, pp. 1-6, doi: 10.1109/INFOCOMWKSHPS57453.2023.10225901.

H. Chang, G. Pang, B. Vucetic and W. Hardjawana, “Neural OTFS Receiver Without Training Requirements,” in IEEE Wireless Communications Letters, vol. 14, no. 11, pp. 3824-3828, Nov. 2025, doi: 10.1109/LWC.2025.3606969. keywords: {Symbols;Training;Receivers;Delays;Channel estimation;Doppler shift;Indexes;Complexity theory;Artificial neural networks;Vectors;Channel estimation;OTFS;symbol detection;untrained neural network},

How to install

  • Install through Matlab
    • HOME/Add-Ons/Get Add-Ons: search whatshow_toolbox and install it.
    • HOME/Add-Ons/Get Add-Ons: search whatshow_phy_mod_otfs and install it.
  • Install through pip
    pip install whatshow-toolbox
    pip install whatshow-phy-mod-otfs
    
    • import this module
      from whatshow_phy_mod_otfs import OTFS, OTFSResGrid, OTFSDetector
      

How to use

All codes are uniform in matlab and python in three class. system_model

  • OTFSResGrid: this class provides the resource grid
    • OTFSResGrid()
      @in1: 1st input, a scalar for subcarrier number or the content directly
      @in2: only if 1st input is scalar, this input is the nTimeslotNum
      @zp_len(opt): zero padding length @batch_size(opt): the batch size (only used in python)
      rg = OTFSResGrid(M, N);     // build a RG (give subcarrier number and timeslot number)
      rg = OTFSResGrid(X_DD);     // build a RG (give X_DD matrix directly)
      // user zero padding
      rg = OTFSResGrid(X_DD, "zp_len", zp_len);
      rg = OTFSResGrid(X_DD, zp_len=zp_len);
      
    • Set the pulse type
      rg.setPulse2Ideal();    // use the ideal pulse
      rg.setPulse2Recta();    // use the rectangular pulse
      
    • Set pilot type
      rg.setPilot2Embed();            // use embedded pilots
      rg.setPilot2SuperImposed();     // use superimposed pilots
      
    • Set the location of pilots (in the center by default)
      @pl_len: pilot length on the delay
      @pk_len: pilot length on the doppler
      @pl1: pilot location on the delay
      @pk1: pilot location on the doppler
      rg.pilot2center(pl_len, pk_len);            // pilots in the center of the entire OTFS frame
      rg.pilot2zp(pl_len, pk_len);                // pilots in the center of zero-padding area
      rg.setPilot2Flex(pl_len, pk_len, pl1, pk1); // pilots in user-defined area
      
    • setGuard(): set the guard range
      @in1: (1,2) negative guard on the delay (3) negative guard on the Doppler
      @in2: (1,2) positive guard on the delay (3) positive guard on the Doppler
      @in3: (1) negative guard on the Doppler
      @in4: (1) positive guard on the Doppler
      @guard_delay_full(opt): full guard on delay (if set true, ignore the number setting)
      @guard_doppl_full(opt): full guard on Doppler (if set true, ignore the number setting)
      // set guard range manually
      rg.setGuard(guard_delay_num_neg, guard_delay_num_pos, guard_doppl_num_neg, guard_doppl_num_pos);
      // full guard
      rg.setGuard(guard_delay_num_neg, guard_delay_num_pos, 'guard_doppl_full', true);
      rg.setGuard(guard_delay_num_neg, guard_delay_num_pos, guard_doppl_full=True);
      
    • map(): symbols is mandatory, pilots_pow and pilots_pow must use one if you want to use pilots. Other parameters define the length of pilots and the guards area around the pilots. If the guard area is oversize, you are suggested to use full guard on that axis so that the channel estimation result will be more accurate.
      @symbols: OTFS symbols
      @pilots(opt): a vector of your pilots (if given pilots_pow won’t be used)
      @pilots_pow(opt): pilot power to generate random pilots
    • setAreaCE(): set the channel estimation area manually. You should only call this function when you disagree with our channel estimation area.
      @ce_l_beg: CE delay beginning
      @ce_l_end: CE delay ending
      @ce_k_beg: CE Doppler beginning
      @ce_k_end: CE Doppler ending
    • demap()
      @isData(opt): whether give the data (true by default)
      @isCE(opt): whether give the channel estimation result(true by default)
      @threshold(opt): the threshold to estimate the channel
      [y, his_est, lis_est, kis_est] = rg_rx.demap("threshold", 1e-10);
      y, his_est, lis_est, kis_est = rg_rx.demap(threshold=1e-10);
      
    • clone(): clone this resource grid
    • isZP(): return zero padding length
    • isPG(): check whether use pilots & guards
    • Check whether your coordinate is in a certain area
      @pos_doppl: the position on the Doppler axis. Not given means the position is for a Doppler-delay vector
      @pos_delay: the position on the delay axis for matrix or th position on the Doppler-delay axis for the vector
      // is in pilots and guards area
      rg.isInAreaPG(k, l);
      rg.isInAreaPG(n);               // you coordinate is from a vector
      // is in zero padding area
      rg.isInAreaZP(k, l);
      rg.isInAreaZP(n);               // you coordinate is from a vector
      // is in data area
      rg.isInAreaDA(k, l);
      rg.isInAreaDA(n);               // you coordinate is from a vector
      // is in channel estimation area
      rg.isInAreaCE(k, l);
      rg.isInAreaCE(n);               // you coordinate is from a vector
      
    • getAreaPG(): get the area of pilots and guards
      [pg_num, pg_delay_beg, pg_delay_end, pg_doppl_beg, pg_doppl_end] = rg.getAreaPG();
      pg_num, pg_delay_beg, pg_delay_end, pg_doppl_beg, pg_doppl_end = rg.getAreaPG();
      
    • getAreaCE(): get the area of channel estimation
      [ce_num, ce_delay_beg, ce_delay_end, ce_doppl_beg, ce_doppl_end] = rg.getAreaCE();
      ce_num, ce_delay_beg, ce_delay_end, ce_doppl_beg, ce_doppl_end = rg.getAreaCE();
      
    • check pulse type
      rg.isPulseIdeal();  // use ideal pulse or not
      rg.isPulseRecta();  // use rectangula pulse or not
      
    • getPilotsMat(): return a DD domain matrix only containing pilots
    • setContent() @content: a 2D matrix containing pilots, guards and data (if used)
      rg.setContent(content);
      
    • getContentSize(): get content size
      [nSubcarNum, nTimeslotNum] = rg.getContentSize();
      nSubcarNum, nTimeslotNum = rg.getContentSize();
      
    • getContent(): get the content
      @isVector(opt): if true, the returned result is a vector
      rg.getContent();
      // vectorized results
      rg.getContent("isVector", true);
      rg.getContent(isVector=True);
      
    • getContentCE(): get the channel estimation area content (return a matrix)
    • getContentNoCE(): get the content except CE area (return a vector)
    • getContentZeroPG(): get the content of zero PG area (return a vector)
    • getContentZeroCE(): get the content of zero CE area (return a vector)
    • getContentDataLocsMat(): get Data locations in content (return a logical matrix)
  • OTFS: this class provides the entire process of OTFS from Tx to Rx
    • OTFS()
      @batch_size(opt): the batch size (only used in python)
    • Pulse settings: if you want to input delay-Doppler domain matrix directly into OTFS, you need to set the pulse type before modulate.
      otfs.setPulse2Ideal();  // use ideal pulses
      otfs.setPulse2Recta();  // use rectangular pulses
      
    • modulate():modulate (use fast method by default)
      @in1: an OTFS resource grid or a 2D matrix [(batch_size), Doppler, delay]
      @isFast(opt): DD domain -> TD domain (no X_TF)
      // fast modulate
      otfs.modulate(rg);
      // slow modulate
      otfs.modulate(rg, "isFast", false);
      otfs.modulate(rg, isFast=False);
      
    • setChannel(): this methods has multiple kinds of inputs.
      • set a fixed chanel (at least two paths, if you want to add one fixed path, call setChannelExtra) @in1->his: the path gains
        @in2->lis: the delays
        @in3->kis: the doppler shifts
      • set a random channel (overwritten the channel setting; use Rayleigh fading if not select channel model) @in1->p: the path number
        @in2->lmax: the maxmimal delay index
        @in3->kmax: the maximal Doppler index (can be fractional)
        @force_frac(opt): use fractional Doppler (force)
        @isAWGN(opt): use awgn
        @isRician(opt): use Rician fading
        @isSameDD(opt): use the same delay or doppler
        otfs.setChannel(p,lmax,kmax);
        // optional inputs
        otfs.setChannel(p,lmax,kmax, "force_frac", true);
        otfs.setChannel(p,lmax,kmax, force_frac=True);
        otfs.setChannel(p,lmax,kmax, "isAWGN", true);
        otfs.setChannel(p,lmax,kmax, isAWGN=True);
        otfs.setChannel(p,lmax,kmax, "isRician", true);
        otfs.setChannel(p,lmax,kmax, isRician=True);
        
    • setChannelExtra(): add a path to the channel (this does not influence other existing paths)
      @hi: the path gain (linear gain)
      @li: the delay
      @ki: the Doppler shift
    • passChannel()
      @No: linear noise power (a scalar) or a given noise vector. [1]: the same noise power for all, [(batch_size), 1]: the same noise for all data in the same batch, [n] & [batch_size, n]: manuall defined noise(if you use batched data)
      otfs.passChannel(No);
      
    • demodulate(): demodulate (use fast method by default)
      @isFast(opt): TD domain -> DD domain (no Y_TF)
      rg = otfs.demodulate(); // if the modulation uses a resource grid
      Y_DD = otfs.demodulate(); // if the modulation uses a delay-Doppler domain matrix
      
    • getChannel(): return the channel on delay Doppler domain. If not given his, lis, kis, use the current channel.
      @his: the channel gains
      @lis: the channel delays
      @kis: the channel Dopplers
      @data_only(opt): whether the channel is only for data (by default true). If you want to get the entire H_DD when using pilos and/or guards, you should manullay set it to false.
      // the channel only for data
      Hdd = otfs.getChannel("data_only", true);
      Hdd = otfs.getChannel(data_only=True);
      
    • getCSI(): get the channel state information @sort_by_gain(opt): sort axis, false by defaut
      @sort_by_delay_doppler(opt): sort axes, false by defaut
      @sort_by_doppler_delay(opt): sort axes, false by defaut
      @descend(opt): sort direction, false by defaut
      otfs.getCSI("sort_by_delay_doppler", true);
      otfs.getCSI(sort_by_delay_doppler=True);
      
    • getXTF(): get the signal in the TF domain
    • getXT(): get the signal in the time domains @fft_size(opt): the size of fft
  • OTFSDetect: this class provides dedicated OTFS detectors
    • OTFSDetector()
      @constel: the constellation (a vector)
      od = OTFSDetector(sympool);
      
    • Select a detector
      • useMPBase(): set detector types - MP Base
        @n_ite(opt): the iteration number (200 by default)
        @delta_fra(opt): the percentage for taking the values in the current iteration
        od.useMPBase();
        od.useMPBase("n_ite", 10, "delta_fra", 0.9);
        od.useMPBase(n_ite=10, delta_fra=0.9);
        
    • detect(): return the estimated symbols
      @y: the received signal from the resource grid (after demapping) or just a resource grid
      @csi_info1: (1) a vector of path gains (2) a matrix of HDD
      @csi_info2: (1) the delay indices (2) the noise power
      @csi_info3: (1) the Doppler indices
      @csi_info4: (1) the noise power
      xDD_est  = od.detect(rg_rx, his, lis, kis, No);
      xDD_est  = od.detect(rg_rx, Hdd, No);
      

Samples

Before running any sample code, please make sure you are at the root path of this repository. Also, Matlab codes require running init in the command window first to load directories.

  • Viterbo_MP_2018: this code is from Emanuele Viterbo. You can download his original code in this page.
  • Viterbo_MP_Embed: examples showing how MP detects symbols using embedded pilots.
  • WaveForm: this is to observe the waveform of OTFS.

Tests

  • ./Modular_OTFS: test OTFS class
    • case000: modular tests on each functions
    • case001: test the light mode (integer and fractional Dopplers. ideal and rectangular pulses)
  • ./Modular_OTFSDetector: test OTFSResGrid class
  • ./Modular_OTFSResGrid: test OTFSResGrid class
  • ./Whole_CE: examples showing how to estimate channel (using OTFSResourceGrid).
  • ./Whole_CE_Detect: examples showing how to estimate channel (using OTFSResourceGrid) and detect symbols.
  • ./Whole_Joint
    • case001: ideal/recta pulse + full guards + single pilot; NMSE
    • case002: ideal/recta pulse + full guards + single pilot; SER(mp base)

TODO

  • OTFS
    • getCSI(): python need to sort
    • removeNoDAChannel(): need to remove zero padding area
  • OTFSDetect
    • detectMPBase: support when batch_size is greater than 1

References

Raviteja, P., Phan, K. T., Hong, Y., & Viterbo, E. (2018). Interference cancellation and iterative detection for orthogonal time frequency space modulation. IEEE transactions on wireless communications, 17(10), 6501-6515.

Raviteja, P., Phan, K. T., & Hong, Y. (2019). Embedded pilot-aided channel estimation for OTFS in delay–Doppler channels. IEEE transactions on vehicular technology, 68(5), 4906-4917.

评论

暂无评论