Skip to main content

No project description provided

Project description

OTFS Modulation

PyPi MathWorks

This repository is a fundamental toolbox of OTFS modulation crossing matlab and python. This repositiory is based on papers below:

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.

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
      
    • 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)
  • 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
        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
      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);
      

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

whatshow_phy_mod_otfs-2.1.11.tar.gz (21.4 kB view hashes)

Uploaded Source

Built Distribution

whatshow_phy_mod_otfs-2.1.11-py3-none-any.whl (20.6 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page