Merge remote-tracking branch 'origin/ntn_leo_time_comp' into integration_2024_w34
This commit is contained in:
@@ -216,7 +216,10 @@ static inline uint64_t BIT_STRING_to_uint64(const BIT_STRING_t *asn) {
|
|||||||
|
|
||||||
#define asn1cSeqAdd(VaR, PtR) if (ASN_SEQUENCE_ADD(VaR,PtR)!=0) AssertFatal(false, "ASN.1 encoding error " #VaR "\n")
|
#define asn1cSeqAdd(VaR, PtR) if (ASN_SEQUENCE_ADD(VaR,PtR)!=0) AssertFatal(false, "ASN.1 encoding error " #VaR "\n")
|
||||||
#define asn1cCallocOne(VaR, VaLue) \
|
#define asn1cCallocOne(VaR, VaLue) \
|
||||||
VaR = calloc(1,sizeof(*VaR)); *VaR=VaLue
|
do { \
|
||||||
|
VaR = calloc(1,sizeof(*VaR)); \
|
||||||
|
*VaR = VaLue; \
|
||||||
|
} while (0)
|
||||||
#define asn1cCalloc(VaR, lOcPtr) \
|
#define asn1cCalloc(VaR, lOcPtr) \
|
||||||
typeof(VaR) lOcPtr = VaR = calloc(1,sizeof(*VaR))
|
typeof(VaR) lOcPtr = VaR = calloc(1,sizeof(*VaR))
|
||||||
#define asn1cSequenceAdd(VaR, TyPe, lOcPtr) \
|
#define asn1cSequenceAdd(VaR, TyPe, lOcPtr) \
|
||||||
|
|||||||
+64
-6
@@ -157,6 +157,42 @@ E.g. to perform a simple simulation of a satellite in geostationary orbit (GEO),
|
|||||||
--rfsimulator.prop_delay 238.74
|
--rfsimulator.prop_delay 238.74
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For simulation of a satellite in low earth orbit (LEO), two channel models have been added to rfsimulator:
|
||||||
|
- `SAT_LEO_TRANS`: transparent LEO satellite with gNB on ground
|
||||||
|
- `SAT_LEO_REGEN`: regenerative LEO satellite with gNB on board
|
||||||
|
|
||||||
|
Both channel models simulate the delay and Doppler for a circular orbit at 600 km height according to the Matlab function [dopplerShiftCircularOrbit](https://de.mathworks.com/help/satcom/ref/dopplershiftcircularorbit.html).
|
||||||
|
An example configuration to simulate a transparent LEO satellite with rfsimulator would be:
|
||||||
|
```
|
||||||
|
channelmod = {
|
||||||
|
max_chan=10;
|
||||||
|
modellist="modellist_rfsimu_1";
|
||||||
|
modellist_rfsimu_1 = (
|
||||||
|
{
|
||||||
|
model_name = "rfsimu_channel_enB0"
|
||||||
|
type = "SAT_LEO_TRANS";
|
||||||
|
noise_power_dB = -100;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model_name = "rfsimu_channel_ue0"
|
||||||
|
type = "SAT_LEO_TRANS";
|
||||||
|
noise_power_dB = -100;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
This configuration is also provided in the file `targets/PROJECTS/GENERIC-NR-5GC/CONF/channelmod_rfsimu_LEO_satellite.conf`.
|
||||||
|
|
||||||
|
Additionally, rfsimulator has to be configured to apply the channel model.
|
||||||
|
This can be done by either providing this line in the conf file in section `rfsimulator`:
|
||||||
|
```
|
||||||
|
options = ("chanmod");
|
||||||
|
```
|
||||||
|
Or by providing this the the command line parameters:
|
||||||
|
```
|
||||||
|
--rfsimulator.options chanmod
|
||||||
|
```
|
||||||
|
|
||||||
### gNB
|
### gNB
|
||||||
|
|
||||||
The main parameter to cope with the large NTN propagation delay is the cellSpecificKoffset.
|
The main parameter to cope with the large NTN propagation delay is the cellSpecificKoffset.
|
||||||
@@ -166,11 +202,12 @@ The unit of the field Koffset is number of slots for a given subcarrier spacing
|
|||||||
This parameter can be provided to the gNB in the conf file as `cellSpecificKoffset_r17` in the section `servingCellConfigCommon`.
|
This parameter can be provided to the gNB in the conf file as `cellSpecificKoffset_r17` in the section `servingCellConfigCommon`.
|
||||||
```
|
```
|
||||||
...
|
...
|
||||||
cellSpecificKoffset_r17 = 478;
|
cellSpecificKoffset_r17 = 478; # GEO satellite
|
||||||
|
# cellSpecificKoffset_r17 = 40; # LEO satellite
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
Besides this, some timers, e.g. `sr_ProhibitTimer_v1700`, `t300`, `t301` and `t319`, in the conf file section `gNBs.[0].TIMERS` might need to be extended.
|
Besides this, some timers, e.g. `sr_ProhibitTimer_v1700`, `t300`, `t301` and `t319`, in the conf file section `gNBs.[0].TIMERS` might need to be extended for GEO satellites.
|
||||||
```
|
```
|
||||||
...
|
...
|
||||||
TIMERS :
|
TIMERS :
|
||||||
@@ -185,7 +222,7 @@ Besides this, some timers, e.g. `sr_ProhibitTimer_v1700`, `t300`, `t301` and `t3
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
To improve the achievable UL and DL throughput in conditions with large RTT, there is a feature defined in REL17 to disable HARQ feedback.
|
To improve the achievable UL and DL throughput in conditions with large RTT (esp. GEO satellites), there is a feature defined in REL17 to disable HARQ feedback.
|
||||||
This allows to reuse HARQ processes immediately, but it breaks compatibility with UEs not supporting this REL17 feature.
|
This allows to reuse HARQ processes immediately, but it breaks compatibility with UEs not supporting this REL17 feature.
|
||||||
To enable this feature, the `disable_harq` flag has to be added to the gNB conf file in the section `gNBs.[0]`
|
To enable this feature, the `disable_harq` flag has to be added to the gNB conf file in the section `gNBs.[0]`
|
||||||
```
|
```
|
||||||
@@ -199,7 +236,7 @@ To enable this feature, the `disable_harq` flag has to be added to the gNB conf
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
So with these modifications to the file `targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf` an example gNB command for FDD, 5 MHz BW, 15 kHz SCS, GEO satellite 5G NR NTN is this:
|
So with these modifications to the file `targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf` an example gNB command for FDD, 5 MHz BW, 15 kHz SCS, transparent GEO satellite 5G NR NTN is this:
|
||||||
```
|
```
|
||||||
cd cmake_targets
|
cd cmake_targets
|
||||||
sudo ./ran_build/build/nr-softmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf --sa --rfsim --rfsimulator.prop_delay 238.74
|
sudo ./ran_build/build/nr-softmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf --sa --rfsim --rfsimulator.prop_delay 238.74
|
||||||
@@ -213,18 +250,39 @@ To configure NTN gNB with 32 HARQ processes in downlink and uplink, add these se
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To simulate a LEO satellite channel model with rfsimulator in UL (DL is simulated at the UE side) either the `channelmod` section as shown before has to be added to the gNB conf file, or a channelmod conf file has to be included like this:
|
||||||
|
```
|
||||||
|
@include "channelmod_rfsimu_LEO_satellite.conf"
|
||||||
|
```
|
||||||
|
|
||||||
|
So with these modifications to the file `targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf` an example gNB command for FDD, 5 MHz BW, 15 kHz SCS, trasparent LEO satellite 5G NR NTN is this:
|
||||||
|
```
|
||||||
|
cd cmake_targets
|
||||||
|
sudo ./ran_build/build/nr-softmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf --sa --rfsim --rfsimulator.prop_delay 20
|
||||||
|
```
|
||||||
|
|
||||||
### NR UE
|
### NR UE
|
||||||
|
|
||||||
At UE side, there are two main parameters to cope with the large NTN propagation delay, cellSpecificKoffset and ta-Common.
|
At UE side, there are two main parameters to cope with the large NTN propagation delay, cellSpecificKoffset and ta-Common.
|
||||||
`cellSpecificKoffset` is the same as for gNB and can be provided to the UE via command line parameter `--ntn-koffset`.
|
`cellSpecificKoffset` is the same as for gNB and can be provided to the UE via command line parameter `--ntn-koffset`.
|
||||||
`ta-Common` is a common timong advance and can be provided to the UE via command line parameter `--ntn-ta-common` in milliseconds.
|
`ta-Common` is a common timing advance and can be provided to the UE via command line parameter `--ntn-ta-common` in milliseconds.
|
||||||
|
|
||||||
So an example NR UE command for FDD, 5MHz BW, 15 kHz SCS, GEO satellite 5G NR NTN is this:
|
So an example NR UE command for FDD, 5MHz BW, 15 kHz SCS, transparent GEO satellite 5G NR NTN is this:
|
||||||
```
|
```
|
||||||
cd cmake_targets
|
cd cmake_targets
|
||||||
sudo ./ran_build/build/nr-uesoftmodem --band 66 -C 2152680000 --CO -400000000 -r 25 --numerology 0 --ssb 48 --sa --rfsim --rfsimulator.prop_delay 238.74 --ntn-koffset 478 --ntn-ta-common 477.48
|
sudo ./ran_build/build/nr-uesoftmodem --band 66 -C 2152680000 --CO -400000000 -r 25 --numerology 0 --ssb 48 --sa --rfsim --rfsimulator.prop_delay 238.74 --ntn-koffset 478 --ntn-ta-common 477.48
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For LEO satellites a third parameter specifying the NTN propagation delay drift has ben added, ta-CommonDrift.
|
||||||
|
`ta-CommonDrift` provides the drift rate of the common timing advance and can be provided to the UE via command line parameter `--ntn-ta-commondrift` in microseconds per second.
|
||||||
|
Also, to perform an autonomous TA update based on the DL drift, the boolean parameter `--autonomous-ta` should be added in case of a LEO satellite scenario.
|
||||||
|
|
||||||
|
So an example NR UE command for FDD, 5MHz BW, 15 kHz SCS, transparent LEO satellite 5G NR NTN is this:
|
||||||
|
```
|
||||||
|
cd cmake_targets
|
||||||
|
sudo ./ran_build/build/nr-uesoftmodem --band 66 -C 2152680000 --CO -400000000 -r 25 --numerology 0 --ssb 48 --sa --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/channelmod_rfsimu_LEO_satellite.conf --ntn-koffset 40 --ntn-ta-common 37.74 --ntn-ta-commondrift -50 --autonomous-ta
|
||||||
|
```
|
||||||
|
|
||||||
# Specific OAI modes
|
# Specific OAI modes
|
||||||
|
|
||||||
## phy-test setup with OAI UE
|
## phy-test setup with OAI UE
|
||||||
|
|||||||
@@ -98,7 +98,6 @@
|
|||||||
#define CONFIG_HLP_TELN "Start embedded telnet server \n"
|
#define CONFIG_HLP_TELN "Start embedded telnet server \n"
|
||||||
#define CONFIG_HLP_SNR "Set average SNR in dB (for --siml1 option)\n"
|
#define CONFIG_HLP_SNR "Set average SNR in dB (for --siml1 option)\n"
|
||||||
#define CONFIG_HLP_NOS1 "Disable s1 interface\n"
|
#define CONFIG_HLP_NOS1 "Disable s1 interface\n"
|
||||||
#define CONFIG_HLP_AGC "Rx Gain control used for UE"
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
/* command line parameters for LOG utility */
|
/* command line parameters for LOG utility */
|
||||||
|
|||||||
+12
-7
@@ -597,7 +597,7 @@ void processSlotTX(void *arg)
|
|||||||
|
|
||||||
static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc, int *tx_wait_for_dlsch, nr_phy_data_t *phy_data)
|
static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc, int *tx_wait_for_dlsch, nr_phy_data_t *phy_data)
|
||||||
{
|
{
|
||||||
int sampleShift = 0;
|
int sampleShift = INT_MAX;
|
||||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||||
if (UE->sl_mode == 2)
|
if (UE->sl_mode == 2)
|
||||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||||
@@ -886,7 +886,12 @@ void *UE_thread(void *arg)
|
|||||||
stream_status = STREAM_STATUS_SYNCING;
|
stream_status = STREAM_STATUS_SYNCING;
|
||||||
syncInFrame(UE, &sync_timestamp, intialSyncOffset);
|
syncInFrame(UE, &sync_timestamp, intialSyncOffset);
|
||||||
openair0_write_reorder_clear_context(&UE->rfdevice);
|
openair0_write_reorder_clear_context(&UE->rfdevice);
|
||||||
shiftForNextFrame = 0; // will be used to track clock drift
|
UE->max_pos_acc = get_nrUE_params()->ntn_ta_commondrift * 1e-6 * fp->samples_per_frame / get_nrUE_params()->time_sync_I; // ntn_ta_commondrift is in µs/s, max_pos_acc * time_sync_I is in samples/frame
|
||||||
|
shiftForNextFrame = -(UE->init_sync_frame + trashed_frames + 2) * UE->max_pos_acc * get_nrUE_params()->time_sync_I; // compensate for the time drift that happened during initial sync
|
||||||
|
LOG_D(PHY, "max_pos_acc = %d, shiftForNextFrame = %d\n", UE->max_pos_acc, shiftForNextFrame);
|
||||||
|
// TODO: remove this autonomous TA and use up-to-date values of ta-Common, ta-CommonDrift and ta-CommonDriftVariant from received SIB19 instead
|
||||||
|
if (get_nrUE_params()->autonomous_ta)
|
||||||
|
UE->timing_advance -= 2 * shiftForNextFrame;
|
||||||
// read in first symbol
|
// read in first symbol
|
||||||
AssertFatal(fp->ofdm_symbol_size + fp->nb_prefix_samples0
|
AssertFatal(fp->ofdm_symbol_size + fp->nb_prefix_samples0
|
||||||
== UE->rfdevice.trx_read_func(&UE->rfdevice,
|
== UE->rfdevice.trx_read_func(&UE->rfdevice,
|
||||||
@@ -947,7 +952,10 @@ void *UE_thread(void *arg)
|
|||||||
if (slot_nr == nb_slot_frame - 1) {
|
if (slot_nr == nb_slot_frame - 1) {
|
||||||
// we shift of half of measured drift, at each beginning of frame for both rx and tx
|
// we shift of half of measured drift, at each beginning of frame for both rx and tx
|
||||||
iq_shift_to_apply = shiftForNextFrame;
|
iq_shift_to_apply = shiftForNextFrame;
|
||||||
shiftForNextFrame = 0; // We will get a new measured offset if we decode PBCH
|
// TODO: remove this autonomous TA and use up-to-date values of ta-Common, ta-CommonDrift and ta-CommonDriftVariant from received SIB19 instead
|
||||||
|
if (get_nrUE_params()->autonomous_ta)
|
||||||
|
UE->timing_advance -= 2 * shiftForNextFrame;
|
||||||
|
shiftForNextFrame = -round(UE->max_pos_acc * get_nrUE_params()->time_sync_I);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply;
|
const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply;
|
||||||
@@ -991,10 +999,7 @@ void *UE_thread(void *arg)
|
|||||||
nr_rxtx_thread_data_t *curMsgRx = (nr_rxtx_thread_data_t *)NotifiedFifoData(newRx);
|
nr_rxtx_thread_data_t *curMsgRx = (nr_rxtx_thread_data_t *)NotifiedFifoData(newRx);
|
||||||
*curMsgRx = (nr_rxtx_thread_data_t){.proc = curMsg.proc, .UE = UE};
|
*curMsgRx = (nr_rxtx_thread_data_t){.proc = curMsg.proc, .UE = UE};
|
||||||
int ret = UE_dl_preprocessing(UE, &curMsgRx->proc, tx_wait_for_dlsch, &curMsgRx->phy_data);
|
int ret = UE_dl_preprocessing(UE, &curMsgRx->proc, tx_wait_for_dlsch, &curMsgRx->phy_data);
|
||||||
if (ret)
|
if (ret != INT_MAX)
|
||||||
// if ret is 0, no rx_offset has been computed,
|
|
||||||
// or the computed value is 0 = no offset to do
|
|
||||||
// we store it to apply the drift compensation at beginning of next frame
|
|
||||||
shiftForNextFrame = ret;
|
shiftForNextFrame = ret;
|
||||||
pushTpool(&(get_nrUE_params()->Tpool), newRx);
|
pushTpool(&(get_nrUE_params()->Tpool), newRx);
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,13 @@
|
|||||||
#define CONFIG_HLP_DLSCH_PARA "number of threads for dlsch processing 0 for no parallelization\n"
|
#define CONFIG_HLP_DLSCH_PARA "number of threads for dlsch processing 0 for no parallelization\n"
|
||||||
#define CONFIG_HLP_OFFSET_DIV "Divisor for computing OFDM symbol offset in Rx chain (num samples in CP/<the value>). Default value is 8. To set the sample offset to 0, set this value ~ 10e6\n"
|
#define CONFIG_HLP_OFFSET_DIV "Divisor for computing OFDM symbol offset in Rx chain (num samples in CP/<the value>). Default value is 8. To set the sample offset to 0, set this value ~ 10e6\n"
|
||||||
#define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n"
|
#define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n"
|
||||||
|
#define CONFIG_HLP_TIME_SYNC_P "coefficient for Proportional part of time sync PI controller\n"
|
||||||
|
#define CONFIG_HLP_TIME_SYNC_I "coefficient for Integrating part of time sync PI controller\n"
|
||||||
#define CONFIG_HLP_NTN_KOFFSET "NTN cellSpecificKoffset-r17 (number of slots for a given subcarrier spacing of 15 kHz)\n"
|
#define CONFIG_HLP_NTN_KOFFSET "NTN cellSpecificKoffset-r17 (number of slots for a given subcarrier spacing of 15 kHz)\n"
|
||||||
#define CONFIG_HLP_NTN_TA_COMMON "NTN ta-Common, but given in ms\n"
|
#define CONFIG_HLP_NTN_TA_COMMON "NTN ta-Common, but given in ms\n"
|
||||||
|
#define CONFIG_HLP_NTN_TA_COMMONDRIFT "NTN ta-CommonDrift, but given in µs/s\n"
|
||||||
|
#define CONFIG_HLP_AUTONOMOUS_TA "Autonomously update TA based on DL drift (useful if main contribution to DL drift is movement, e.g. LEO satellite)\n"
|
||||||
|
#define CONFIG_HLP_AGC "Rx Gain control used for UE\n"
|
||||||
|
|
||||||
/***************************************************************************************************************************************/
|
/***************************************************************************************************************************************/
|
||||||
/* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument
|
/* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument
|
||||||
@@ -59,9 +64,13 @@
|
|||||||
{"ue-timing-correction-disable", CONFIG_HLP_DISABLETIMECORR, PARAMFLAG_BOOL, .iptr=&(nrUE_params.no_timing_correction), .defintval=0, TYPE_INT, 0}, \
|
{"ue-timing-correction-disable", CONFIG_HLP_DISABLETIMECORR, PARAMFLAG_BOOL, .iptr=&(nrUE_params.no_timing_correction), .defintval=0, TYPE_INT, 0}, \
|
||||||
{"SLC", CONFIG_HLP_SLF, 0, .u64ptr=&(sidelink_frequency[0][0]), .defuintval=2600000000,TYPE_UINT64,0}, \
|
{"SLC", CONFIG_HLP_SLF, 0, .u64ptr=&(sidelink_frequency[0][0]), .defuintval=2600000000,TYPE_UINT64,0}, \
|
||||||
{"num-ues", NULL, 0, .iptr=&(NB_UE_INST), .defuintval=1, TYPE_INT, 0}, \
|
{"num-ues", NULL, 0, .iptr=&(NB_UE_INST), .defuintval=1, TYPE_INT, 0}, \
|
||||||
|
{"time-sync-P", CONFIG_HLP_TIME_SYNC_P, 0, .dblptr=&(nrUE_params.time_sync_P), .defdblval=0.5, TYPE_DOUBLE, 0}, \
|
||||||
|
{"time-sync-I", CONFIG_HLP_TIME_SYNC_I, 0, .dblptr=&(nrUE_params.time_sync_I), .defdblval=0.2, TYPE_DOUBLE, 0}, \
|
||||||
{"ntn-koffset", CONFIG_HLP_NTN_KOFFSET, 0, .uptr=&(nrUE_params.ntn_koffset), .defuintval=0, TYPE_UINT, 0}, \
|
{"ntn-koffset", CONFIG_HLP_NTN_KOFFSET, 0, .uptr=&(nrUE_params.ntn_koffset), .defuintval=0, TYPE_UINT, 0}, \
|
||||||
{"ntn-ta-common", CONFIG_HLP_NTN_TA_COMMON, 0, .dblptr=&(nrUE_params.ntn_ta_common), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
{"ntn-ta-common", CONFIG_HLP_NTN_TA_COMMON, 0, .dblptr=&(nrUE_params.ntn_ta_common), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||||
{"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \
|
{"ntn-ta-commondrift", CONFIG_HLP_NTN_TA_COMMONDRIFT, 0, .dblptr=&(nrUE_params.ntn_ta_commondrift), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||||
|
{"autonomous-ta", CONFIG_HLP_AUTONOMOUS_TA, PARAMFLAG_BOOL, .iptr=&(nrUE_params.autonomous_ta), .defintval=0, TYPE_INT, 0}, \
|
||||||
|
{"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -82,8 +91,12 @@ typedef struct {
|
|||||||
int N_RB_DL;
|
int N_RB_DL;
|
||||||
int ssb_start_subcarrier;
|
int ssb_start_subcarrier;
|
||||||
int ldpc_offload_flag;
|
int ldpc_offload_flag;
|
||||||
|
double time_sync_P;
|
||||||
|
double time_sync_I;
|
||||||
unsigned int ntn_koffset;
|
unsigned int ntn_koffset;
|
||||||
double ntn_ta_common;
|
double ntn_ta_common;
|
||||||
|
double ntn_ta_commondrift;
|
||||||
|
int autonomous_ta;
|
||||||
int agc;
|
int agc;
|
||||||
char *usrp_args;
|
char *usrp_args;
|
||||||
char *tx_subdev;
|
char *tx_subdev;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
||||||
#include "PHY/impl_defs_top.h"
|
#include "PHY/impl_defs_top.h"
|
||||||
|
|
||||||
#include "executables/softmodem-common.h"
|
#include "executables/nr-uesoftmodem.h"
|
||||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||||
|
|
||||||
//#define DEBUG_PHY
|
//#define DEBUG_PHY
|
||||||
@@ -43,12 +43,9 @@ int nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
|
|||||||
short coef)
|
short coef)
|
||||||
{
|
{
|
||||||
int max_val = 0, max_pos = 0;
|
int max_val = 0, max_pos = 0;
|
||||||
uint8_t sync_offset = 0;
|
|
||||||
|
|
||||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_IN);
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_IN);
|
||||||
|
|
||||||
short ncoef = 32767 - coef;
|
|
||||||
|
|
||||||
// search for maximum position within the cyclic prefix
|
// search for maximum position within the cyclic prefix
|
||||||
for (int i = -frame_parms->nb_prefix_samples/2; i < frame_parms->nb_prefix_samples/2; i++) {
|
for (int i = -frame_parms->nb_prefix_samples/2; i < frame_parms->nb_prefix_samples/2; i++) {
|
||||||
int temp = 0;
|
int temp = 0;
|
||||||
@@ -67,32 +64,37 @@ int nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filter position to reduce jitter
|
// filter position to reduce jitter
|
||||||
ue->max_pos_avg = ((ue->max_pos_avg * coef) >> 15) + (max_pos * ncoef);
|
const int ncoef = 32767 - coef;
|
||||||
|
ue->max_pos_iir = ((ue->max_pos_iir * coef) >> 15) + (max_pos * ncoef);
|
||||||
int diff = ue->max_pos_avg >> 15;
|
const int diff = (ue->max_pos_iir + 16384) >> 15;
|
||||||
|
|
||||||
|
// FIXME: Do we really need this hysteresis for FR2?
|
||||||
|
int sampleShift = diff;
|
||||||
if (frame_parms->freq_range == FR2)
|
if (frame_parms->freq_range == FR2)
|
||||||
sync_offset = 2;
|
if (abs(diff) <= 2)
|
||||||
else
|
sampleShift = 0;
|
||||||
sync_offset = 0;
|
|
||||||
|
|
||||||
int sampleShift = 0;
|
// PI controller
|
||||||
if (abs(diff) > (NR_SYNCH_HYST + sync_offset))
|
const double PID_P = get_nrUE_params()->time_sync_P;
|
||||||
sampleShift = diff;
|
const double PID_I = get_nrUE_params()->time_sync_I;
|
||||||
|
int sample_shift = -round(sampleShift * PID_P + ue->max_pos_acc * PID_I);
|
||||||
const int sample_shift = -(sampleShift / 2);
|
|
||||||
// reset IIR filter for next offset calculation
|
|
||||||
ue->max_pos_avg += sample_shift * 32768;
|
|
||||||
|
|
||||||
LOG_D(PHY,
|
LOG_D(PHY,
|
||||||
"Slot %d: diff = %i, rx_offset (final) = %i : max_pos = %d, max_pos filtered = %ld, max_power = %d\n",
|
"Frame %d, Slot %d: max_pos = %d, max_pos filtered = %f, diff = %i, sampleShift = %i, max_pos_acc = %d, sample_shift (final) = %d, max_power = %d\n",
|
||||||
|
frame,
|
||||||
slot,
|
slot,
|
||||||
|
max_pos,
|
||||||
|
ue->max_pos_iir / 32768.0,
|
||||||
diff,
|
diff,
|
||||||
sampleShift,
|
sampleShift,
|
||||||
max_pos,
|
ue->max_pos_acc,
|
||||||
ue->max_pos_avg,
|
sample_shift,
|
||||||
max_val);
|
max_val);
|
||||||
|
|
||||||
|
// reset IIR filter for next offset calculation
|
||||||
|
ue->max_pos_iir += -round(sampleShift * PID_P) * 32768;
|
||||||
|
ue->max_pos_acc += max_pos;
|
||||||
|
|
||||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_OUT);
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_OUT);
|
||||||
return sample_shift;
|
return sample_shift;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,6 @@
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!\brief Timing drift hysterisis in samples*/
|
|
||||||
#define NR_SYNCH_HYST 1
|
|
||||||
|
|
||||||
/* A function to perform the channel estimation of DL PRS signal */
|
/* A function to perform the channel estimation of DL PRS signal */
|
||||||
int nr_prs_channel_estimation(uint8_t gNB_id,
|
int nr_prs_channel_estimation(uint8_t gNB_id,
|
||||||
uint8_t rsc_id,
|
uint8_t rsc_id,
|
||||||
|
|||||||
@@ -456,7 +456,8 @@ typedef struct PHY_VARS_NR_UE_s {
|
|||||||
/// temporary offset during cell search prior to MIB decoding
|
/// temporary offset during cell search prior to MIB decoding
|
||||||
int ssb_offset;
|
int ssb_offset;
|
||||||
uint16_t symbol_offset; /// offset in terms of symbols for detected ssb in sync
|
uint16_t symbol_offset; /// offset in terms of symbols for detected ssb in sync
|
||||||
int64_t max_pos_avg; /// Timing offset IIR filter
|
int64_t max_pos_iir; /// Timing offset IIR filter
|
||||||
|
int max_pos_acc; /// Timing offset accumuluated error for PI filter
|
||||||
|
|
||||||
/// Timing Advance updates variables
|
/// Timing Advance updates variables
|
||||||
/// Timing advance update computed from the TA command signalled from gNB
|
/// Timing advance update computed from the TA command signalled from gNB
|
||||||
|
|||||||
@@ -877,7 +877,7 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
|
|||||||
fapi_nr_config_request_t *cfg = &ue->nrUE_config;
|
fapi_nr_config_request_t *cfg = &ue->nrUE_config;
|
||||||
NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
|
NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
|
||||||
NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config;
|
NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config;
|
||||||
int sampleShift = 0;
|
int sampleShift = INT_MAX;
|
||||||
nr_ue_dlsch_init(phy_data->dlsch, NR_MAX_NB_LAYERS>4 ? 2:1, ue->max_ldpc_iterations);
|
nr_ue_dlsch_init(phy_data->dlsch, NR_MAX_NB_LAYERS>4 ? 2:1, ue->max_ldpc_iterations);
|
||||||
|
|
||||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN);
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN);
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr
|
|||||||
int nr_slot_rx = proc->nr_slot_rx;
|
int nr_slot_rx = proc->nr_slot_rx;
|
||||||
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
|
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
|
||||||
NR_DL_FRAME_PARMS *fp = &sl_phy_params->sl_frame_params;
|
NR_DL_FRAME_PARMS *fp = &sl_phy_params->sl_frame_params;
|
||||||
int sampleShift = 0;
|
int sampleShift = INT_MAX;
|
||||||
|
|
||||||
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX_SL, VCD_FUNCTION_IN);
|
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX_SL, VCD_FUNCTION_IN);
|
||||||
start_meas(&sl_phy_params->phy_proc_sl_rx);
|
start_meas(&sl_phy_params->phy_proc_sl_rx);
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ void fill_channel_desc(channel_desc_t *chan_desc,
|
|||||||
chan_desc->first_run = 1;
|
chan_desc->first_run = 1;
|
||||||
chan_desc->ip = 0.0;
|
chan_desc->ip = 0.0;
|
||||||
chan_desc->max_Doppler = max_Doppler;
|
chan_desc->max_Doppler = max_Doppler;
|
||||||
|
chan_desc->Doppler_phase_cur = calloc(nb_rx, sizeof(double));
|
||||||
chan_desc->ch = calloc(nb_tx*nb_rx, sizeof(struct complexd *));
|
chan_desc->ch = calloc(nb_tx*nb_rx, sizeof(struct complexd *));
|
||||||
chan_desc->chF = calloc(nb_tx*nb_rx, sizeof(struct complexd *));
|
chan_desc->chF = calloc(nb_tx*nb_rx, sizeof(struct complexd *));
|
||||||
chan_desc->a = calloc(nb_taps, sizeof(struct complexd *));
|
chan_desc->a = calloc(nb_taps, sizeof(struct complexd *));
|
||||||
@@ -1653,6 +1654,37 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
|||||||
0);
|
0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SAT_LEO_TRANS:
|
||||||
|
case SAT_LEO_REGEN:
|
||||||
|
nb_taps = 1;
|
||||||
|
Td = 0;
|
||||||
|
channel_length = 1;
|
||||||
|
ricean_factor = 0.0;
|
||||||
|
aoa = 0.0;
|
||||||
|
maxDoppler = 0;
|
||||||
|
chan_desc->sat_height = 600e3;
|
||||||
|
chan_desc->enable_dynamic_delay = true;
|
||||||
|
chan_desc->enable_dynamic_Doppler = false; // TODO: requires UE to support continuous Doppler estimation, compensation and pre-compensation
|
||||||
|
fill_channel_desc(chan_desc,nb_tx,
|
||||||
|
nb_rx,
|
||||||
|
nb_taps,
|
||||||
|
channel_length,
|
||||||
|
default_amp_lin,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
Td,
|
||||||
|
sampling_rate,
|
||||||
|
channel_bandwidth,
|
||||||
|
ricean_factor,
|
||||||
|
aoa,
|
||||||
|
forgetting_factor,
|
||||||
|
maxDoppler,
|
||||||
|
channel_offset,
|
||||||
|
path_loss_dB,
|
||||||
|
0);
|
||||||
|
printf("%s: satellite orbit height %f km\n", map_int_to_str(channelmod_names, channel_model), chan_desc->sat_height / 1000);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG_W(OCM,"channel model not yet supported\n");
|
LOG_W(OCM,"channel model not yet supported\n");
|
||||||
free(chan_desc);
|
free(chan_desc);
|
||||||
@@ -1711,6 +1743,7 @@ void free_channel_desc_scm(channel_desc_t *ch) {
|
|||||||
free(ch->R_sqrt[i]);
|
free(ch->R_sqrt[i]);
|
||||||
|
|
||||||
free(ch->R_sqrt);
|
free(ch->R_sqrt);
|
||||||
|
free(ch->Doppler_phase_cur);
|
||||||
free(ch->ch);
|
free(ch->ch);
|
||||||
free(ch->chF);
|
free(ch->chF);
|
||||||
free(ch->a);
|
free(ch->a);
|
||||||
@@ -1743,9 +1776,9 @@ int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) {
|
|||||||
struct complexd phase, alpha, beta;
|
struct complexd phase, alpha, beta;
|
||||||
start_meas(&desc->random_channel);
|
start_meas(&desc->random_channel);
|
||||||
|
|
||||||
// For AWGN channel, the received signal (Srx) is equal to transmitted signal (Stx) plus noise (N), i.e., Srx = Stx + N,
|
// For AWGN and SAT_LEO_* channels, the received signal (Srx) is equal to transmitted signal (Stx) plus noise (N), i.e., Srx = Stx + N,
|
||||||
// therefore, the channel matrix is the identity matrix.
|
// therefore, the channel matrix is the identity matrix.
|
||||||
if (desc->modelid == AWGN) {
|
if (desc->modelid == AWGN || desc->modelid == SAT_LEO_TRANS || desc->modelid == SAT_LEO_REGEN) {
|
||||||
for (aarx=0; aarx<desc->nb_rx; aarx++) {
|
for (aarx=0; aarx<desc->nb_rx; aarx++) {
|
||||||
for (aatx = 0; aatx < desc->nb_tx; aatx++) {
|
for (aatx = 0; aatx < desc->nb_tx; aatx++) {
|
||||||
desc->ch[aarx+(aatx*desc->nb_rx)][0].r = aarx%desc->nb_tx == aatx ? 1.0 : 0.0;
|
desc->ch[aarx+(aatx*desc->nb_rx)][0].r = aarx%desc->nb_tx == aatx ? 1.0 : 0.0;
|
||||||
@@ -2071,6 +2104,8 @@ static void display_channelmodel(channel_desc_t *cd,int debug, telnet_printfunc_
|
|||||||
cd->forgetting_factor);
|
cd->forgetting_factor);
|
||||||
prnt("Initial phase: %lf nb_path: %i \n",
|
prnt("Initial phase: %lf nb_path: %i \n",
|
||||||
cd->ip, cd->nb_paths);
|
cd->ip, cd->nb_paths);
|
||||||
|
if (cd->modelid == SAT_LEO_TRANS || cd->modelid == SAT_LEO_REGEN)
|
||||||
|
prnt("satellite orbit height: %f\n", cd->sat_height);
|
||||||
|
|
||||||
for (int i=0; i<cd->nb_taps ; i++) {
|
for (int i=0; i<cd->nb_taps ; i++) {
|
||||||
prnt("taps: %i lin. ampli. : %lf delay: %lf \n",i,cd->amps[i], cd->delays[i]);
|
prnt("taps: %i lin. ampli. : %lf delay: %lf \n",i,cd->amps[i], cd->delays[i]);
|
||||||
@@ -2281,7 +2316,7 @@ void init_channelmod(void) {
|
|||||||
} /* init_channelmod */
|
} /* init_channelmod */
|
||||||
|
|
||||||
|
|
||||||
int load_channellist(uint8_t nb_tx, uint8_t nb_rx, double sampling_rate, double channel_bandwidth) {
|
int load_channellist(uint8_t nb_tx, uint8_t nb_rx, double sampling_rate, uint64_t center_freq, double channel_bandwidth) {
|
||||||
paramdef_t achannel_params[] = CHANNELMOD_MODEL_PARAMS_DESC;
|
paramdef_t achannel_params[] = CHANNELMOD_MODEL_PARAMS_DESC;
|
||||||
paramlist_def_t channel_list;
|
paramlist_def_t channel_list;
|
||||||
memset(&channel_list,0,sizeof(paramlist_def_t));
|
memset(&channel_list,0,sizeof(paramlist_def_t));
|
||||||
@@ -2314,7 +2349,7 @@ int load_channellist(uint8_t nb_tx, uint8_t nb_rx, double sampling_rate, double
|
|||||||
nb_rx,
|
nb_rx,
|
||||||
modid,
|
modid,
|
||||||
sampling_rate,
|
sampling_rate,
|
||||||
0,
|
center_freq,
|
||||||
channel_bandwidth,
|
channel_bandwidth,
|
||||||
*(channel_list.paramarray[i][pindex_DT].dblptr),
|
*(channel_list.paramarray[i][pindex_DT].dblptr),
|
||||||
0.0,
|
0.0,
|
||||||
|
|||||||
@@ -126,6 +126,18 @@ typedef struct {
|
|||||||
char *model_name;
|
char *model_name;
|
||||||
/// flags to properly trigger memory free
|
/// flags to properly trigger memory free
|
||||||
unsigned int free_flags;
|
unsigned int free_flags;
|
||||||
|
/// time stamp when the time varying channel emulation starts (when client connected)
|
||||||
|
uint64_t start_TS;
|
||||||
|
/// height of LEO satellite
|
||||||
|
float sat_height;
|
||||||
|
/// flag to enable dynamic delay simulation for LEO satellite
|
||||||
|
bool enable_dynamic_delay;
|
||||||
|
/// flag to enable dynamic Doppler simulation for LEO satellite
|
||||||
|
bool enable_dynamic_Doppler;
|
||||||
|
/// Doppler phase increment (might vary over time, e.g. for LEO satellite)
|
||||||
|
float Doppler_phase_inc;
|
||||||
|
/// current Doppler phase of each RX antenna (for continuous phase from one block to the next)
|
||||||
|
float *Doppler_phase_cur;
|
||||||
} channel_desc_t;
|
} channel_desc_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -218,6 +230,8 @@ typedef enum {
|
|||||||
EPA_low,
|
EPA_low,
|
||||||
EPA_medium,
|
EPA_medium,
|
||||||
EPA_high,
|
EPA_high,
|
||||||
|
SAT_LEO_TRANS,
|
||||||
|
SAT_LEO_REGEN,
|
||||||
} SCM_t;
|
} SCM_t;
|
||||||
#define CHANNELMOD_MAP_INIT \
|
#define CHANNELMOD_MAP_INIT \
|
||||||
{"custom",custom},\
|
{"custom",custom},\
|
||||||
@@ -253,6 +267,8 @@ typedef enum {
|
|||||||
{"EPA_low",EPA_low},\
|
{"EPA_low",EPA_low},\
|
||||||
{"EPA_medium",EPA_medium},\
|
{"EPA_medium",EPA_medium},\
|
||||||
{"EPA_high",EPA_high},\
|
{"EPA_high",EPA_high},\
|
||||||
|
{"SAT_LEO_TRANS",SAT_LEO_TRANS},\
|
||||||
|
{"SAT_LEO_REGEN",SAT_LEO_REGEN},\
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
|
|
||||||
#define CONFIG_HLP_SNR "Set average SNR in dB (for --siml1 option)\n"
|
#define CONFIG_HLP_SNR "Set average SNR in dB (for --siml1 option)\n"
|
||||||
@@ -543,7 +559,7 @@ int modelid_fromstrtype(char *modeltype);
|
|||||||
double channelmod_get_snr_dB(void);
|
double channelmod_get_snr_dB(void);
|
||||||
double channelmod_get_sinr_dB(void);
|
double channelmod_get_sinr_dB(void);
|
||||||
void init_channelmod(void) ;
|
void init_channelmod(void) ;
|
||||||
int load_channellist(uint8_t nb_tx, uint8_t nb_rx, double sampling_rate, double channel_bandwidth) ;
|
int load_channellist(uint8_t nb_tx, uint8_t nb_rx, double sampling_rate, uint64_t center_freq, double channel_bandwidth) ;
|
||||||
double N_RB2sampling_rate(uint16_t N_RB);
|
double N_RB2sampling_rate(uint16_t N_RB);
|
||||||
double N_RB2channel_bandwidth(uint16_t N_RB);
|
double N_RB2channel_bandwidth(uint16_t N_RB);
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac)
|
|||||||
|
|
||||||
// Fake SIB19 reception for NTN
|
// Fake SIB19 reception for NTN
|
||||||
// TODO: remove this and implement the actual SIB19 reception instead!
|
// TODO: remove this and implement the actual SIB19 reception instead!
|
||||||
if (get_nrUE_params()->ntn_koffset || get_nrUE_params()->ntn_ta_common) {
|
if (get_nrUE_params()->ntn_koffset || get_nrUE_params()->ntn_ta_common || get_nrUE_params()->ntn_ta_commondrift) {
|
||||||
NR_SIB19_r17_t *sib19_r17 = calloc(1, sizeof(*sib19_r17));
|
NR_SIB19_r17_t *sib19_r17 = calloc(1, sizeof(*sib19_r17));
|
||||||
sib19_r17->ntn_Config_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17));
|
sib19_r17->ntn_Config_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17));
|
||||||
|
|
||||||
@@ -98,9 +98,11 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NTN ta-Common-r17
|
// NTN ta-Common-r17
|
||||||
if (get_nrUE_params()->ntn_ta_common) {
|
if (get_nrUE_params()->ntn_ta_common || get_nrUE_params()->ntn_ta_commondrift) {
|
||||||
sib19_r17->ntn_Config_r17->ta_Info_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17->ta_Info_r17));
|
sib19_r17->ntn_Config_r17->ta_Info_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17->ta_Info_r17));
|
||||||
sib19_r17->ntn_Config_r17->ta_Info_r17->ta_Common_r17 = get_nrUE_params()->ntn_ta_common / 4.072e-6; // ta-Common-r17 is in units of 4.072e-3 µs, ntn_ta_common is in ms
|
sib19_r17->ntn_Config_r17->ta_Info_r17->ta_Common_r17 = get_nrUE_params()->ntn_ta_common / 4.072e-6; // ta-Common-r17 is in units of 4.072e-3 µs, ntn_ta_common is in ms
|
||||||
|
if (get_nrUE_params()->ntn_ta_commondrift)
|
||||||
|
asn1cCallocOne(sib19_r17->ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17, get_nrUE_params()->ntn_ta_commondrift / 0.2e-3); // is in units of 0.2e-3 µs/s, ntn_ta_commondrift is in µs/s
|
||||||
}
|
}
|
||||||
|
|
||||||
nr_rrc_mac_config_req_sib19_r17(mac->ue_id, sib19_r17);
|
nr_rrc_mac_config_req_sib19_r17(mac->ue_id, sib19_r17);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <complex.h>
|
||||||
|
|
||||||
#include <common/utils/assertions.h>
|
#include <common/utils/assertions.h>
|
||||||
#include <common/utils/LOG/log.h>
|
#include <common/utils/LOG/log.h>
|
||||||
@@ -52,14 +52,85 @@
|
|||||||
either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
|
either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
|
||||||
legacy: we regenerate each sub frame in UL, and each frame only in DL
|
legacy: we regenerate each sub frame in UL, and each frame only in DL
|
||||||
*/
|
*/
|
||||||
void rxAddInput( const c16_t *input_sig,
|
void rxAddInput(const c16_t *input_sig,
|
||||||
c16_t *after_channel_sig,
|
c16_t *after_channel_sig,
|
||||||
int rxAnt,
|
int rxAnt,
|
||||||
channel_desc_t *channelDesc,
|
channel_desc_t *channelDesc,
|
||||||
int nbSamples,
|
int nbSamples,
|
||||||
uint64_t TS,
|
uint64_t TS,
|
||||||
uint32_t CirSize
|
uint32_t CirSize)
|
||||||
) {
|
{
|
||||||
|
if ((channelDesc->sat_height > 0) && (channelDesc->enable_dynamic_delay || channelDesc->enable_dynamic_Doppler)) { // model for transparent satellite on circular orbit
|
||||||
|
/* assumptions:
|
||||||
|
- The Earth is spherical, the ground station is static, and that the Earth does not rotate.
|
||||||
|
- An access or link is possible from the satellite to the ground station at all times.
|
||||||
|
- The ground station is located at the North Pole (positive Zaxis), and the satellite starts from the initial elevation angle 0° in the second quadrant of the YZplane.
|
||||||
|
- Satellite moves in the clockwise direction in its circular orbit.
|
||||||
|
*/
|
||||||
|
const double radius_earth = 6371e3; // m
|
||||||
|
const double radius_sat = radius_earth + channelDesc->sat_height;
|
||||||
|
const double GM_earth = 3.986e14; // m^3/s^2
|
||||||
|
const double w_sat = sqrt(GM_earth / (radius_sat * radius_sat * radius_sat)); // rad/s
|
||||||
|
|
||||||
|
// start_time and end_time are when the pos_sat_z == pos_gnb_z (elevation angle == 0 and 180 degree)
|
||||||
|
const double start_phase = -acos(radius_earth / radius_sat); // SAT is just rising above the horizon
|
||||||
|
const double end_phase = -start_phase; // SAT is just falling behind the horizon
|
||||||
|
const double start_time = start_phase / w_sat; // in seconds
|
||||||
|
const double end_time = end_phase / w_sat; // in seconds
|
||||||
|
const uint64_t duration_samples = (end_time - start_time) * channelDesc->sampling_rate;
|
||||||
|
const double t = start_time + ((TS - channelDesc->start_TS) % duration_samples) / channelDesc->sampling_rate;
|
||||||
|
|
||||||
|
const double pos_sat_x = 0;
|
||||||
|
const double pos_sat_y = radius_sat * sin(w_sat * t);
|
||||||
|
const double pos_sat_z = radius_sat * cos(w_sat * t);
|
||||||
|
|
||||||
|
const double vel_sat_x = 0;
|
||||||
|
const double vel_sat_y = w_sat * radius_sat * cos(w_sat * t);
|
||||||
|
const double vel_sat_z = -w_sat * radius_sat * sin(w_sat * t);
|
||||||
|
|
||||||
|
const double pos_ue_x = 0;
|
||||||
|
const double pos_ue_y = 0;
|
||||||
|
const double pos_ue_z = radius_earth;
|
||||||
|
|
||||||
|
const double dir_sat_ue_x = pos_ue_x - pos_sat_x;
|
||||||
|
const double dir_sat_ue_y = pos_ue_y - pos_sat_y;
|
||||||
|
const double dir_sat_ue_z = pos_ue_z - pos_sat_z;
|
||||||
|
|
||||||
|
const double dist_sat_ue = sqrt(dir_sat_ue_x * dir_sat_ue_x + dir_sat_ue_y * dir_sat_ue_y + dir_sat_ue_z * dir_sat_ue_z);
|
||||||
|
const double vel_sat_ue = (vel_sat_x * dir_sat_ue_x + vel_sat_y * dir_sat_ue_y + vel_sat_z * dir_sat_ue_z) / dist_sat_ue;
|
||||||
|
|
||||||
|
double dist_gnb_sat = 0;
|
||||||
|
double vel_gnb_sat = 0;
|
||||||
|
if (channelDesc->modelid == SAT_LEO_TRANS) {
|
||||||
|
const double pos_gnb_x = 0;
|
||||||
|
const double pos_gnb_y = 0;
|
||||||
|
const double pos_gnb_z = radius_earth;
|
||||||
|
|
||||||
|
const double dir_gnb_sat_x = pos_sat_x - pos_gnb_x;
|
||||||
|
const double dir_gnb_sat_y = pos_sat_y - pos_gnb_y;
|
||||||
|
const double dir_gnb_sat_z = pos_sat_z - pos_gnb_z;
|
||||||
|
|
||||||
|
dist_gnb_sat = sqrt(dir_gnb_sat_x * dir_gnb_sat_x + dir_gnb_sat_y * dir_gnb_sat_y + dir_gnb_sat_z * dir_gnb_sat_z);
|
||||||
|
vel_gnb_sat = (vel_sat_x * dir_gnb_sat_x + vel_sat_y * dir_gnb_sat_y + vel_sat_z * dir_gnb_sat_z) / dist_gnb_sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double c = 299792458; // m/s
|
||||||
|
const double prop_delay = (dist_gnb_sat + dist_sat_ue) / c;
|
||||||
|
if (channelDesc->enable_dynamic_delay)
|
||||||
|
channelDesc->channel_offset = prop_delay * channelDesc->sampling_rate;
|
||||||
|
|
||||||
|
const double f_Doppler_shift_sat_ue = (vel_sat_ue / (c - vel_sat_ue)) * channelDesc->center_freq;
|
||||||
|
const double f_Doppler_shift_gnb_sat = (-vel_gnb_sat / c) * channelDesc->center_freq;
|
||||||
|
if (channelDesc->enable_dynamic_Doppler)
|
||||||
|
channelDesc->Doppler_phase_inc = 2 * M_PI * (f_Doppler_shift_gnb_sat + f_Doppler_shift_sat_ue) / channelDesc->sampling_rate;
|
||||||
|
|
||||||
|
static uint64_t last_TS = 0;
|
||||||
|
if(TS - last_TS >= channelDesc->sampling_rate) {
|
||||||
|
last_TS = TS;
|
||||||
|
LOG_I(HW, "Satellite orbit: time %f s, Doppler: gNB->SAT %f kHz, SAT->UE %f kHz, Delay %f ms\n", t, f_Doppler_shift_gnb_sat / 1000, f_Doppler_shift_sat_ue / 1000, prop_delay * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// channelDesc->path_loss_dB should contain the total path gain
|
// channelDesc->path_loss_dB should contain the total path gain
|
||||||
// so, in actual RF: tx gain + path loss + rx gain (+antenna gain, ...)
|
// so, in actual RF: tx gain + path loss + rx gain (+antenna gain, ...)
|
||||||
// UE and NB gain control to be added
|
// UE and NB gain control to be added
|
||||||
@@ -94,9 +165,20 @@ void rxAddInput( const c16_t *input_sig,
|
|||||||
} //l
|
} //l
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fixme: lround(), rount(), ... is detected by valgrind as error, not found why
|
if (channelDesc->Doppler_phase_inc != 0.0) {
|
||||||
out_ptr->r += lround(rx_tmp.r*pathLossLinear + noise_per_sample*gaussZiggurat(0.0,1.0));
|
#ifdef CMPLX
|
||||||
out_ptr->i += lround(rx_tmp.i*pathLossLinear + noise_per_sample*gaussZiggurat(0.0,1.0));
|
double complex in = CMPLX(rx_tmp.r, rx_tmp.i);
|
||||||
|
#else
|
||||||
|
double complex in = rx_tmp.r + rx_tmp.i * I;
|
||||||
|
#endif
|
||||||
|
double complex out = in * cexp(channelDesc->Doppler_phase_cur[rxAnt] * I);
|
||||||
|
rx_tmp.r = creal(out);
|
||||||
|
rx_tmp.i = cimag(out);
|
||||||
|
channelDesc->Doppler_phase_cur[rxAnt] += channelDesc->Doppler_phase_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_ptr->r = lround(rx_tmp.r*pathLossLinear + noise_per_sample*gaussZiggurat(0.0,1.0));
|
||||||
|
out_ptr->i = lround(rx_tmp.i*pathLossLinear + noise_per_sample*gaussZiggurat(0.0,1.0));
|
||||||
out_ptr++;
|
out_ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ typedef struct {
|
|||||||
int rx_num_channels;
|
int rx_num_channels;
|
||||||
int tx_num_channels;
|
int tx_num_channels;
|
||||||
double sample_rate;
|
double sample_rate;
|
||||||
|
double rx_freq;
|
||||||
double tx_bw;
|
double tx_bw;
|
||||||
int channelmod;
|
int channelmod;
|
||||||
double chan_pathloss;
|
double chan_pathloss;
|
||||||
@@ -342,7 +343,7 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) {
|
|||||||
break;
|
break;
|
||||||
} else if (strcmp(rfsimu_params[p].strlistptr[i],"chanmod") == 0) {
|
} else if (strcmp(rfsimu_params[p].strlistptr[i],"chanmod") == 0) {
|
||||||
init_channelmod();
|
init_channelmod();
|
||||||
load_channellist(rfsimulator->tx_num_channels, rfsimulator->rx_num_channels, rfsimulator->sample_rate, rfsimulator->tx_bw);
|
load_channellist(rfsimulator->tx_num_channels, rfsimulator->rx_num_channels, rfsimulator->sample_rate, rfsimulator->rx_freq, rfsimulator->tx_bw);
|
||||||
rfsimulator->channelmod=true;
|
rfsimulator->channelmod=true;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "unknown rfsimulator option: %s\n", rfsimu_params[p].strlistptr[i]);
|
fprintf(stderr, "unknown rfsimulator option: %s\n", rfsimu_params[p].strlistptr[i]);
|
||||||
@@ -400,7 +401,7 @@ static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt,
|
|||||||
t->rx_num_channels,
|
t->rx_num_channels,
|
||||||
channelmod,
|
channelmod,
|
||||||
t->sample_rate,
|
t->sample_rate,
|
||||||
0,
|
t->rx_freq,
|
||||||
t->tx_bw,
|
t->tx_bw,
|
||||||
30e-9, // TDL delay-spread parameter
|
30e-9, // TDL delay-spread parameter
|
||||||
0.0,
|
0.0,
|
||||||
@@ -708,6 +709,10 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi
|
|||||||
samplesVoid[i]=(void *)&v;
|
samplesVoid[i]=(void *)&v;
|
||||||
|
|
||||||
rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS - 1 : 0, samplesVoid, 1, t->tx_num_channels, 1, false);
|
rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS - 1 : 0, samplesVoid, 1, t->tx_num_channels, 1, false);
|
||||||
|
|
||||||
|
buffer_t *b = &t->buf[conn_sock];
|
||||||
|
if (b->channel_model)
|
||||||
|
b->channel_model->start_TS = t->lastWroteTS;
|
||||||
} else {
|
} else {
|
||||||
if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) {
|
if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) {
|
||||||
socketError(t,fd);
|
socketError(t,fd);
|
||||||
@@ -760,6 +765,8 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi
|
|||||||
nsamps_for_initial;
|
nsamps_for_initial;
|
||||||
LOG_D(HW, "UE got first timestamp: starting at %lu\n", t->nextRxTstamp);
|
LOG_D(HW, "UE got first timestamp: starting at %lu\n", t->nextRxTstamp);
|
||||||
b->trashingPacket=true;
|
b->trashingPacket=true;
|
||||||
|
if (b->channel_model)
|
||||||
|
b->channel_model->start_TS = t->nextRxTstamp;
|
||||||
} else if (b->lastReceivedTS < b->th.timestamp) {
|
} else if (b->lastReceivedTS < b->th.timestamp) {
|
||||||
int nbAnt= b->th.nbAnt;
|
int nbAnt= b->th.nbAnt;
|
||||||
|
|
||||||
@@ -963,6 +970,8 @@ static int rfsimulator_stop(openair0_device *device) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static int rfsimulator_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) {
|
static int rfsimulator_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||||
|
rfsimulator_state_t* s = device->priv;
|
||||||
|
s->rx_freq = openair0_cfg->rx_freq[0];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static int rfsimulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) {
|
static int rfsimulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||||
@@ -980,6 +989,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
|||||||
rfsimulator->tx_num_channels=openair0_cfg->tx_num_channels;
|
rfsimulator->tx_num_channels=openair0_cfg->tx_num_channels;
|
||||||
rfsimulator->rx_num_channels=openair0_cfg->rx_num_channels;
|
rfsimulator->rx_num_channels=openair0_cfg->rx_num_channels;
|
||||||
rfsimulator->sample_rate=openair0_cfg->sample_rate;
|
rfsimulator->sample_rate=openair0_cfg->sample_rate;
|
||||||
|
rfsimulator->rx_freq=openair0_cfg->rx_freq[0];
|
||||||
rfsimulator->tx_bw=openair0_cfg->tx_bw;
|
rfsimulator->tx_bw=openair0_cfg->tx_bw;
|
||||||
rfsimulator_readconfig(rfsimulator);
|
rfsimulator_readconfig(rfsimulator);
|
||||||
if (rfsimulator->prop_delay_ms > 0.0)
|
if (rfsimulator->prop_delay_ms > 0.0)
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
channelmod = {
|
||||||
|
max_chan=10;
|
||||||
|
modellist="modellist_rfsimu_1";
|
||||||
|
modellist_rfsimu_1 = (
|
||||||
|
{
|
||||||
|
model_name = "rfsimu_channel_enB0"
|
||||||
|
type = "SAT_LEO_TRANS";
|
||||||
|
noise_power_dB = -100;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model_name = "rfsimu_channel_ue0"
|
||||||
|
type = "SAT_LEO_TRANS";
|
||||||
|
noise_power_dB = -100;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -165,7 +165,8 @@ gNBs =
|
|||||||
|
|
||||||
#ext2
|
#ext2
|
||||||
#ntn_Config_r17
|
#ntn_Config_r17
|
||||||
# cellSpecificKoffset_r17 = 478;
|
# cellSpecificKoffset_r17 = 478; # GEO satellite
|
||||||
|
# cellSpecificKoffset_r17 = 40; # LEO satellite
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
@@ -255,7 +256,6 @@ rfsimulator :
|
|||||||
serveraddr = "server";
|
serveraddr = "server";
|
||||||
serverport = 4043;
|
serverport = 4043;
|
||||||
options = (); #("saviq"); or/and "chanmod"
|
options = (); #("saviq"); or/and "chanmod"
|
||||||
modelname = "AWGN";
|
|
||||||
IQfile = "/tmp/rfsimulator.iqs";
|
IQfile = "/tmp/rfsimulator.iqs";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -289,3 +289,4 @@ log_config :
|
|||||||
f1ap_log_level ="debug";
|
f1ap_log_level ="debug";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@include "channelmod_rfsimu_LEO_satellite.conf"
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ gNBs =
|
|||||||
|
|
||||||
#ext2
|
#ext2
|
||||||
#ntn_Config_r17
|
#ntn_Config_r17
|
||||||
# cellSpecificKoffset_r17 = 478;
|
# cellSpecificKoffset_r17 = 478; # GEO satellite
|
||||||
|
# cellSpecificKoffset_r17 = 40; # LEO satellite
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
@@ -255,7 +256,6 @@ rfsimulator :
|
|||||||
serveraddr = "server";
|
serveraddr = "server";
|
||||||
serverport = 4043;
|
serverport = 4043;
|
||||||
options = (); #("saviq"); or/and "chanmod"
|
options = (); #("saviq"); or/and "chanmod"
|
||||||
modelname = "AWGN";
|
|
||||||
IQfile = "/tmp/rfsimulator.iqs";
|
IQfile = "/tmp/rfsimulator.iqs";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -289,3 +289,4 @@ log_config :
|
|||||||
f1ap_log_level ="debug";
|
f1ap_log_level ="debug";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@include "channelmod_rfsimu_LEO_satellite.conf"
|
||||||
|
|||||||
Reference in New Issue
Block a user