Merge remote-tracking branch 'origin/ntn_leo_freq_comp' into integration_2025_w15 (!3355)
NR UE: add support for continuous frequency offset compensation (in particular NTN LEO Doppler)
- move function add_noise() to file
openair1/SIMULATION/TOOLS/phase_noise.c
- refactor (co)sinus calculation out of phase_noise() into get_sin_cos()
in nr_common.c
- NR UE: continuously estimate the frequency offset using PBCH DMRS
- NR UE: add command line parameter --initial-fo to specify known
initial frequency offset
- NR UE: add support for continuous DL frequency offset compensation
--cont-fo-comp
- NR UE: add support for continuous UL frequency offset
pre-compensation. Depending on the main source of frequency offset,
pre-compensate the UL frequency offset (FO) accordingly. Therefore
modify the flag --cont-fo-comp to accept an integer value, where
* 1 specifies, that the main FO contribution comes from the accuracy of the local oscillator (LO)
* 2 specifies, that the main FO contribution comes from Doppler shift
- NR UE: add PI controller to continuous frequency offset compensation
- rfsimulator: enable and correct NTN LEO doppler simulation
- use SIMD to speed up nr_fo_compensation()
- Extend NTN LEO example in RUNMODEM.md to include continuous Doppler
compensation
- NR UE: in nr_adjust_synch_ue() extend the peak search to +/- cyclic
prefix size, esp. for LEO NTN scenarios the timing drifts during
initial sync, which is mostly compensated with
--ntn-initial-time-drift. But there might be a residual time offset,
and by extending the peak search window we make this more tolerant.
- NR UE: remove unused nr_slot_tx_offset, it is unused since commit
f3e60a14
- NR UE: remove now unnecessary local variable
update_ntn_system_information, directly use
UE->ntn_config_message->update instead
This commit is contained in:
@@ -823,6 +823,7 @@ set(PHY_SRC_COMMON
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/sqrt.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/lut.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/simde_operations.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/get_sin_cos.c
|
||||
)
|
||||
|
||||
set(PHY_SRC
|
||||
|
||||
@@ -235,15 +235,6 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
|
||||
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
|
||||
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
|
||||
worker_config = "WORKER_DISABLE";
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
@@ -296,6 +287,4 @@ log_config :
|
||||
rlc_log_level ="info";
|
||||
pdcp_log_level ="info";
|
||||
rrc_log_level ="info";
|
||||
ngap_log_level ="debug";
|
||||
f1ap_log_level ="debug";
|
||||
};
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
}
|
||||
|
||||
position0 = {
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
z = 6377900.0;
|
||||
}
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
#/* configuration for channel modelisation */
|
||||
#/* To be included in main config file when */
|
||||
#/* channel modelisation is used (rfsimulator with chanmod options enabled) */
|
||||
channelmod = {
|
||||
max_chan = 10;
|
||||
modellist = "modellist_rfsimu_1";
|
||||
modellist_rfsimu_1 = (
|
||||
{ # DL, modify on UE side
|
||||
model_name = "rfsimu_channel_enB0"
|
||||
type = "SAT_LEO_TRANS";
|
||||
noise_power_dB = -100;
|
||||
},
|
||||
{ # UL, modify on gNB side
|
||||
model_name = "rfsimu_channel_ue0"
|
||||
type = "SAT_LEO_TRANS";
|
||||
noise_power_dB = -100;
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
<!--
|
||||
|
||||
Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The OpenAirInterface Software Alliance licenses this file to You under
|
||||
the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.openairinterface.org/?page_id=698
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
contact@openairinterface.org
|
||||
|
||||
-->
|
||||
<testCaseList>
|
||||
<htmlTabRef>rfsim-5gnr-ntn-Leo</htmlTabRef>
|
||||
<htmlTabName>Monolithic SA NTN LEO gNB</htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
<TestCaseRequestedList>
|
||||
111111
|
||||
100001
|
||||
800813
|
||||
000001
|
||||
000002
|
||||
000003
|
||||
020001
|
||||
020002
|
||||
100001
|
||||
222222
|
||||
</TestCaseRequestedList>
|
||||
<TestCaseExclusionList></TestCaseExclusionList>
|
||||
|
||||
<testCase id="111111">
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
<testCase id="800813">
|
||||
<class>Create_Workspace</class>
|
||||
<desc>Create new Workspace</desc>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
<testCase id="000001">
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G CoreNetwork</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_ntn_leo</yaml_path>
|
||||
<services>mysql oai-amf oai-smf oai-upf oai-ext-dn</services>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000002">
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G gNB+nrUE RF sim SA</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_ntn_leo</yaml_path>
|
||||
<services>oai-gnb oai-nr-ue</services>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000003">
|
||||
<class>Attach_UE</class>
|
||||
<desc>Attach OAI UE (Wait for IP)</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<nodes>cacofonix</nodes>
|
||||
</testCase>
|
||||
|
||||
<testCase id="020001">
|
||||
<class>Ping</class>
|
||||
<desc>Ping ext-dn from NR-UE</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<nodes>cacofonix</nodes>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>cacofonix</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase id="020002">
|
||||
<class>Ping</class>
|
||||
<desc>Ping NR-UE from ext-dn</desc>
|
||||
<id>rfsim5g_ext_dn</id>
|
||||
<nodes>cacofonix</nodes>
|
||||
<svr_id>rfsim5g_ue</svr_id>
|
||||
<svr_node>cacofonix</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase id="100001">
|
||||
<class>Undeploy_Object</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Undeploy all OAI 5G stack</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_ntn_leo</yaml_path>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="222222">
|
||||
<class>Clean_Test_Server_Images</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
@@ -0,0 +1,151 @@
|
||||
services:
|
||||
mysql:
|
||||
container_name: "rfsim5g-mysql"
|
||||
image: mysql:8.0
|
||||
volumes:
|
||||
- ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql
|
||||
- ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
- MYSQL_DATABASE=oai_db
|
||||
- MYSQL_USER=test
|
||||
- MYSQL_PASSWORD=test
|
||||
- MYSQL_ROOT_PASSWORD=linux
|
||||
healthcheck:
|
||||
test: /bin/bash -c "/tmp/mysql-healthcheck.sh"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.131
|
||||
oai-amf:
|
||||
container_name: "rfsim5g-oai-amf"
|
||||
image: oaisoftwarealliance/oai-amf:v2.0.0
|
||||
environment:
|
||||
- TZ=Europe/paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-amf/etc/config.yaml
|
||||
depends_on:
|
||||
- mysql
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.132
|
||||
oai-smf:
|
||||
container_name: "rfsim5g-oai-smf"
|
||||
image: oaisoftwarealliance/oai-smf:v2.0.0
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-smf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-amf
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.133
|
||||
oai-upf:
|
||||
container_name: "rfsim5g-oai-upf"
|
||||
image: oaisoftwarealliance/oai-upf:v2.0.0
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-upf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-smf
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
cap_drop:
|
||||
- ALL
|
||||
privileged: true
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.134
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.134
|
||||
oai-ext-dn:
|
||||
privileged: true
|
||||
container_name: rfsim5g-oai-ext-dn
|
||||
image: oaisoftwarealliance/trf-gen-cn5g:focal
|
||||
entrypoint: /bin/bash -c \
|
||||
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
|
||||
"ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity"
|
||||
depends_on:
|
||||
- oai-upf
|
||||
networks:
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.135
|
||||
healthcheck:
|
||||
test: /bin/bash -c "ping -c 2 192.168.72.134"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
oai-gnb:
|
||||
image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-gnb
|
||||
cap_drop:
|
||||
- ALL
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
depends_on:
|
||||
- oai-ext-dn
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.140
|
||||
volumes:
|
||||
- ../../conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf:/opt/oai-gnb/etc/gnb.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-softmodem"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
oai-nr-ue:
|
||||
image: ${REGISTRY:-oaisoftwarealliance}/${NRUE_IMG:-oai-nr-ue}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-nr-ue
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- NET_ADMIN # for interface bringup
|
||||
- NET_RAW # for ping
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS:
|
||||
--band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60
|
||||
--rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod
|
||||
--rfsimulator.serveraddr 192.168.71.140
|
||||
--time-sync-I 0.1 --ntn-initial-time-drift -46
|
||||
--autonomous-ta --initial-fo 57340 --cont-fo-comp 2
|
||||
--log_config.global_log_options level,nocolor,time
|
||||
depends_on:
|
||||
- oai-gnb
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.150
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ../../conf_files/nrue.uicc.ntn-leo.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-uesoftmodem"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
networks:
|
||||
public_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-public-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.71.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-public"
|
||||
traffic_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-traffic-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.72.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-traffic"
|
||||
+16
-2
@@ -136,7 +136,15 @@ Here are some useful command line options for the NR UE:
|
||||
| Parameter | Description |
|
||||
|--------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| `--ue-scan-carrier` | Scan for cells in current bandwidth. This option can be used if the SSB position of the gNB is unknown. If multiple cells are detected, the UE will try to connect to the first cell. By default, this option is disabled and the UE attempts to only decode SSB given by `--ssb`. |
|
||||
| `--ue-fo-compensation` | Enables the frequency offset compensation at the UE. Useful when running over the air and/or without an external clock/time source. |
|
||||
| `--ue-fo-compensation` | Enables the initial frequency offset compensation at the UE. Useful when running over the air and/or without an external clock/time source. |
|
||||
| `--cont-fo-comp` | Enables the continuous frequency offset (FO) estimation and compensation. Parameter value `1` specifies that the main FO contribution comes from the local oscillator's (LO) accuracy. Parameter value `2` specifies that the main FO contribution comes from Doppler shift. |
|
||||
| `--initial-fo` | Sets the known initial frequency offset. Useful especially with large Doppler frequency, e.g. LEO satellite. |
|
||||
| `--freq-sync-P` | Sets the coefficient for the Proportional part of the PI-controller for the continuous frequency offset compensation. Default value 0.01. |
|
||||
| `--freq-sync-I` | Sets the coefficient for the Integrating part of the PI-controller for the continuous frequency offset compensation. Default value 0.001. |
|
||||
| `--ntn-initial-time-drift` | Sets the initial NTN DL time drift (feeder link and service link), given in µs/s. |
|
||||
| `--autonomous-ta` | Enables the autonomous TA update, based on DL drift (useful if main contribution to DL drift is movement, e.g. LEO satellite). |
|
||||
| `--time-sync-P` | Sets the coefficient for the Proportional part of the PI-controller for the time synchronization. Default value 0.5. |
|
||||
| `--time-sync-I` | Sets the coefficient for the Integrating part of the PI-controller for the time synchronization. Default value 0.0. |
|
||||
| `--usrp-args` | Equivalent to the `sdr_addrs` field in the gNB config file. Used to identify the USRP and set some basic parameters (like the clock source). |
|
||||
| `--clock-source` | Sets the clock source (internal or external). |
|
||||
| `--time-source` | Sets the time source (internal or external). |
|
||||
@@ -349,10 +357,16 @@ For LEO satellite scenarios, the parameter `--ntn-initial-time-drift` must be pr
|
||||
This parameter provides the drift rate of the complete DL timing (incl. feeder link and service link) in µs/s.
|
||||
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.
|
||||
|
||||
For LEO satellite scenario we assume the LO to be very accurate and the main FO contribution comes from Doppler shift.
|
||||
Therefore, we use the command line parameter `--cont-fo-comp 2` to continuously compensate the DL Doppler and pre-compensate the UL Doppler.
|
||||
The initial Doppler frequency offset must be provided via command line with the parameter `--initial-fo`.
|
||||
|
||||
For other information on optional NR UE command line options, please refer [here](#optional-nr-ue-command-line-options).
|
||||
|
||||
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 -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod --time-sync-I 0.1 --ntn-initial-time-drift -46 --autonomous-ta
|
||||
sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod --time-sync-I 0.1 --ntn-initial-time-drift -46 --autonomous-ta --initial-fo 57340 --cont-fo-comp 2
|
||||
```
|
||||
|
||||
# Specific OAI modes
|
||||
|
||||
+24
-20
@@ -41,6 +41,7 @@
|
||||
#include "instrumentation.h"
|
||||
#include "common/utils/threadPool/notified_fifo.h"
|
||||
#include "position_interface.h"
|
||||
#include "nr_phy_common.h"
|
||||
|
||||
/*
|
||||
* NR SLOT PROCESSING SEQUENCE
|
||||
@@ -438,9 +439,13 @@ static void UE_synch(void *arg) {
|
||||
((ret.rx_offset << 1) / fp->samples_per_subframe * fp->slots_per_subframe)
|
||||
+ round((float)((ret.rx_offset << 1) % fp->samples_per_subframe) / fp->samples_per_slot0);
|
||||
|
||||
// rerun with new cell parameters and frequency-offset
|
||||
// todo: the freq_offset computed on DL shall be scaled before being applied to UL
|
||||
nr_rf_card_config_freq(cfg0, ul_carrier, dl_carrier, freq_offset);
|
||||
if (get_nrUE_params()->cont_fo_comp) {
|
||||
UE->freq_offset = freq_offset;
|
||||
} else {
|
||||
// rerun with new cell parameters and frequency-offset
|
||||
nr_rf_card_config_freq(cfg0, ul_carrier, dl_carrier, freq_offset);
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice, cfg0);
|
||||
}
|
||||
|
||||
if (get_nrUE_params()->agc) {
|
||||
nr_ue_adjust_rx_gain(UE, cfg0, UE->adjust_rxgain);
|
||||
@@ -454,7 +459,6 @@ static void UE_synch(void *arg) {
|
||||
cfg0->rx_freq[0],
|
||||
cfg0->tx_freq[0]);
|
||||
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice, cfg0);
|
||||
UE->is_synchronized = 1;
|
||||
} else {
|
||||
int gain_change = 0;
|
||||
@@ -553,6 +557,15 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action)
|
||||
writeBlockSize -= dummyBlockSize;
|
||||
}
|
||||
|
||||
// pre-compensate UL frequency offset
|
||||
if (flags != TX_BURST_INVALID && get_nrUE_params()->cont_fo_comp) {
|
||||
double ul_freq_offset = -UE->freq_offset * ((double)fp->ul_CarrierFreq / (double)fp->dl_CarrierFreq);
|
||||
if (get_nrUE_params()->cont_fo_comp == 2) // different from LO frequency error compensation, Doppler UL pre-compensation has to be negative
|
||||
ul_freq_offset = -ul_freq_offset;
|
||||
for (int i = 0; i < fp->nb_antennas_tx; i++)
|
||||
nr_fo_compensation(ul_freq_offset, fp->samples_per_subframe, writeTimestamp, txp[i], writeBlockSize);
|
||||
}
|
||||
|
||||
int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, writeBlockSize, fp->nb_antennas_tx, flags);
|
||||
AssertFatal(tmp == writeBlockSize, "");
|
||||
}
|
||||
@@ -868,13 +881,12 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
|
||||
static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int slot_nr,
|
||||
bool *update_ntn_system_information,
|
||||
int *duration_rx_to_tx,
|
||||
int *timing_advance,
|
||||
int *ntn_koffset)
|
||||
{
|
||||
if (*update_ntn_system_information) {
|
||||
*update_ntn_system_information = false;
|
||||
if (UE->ntn_config_message->update) {
|
||||
UE->ntn_config_message->update = false;
|
||||
|
||||
double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms;
|
||||
UE->timing_advance = fp->samples_per_subframe * total_ta_ms;
|
||||
@@ -920,6 +932,8 @@ void *UE_thread(void *arg)
|
||||
if (usrp_tx_thread == 1)
|
||||
UE->rfdevice.trx_write_init(&UE->rfdevice);
|
||||
|
||||
InitSinLUT();
|
||||
|
||||
notifiedFIFO_t nf;
|
||||
initNotifiedFIFO(&nf);
|
||||
|
||||
@@ -954,13 +968,9 @@ void *UE_thread(void *arg)
|
||||
|
||||
double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift;
|
||||
int ntn_koffset = 0;
|
||||
|
||||
int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX;
|
||||
int nr_slot_tx_offset = 0;
|
||||
bool update_ntn_system_information = false;
|
||||
|
||||
while (!oai_exit) {
|
||||
nr_slot_tx_offset = 0;
|
||||
if (syncRunning) {
|
||||
notifiedFIFO_elt_t *res = pollNotifiedFIFO(&nf);
|
||||
|
||||
@@ -1085,12 +1095,6 @@ void *UE_thread(void *arg)
|
||||
absolute_slot++;
|
||||
TracyCFrameMark;
|
||||
|
||||
if (UE->ntn_config_message->update) {
|
||||
UE->ntn_config_message->update = false;
|
||||
update_ntn_system_information = true;
|
||||
nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset << fp->numerology_index;
|
||||
}
|
||||
|
||||
int slot_nr = absolute_slot % nb_slot_frame;
|
||||
nr_rxtx_thread_data_t curMsg = {0};
|
||||
curMsg.UE=UE;
|
||||
@@ -1180,8 +1184,8 @@ void *UE_thread(void *arg)
|
||||
shiftForNextFrame = ret;
|
||||
pushNotifiedFIFO(&UE->dl_actors[curMsg.proc.nr_slot_rx % NUM_DL_ACTORS].fifo, newRx);
|
||||
|
||||
// apply new duration next run to avoid thread dead lock
|
||||
apply_ntn_config(UE, fp, slot_nr, &update_ntn_system_information, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
// apply new NTN timing information
|
||||
apply_ntn_config(UE, fp, slot_nr, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
|
||||
// Start TX slot processing here. It runs in parallel with RX slot processing
|
||||
// in current code, DURATION_RX_TO_TX constant is the limit to get UL data to encode from a RX slot
|
||||
@@ -1192,7 +1196,7 @@ void *UE_thread(void *arg)
|
||||
curMsgTx->writeBlockSize = writeBlockSize;
|
||||
curMsgTx->proc.timestamp_tx = writeTimestamp;
|
||||
curMsgTx->UE = UE;
|
||||
curMsgTx->proc.nr_slot_tx_offset = nr_slot_tx_offset;
|
||||
|
||||
int slot = curMsgTx->proc.nr_slot_tx;
|
||||
int slot_and_frame = slot + curMsgTx->proc.frame_tx * UE->frame_parms.slots_per_frame;
|
||||
int next_tx_slot_and_frame = absolute_slot + duration_rx_to_tx + 1;
|
||||
|
||||
@@ -224,6 +224,8 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
|
||||
UE->chest_freq = nrUE_params.chest_freq;
|
||||
UE->chest_time = nrUE_params.chest_time;
|
||||
UE->no_timing_correction = nrUE_params.no_timing_correction;
|
||||
UE->initial_fo = nrUE_params.initial_fo;
|
||||
UE->cont_fo_comp = nrUE_params.cont_fo_comp;
|
||||
|
||||
LOG_I(PHY,"Set UE_fo_compensation %d, UE_scan_carrier %d, UE_no_timing_correction %d \n, chest-freq %d, chest-time %d\n",
|
||||
UE->UE_fo_compensation, UE->UE_scan_carrier, UE->no_timing_correction, UE->chest_freq, UE->chest_time);
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#define CONFIG_HLP_TIME_SYNC_I "coefficient for Integrating part of time sync PI controller\n"
|
||||
#define CONFIG_HLP_NTN_INIT_TIME_DRIFT "Initial NTN DL time drift (feeder link and service link), 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_INITIAL_FO "Initially compensated DL frequency offset (e.g. known Doppler shift in NTN LEO scenario)\n"
|
||||
#define CONFIG_HLP_FREQ_SYNC_P "coefficient for Proportional part of continuous frequency offset compensation PI controller\n"
|
||||
#define CONFIG_HLP_FREQ_SYNC_I "coefficient for Integrating part of continuous frequency offset compensation PI controller\n"
|
||||
#define CONFIG_HLP_CONT_FO_COMP "Enable continuous frequency offset (FO) estimation and compensation and specify main FO source (1 = local oscillator, 2 = Doppler shift)\n"
|
||||
#define CONFIG_HLP_AGC "Rx Gain control used for UE\n"
|
||||
#define CONFIG_HLP_NUM_UL_ACTORS "Number of UL actors to use. Set to 0 to use the default value\n"
|
||||
|
||||
@@ -66,6 +70,10 @@
|
||||
{"time-sync-I", CONFIG_HLP_TIME_SYNC_I, 0, .dblptr=&(nrUE_params.time_sync_I), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"ntn-initial-time-drift", CONFIG_HLP_NTN_INIT_TIME_DRIFT, 0, .dblptr=&(nrUE_params.ntn_init_time_drift), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"autonomous-ta", CONFIG_HLP_AUTONOMOUS_TA, PARAMFLAG_BOOL, .iptr=&(nrUE_params.autonomous_ta), .defintval=0, TYPE_INT, 0}, \
|
||||
{"initial-fo", CONFIG_HLP_INITIAL_FO, 0, .dblptr=&(nrUE_params.initial_fo), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"freq-sync-P", CONFIG_HLP_FREQ_SYNC_P, 0, .dblptr=&(nrUE_params.freq_sync_P), .defdblval=0.01, TYPE_DOUBLE, 0}, \
|
||||
{"freq-sync-I", CONFIG_HLP_FREQ_SYNC_I, 0, .dblptr=&(nrUE_params.freq_sync_I), .defdblval=0.001, TYPE_DOUBLE, 0}, \
|
||||
{"cont-fo-comp", CONFIG_HLP_CONT_FO_COMP, 0, .iptr=&(nrUE_params.cont_fo_comp), .defintval=0, TYPE_INT, 0}, \
|
||||
{"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \
|
||||
{"num-ul-actors", CONFIG_HLP_NUM_UL_ACTORS, 0, .iptr=&nrUE_params.num_ul_actors, .defintval=0, TYPE_INT, 0}, \
|
||||
}
|
||||
@@ -91,6 +99,10 @@ typedef struct {
|
||||
double time_sync_I;
|
||||
double ntn_init_time_drift;
|
||||
int autonomous_ta;
|
||||
double initial_fo;
|
||||
double freq_sync_P;
|
||||
double freq_sync_I;
|
||||
int cont_fo_comp;
|
||||
int agc;
|
||||
char *usrp_args;
|
||||
char *tx_subdev;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "nr_modulation.h"
|
||||
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
|
||||
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
||||
#include "PHY/nr_phy_common/inc/nr_phy_common.h"
|
||||
#include <common/utils/LOG/log.h>
|
||||
|
||||
//#define DEBUG_FEP
|
||||
@@ -108,6 +109,12 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
rxdata_ptr = (int16_t *)tmp_dft_in;
|
||||
}
|
||||
|
||||
if (ue && ue->cont_fo_comp) {
|
||||
start_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS);
|
||||
nr_fo_compensation(ue->freq_offset, frame_parms->samples_per_subframe, rx_offset, (c16_t *)rxdata_ptr, frame_parms->ofdm_symbol_size);
|
||||
stop_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS);
|
||||
}
|
||||
|
||||
if (ue)
|
||||
start_meas_nr_ue_phy(ue, RX_DFT_STATS);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ int nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_IN);
|
||||
|
||||
// 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; i < frame_parms->nb_prefix_samples; i++) {
|
||||
int temp = 0;
|
||||
|
||||
int j = (i < 0) ? (i + frame_parms->ofdm_symbol_size) : i;
|
||||
|
||||
@@ -199,6 +199,9 @@ void nr_scan_ssb(void *arg)
|
||||
// initial sync performed on two successive frames, if pbch passes on first frame, no need to process second frame
|
||||
// only one frame is used for simulation tools
|
||||
for (int frame_id = 0; frame_id < ssbInfo->nFrames && !ssbInfo->syncRes.cell_detected; frame_id++) {
|
||||
if (ssbInfo->freqOffset)
|
||||
compensate_freq_offset(rxdata, fp, ssbInfo->freqOffset, frame_id);
|
||||
|
||||
/* process pss search on received buffer */
|
||||
ssbInfo->syncRes.frame_id = frame_id;
|
||||
int nid2;
|
||||
@@ -268,7 +271,7 @@ void nr_scan_ssb(void *arg)
|
||||
phase_tdd_ncp,
|
||||
ssbInfo->syncRes.rx_offset);
|
||||
#endif
|
||||
ssbInfo->freqOffset = freq_offset_pss + freq_offset_sss;
|
||||
ssbInfo->freqOffset += freq_offset_pss + freq_offset_sss;
|
||||
|
||||
if (ssbInfo->syncRes.cell_detected) { // we got sss channel
|
||||
ssbInfo->syncRes.cell_detected = nr_pbch_detection(ssbInfo->proc,
|
||||
@@ -319,6 +322,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
|
||||
.syncRes.cell_detected = false,
|
||||
.nFrames = n_frames,
|
||||
.foFlag = ue->UE_fo_compensation,
|
||||
.freqOffset = ue->initial_fo,
|
||||
.targetNidCell = ue->target_Nid_cell};
|
||||
ssbInfo->rxdata = malloc16_clear(fp->nb_antennas_rx * sizeof(c16_t *));
|
||||
for (int ant = 0; ant < fp->nb_antennas_rx; ant++) {
|
||||
|
||||
@@ -525,3 +525,21 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
|
||||
TracyCZoneEnd(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
double nr_ue_pbch_freq_offset(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int estimateSz,
|
||||
const c16_t dl_ch_estimates[][estimateSz])
|
||||
{
|
||||
const int i_ssb = frame_parms->ssb_index;
|
||||
const int symbol_offset = nr_get_ssb_start_symbol(frame_parms, i_ssb) % frame_parms->symbols_per_slot;
|
||||
const c16_t *dl_ch_est_symb1 = &dl_ch_estimates[0][(symbol_offset + 1) * frame_parms->ofdm_symbol_size];
|
||||
const c16_t *dl_ch_est_symb3 = &dl_ch_estimates[0][(symbol_offset + 3) * frame_parms->ofdm_symbol_size];
|
||||
const int nb_re = 240;
|
||||
const c32_t dot_prod_res = dot_product(dl_ch_est_symb1, dl_ch_est_symb3, nb_re, 8);
|
||||
const double res_phase = atan2(dot_prod_res.i, dot_prod_res.r);
|
||||
const int samples_per_symbol = frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples;
|
||||
const double t_ofdm = samples_per_symbol / (frame_parms->samples_per_subframe * 1000.0); // symbol duration in sec
|
||||
const double freq_offset = res_phase / (2 * M_PI * (3 - 1) * t_ofdm);
|
||||
|
||||
return freq_offset;
|
||||
}
|
||||
|
||||
@@ -204,6 +204,10 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
|
||||
int rxdataFSize,
|
||||
const struct complex16 rxdataF[][rxdataFSize]);
|
||||
|
||||
double nr_ue_pbch_freq_offset(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int estimateSz,
|
||||
const c16_t dl_ch_estimates[][estimateSz]);
|
||||
|
||||
#ifndef modOrder
|
||||
#define modOrder(I_MCS,I_TBS) ((I_MCS-I_TBS)*2+2) // Find modulation order from I_TBS and I_MCS
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "tools_defs.h"
|
||||
|
||||
#define LUT_SIN_RESOL 128
|
||||
// look-up table for the sine (cosine) function
|
||||
static uint16_t LUTSin[LUT_SIN_RESOL + 1];
|
||||
|
||||
void InitSinLUT(void)
|
||||
{
|
||||
for (int i = 0; i < (LUT_SIN_RESOL + 1); i++) {
|
||||
LUTSin[i] = round(sin((M_PI * i) / (2 * LUT_SIN_RESOL)) * (1 << 14)); // Format: Q14
|
||||
}
|
||||
}
|
||||
|
||||
// fast calculation of e^{i*2*pi*phase}
|
||||
// ret.r == cosinus << 14
|
||||
// ret.i == sinus << 14
|
||||
c16_t get_sin_cos(double phase)
|
||||
{
|
||||
int index;
|
||||
if (phase < 0) {
|
||||
index = (int)(-phase * 4 * LUT_SIN_RESOL + 0.5) % (4 * LUT_SIN_RESOL);
|
||||
index = 4 * LUT_SIN_RESOL - index;
|
||||
} else {
|
||||
index = (int)(phase * 4 * LUT_SIN_RESOL + 0.5) % (4 * LUT_SIN_RESOL);
|
||||
}
|
||||
|
||||
c16_t ret;
|
||||
if (index < 2 * LUT_SIN_RESOL) { // check for 1st and 2nd Quadrant
|
||||
if (index < LUT_SIN_RESOL) { // 1st Quadrant
|
||||
ret.r = LUTSin[LUT_SIN_RESOL - index];
|
||||
ret.i = LUTSin[index];
|
||||
} else { // 2nd Quadrant
|
||||
ret.r = -LUTSin[index - LUT_SIN_RESOL];
|
||||
ret.i = LUTSin[2 * LUT_SIN_RESOL - index];
|
||||
}
|
||||
} else { // 3rd and 4th Quadrant
|
||||
if (index < 3 * LUT_SIN_RESOL) { // 3rd Quadrant
|
||||
ret.r = -LUTSin[3 * LUT_SIN_RESOL - index];
|
||||
ret.i = -LUTSin[index - 2 * LUT_SIN_RESOL];
|
||||
} else { // 4th Quadrant
|
||||
ret.r = LUTSin[index - 3 * LUT_SIN_RESOL];
|
||||
ret.i = -LUTSin[4 * LUT_SIN_RESOL - index];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -792,6 +792,13 @@ double interp(double x, double *xs, double *ys, int count);
|
||||
void simde_mm128_separate_real_imag_parts(simde__m128i *out_re, simde__m128i *out_im, simde__m128i in0, simde__m128i in1);
|
||||
void simde_mm256_separate_real_imag_parts(simde__m256i *out_re, simde__m256i *out_im, simde__m256i in0, simde__m256i in1);
|
||||
|
||||
void InitSinLUT(void);
|
||||
|
||||
// fast calculation of e^{i*2*pi*phase}
|
||||
// ret.r == cosinus << 14
|
||||
// ret.i == sinus << 14
|
||||
c16_t get_sin_cos(double phase);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -460,6 +460,11 @@ typedef struct PHY_VARS_NR_UE_s {
|
||||
int64_t max_pos_iir; /// Timing offset IIR filter
|
||||
int max_pos_acc; /// Timing offset accumuluated error for PI filter
|
||||
|
||||
double initial_fo; /// initial frequency offset provided by the user
|
||||
int cont_fo_comp; /// flag enabling the continuous frequency offset estimation and compensation
|
||||
double freq_offset; /// currently compensated frequency offset
|
||||
double freq_off_acc; /// accumulated frequency error (for PI controller)
|
||||
|
||||
/// Timing Advance updates variables
|
||||
/// Timing advance update computed from the TA command signalled from gNB
|
||||
int timing_advance;
|
||||
@@ -525,10 +530,6 @@ typedef struct {
|
||||
int gNB_id;
|
||||
/// NR slot index within frame_tx [0 .. slots_per_frame - 1] to act upon for transmission
|
||||
int nr_slot_tx;
|
||||
/// NR slot index tx offset to resume
|
||||
/// in case of NTN, tx_offset can be changed dynamically via SIB19
|
||||
/// we need to notify the right tx thread slot based on TX offset change
|
||||
int nr_slot_tx_offset;
|
||||
int rx_slot_type;
|
||||
/// NR slot index within frame_rx [0 .. slots_per_frame - 1] to act upon for transmission
|
||||
int nr_slot_rx;
|
||||
|
||||
@@ -80,4 +80,6 @@ void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int
|
||||
void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal);
|
||||
void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay);
|
||||
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb);
|
||||
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16_t *rxdata_ptr, int size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define FOREACH_NR_PHY_CPU_MEAS(FN) \
|
||||
FN(RX_PDSCH_STATS),\
|
||||
FN(DLSCH_RX_PDCCH_STATS),\
|
||||
FN(RX_FO_COMPENSATION_STATS),\
|
||||
FN(RX_DFT_STATS),\
|
||||
FN(DLSCH_CHANNEL_ESTIMATION_STATS),\
|
||||
FN(DLSCH_DECODING_STATS),\
|
||||
|
||||
@@ -453,3 +453,40 @@ unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, in
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16_t *rxdata_ptr, int size)
|
||||
{
|
||||
const double phase_inc = -fo_Hz / (samples_per_ms * 1000);
|
||||
double phase = sample_offset * phase_inc;
|
||||
phase -= (int)phase;
|
||||
#if 1
|
||||
// The bottleneck is the calculation of the complex rotation values using get_sin_cos().
|
||||
// This code path does not compute these values for the complete OFDM symbol, but only for a smaller CHUNK size.
|
||||
// After applying the rotation to a CHUNK size of the output, these rotation values are efficiently rotated further by `rot_vec`.
|
||||
// Unfortunately, this propagates small errors from one chunk to the next.
|
||||
// Therefore, there is a tradeoff between speed (better with small CHUNK sizes) and accuracy (better with large CHUNK sizes).
|
||||
#define CHUNK 128
|
||||
c16_t rot[CHUNK] __attribute__((aligned(32)));
|
||||
for (int i = 0; i < CHUNK; i++) {
|
||||
rot[i] = get_sin_cos(phase);
|
||||
phase += phase_inc;
|
||||
}
|
||||
const c16_t rot_vec = get_sin_cos(CHUNK * phase_inc);
|
||||
while (size > CHUNK) {
|
||||
mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, CHUNK, 14);
|
||||
rxdata_ptr += CHUNK;
|
||||
rotate_cpx_vector(rot, &rot_vec, rot, CHUNK, 14);
|
||||
size -= CHUNK;
|
||||
}
|
||||
mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, size, 14);
|
||||
#else
|
||||
// This code path computes the complex rotation values for the complete OFDM symbol using get_sin_cos().
|
||||
// This is more accurate, but also slower than the code path above.
|
||||
c16_t rot[size] __attribute__((aligned(32)));
|
||||
for (int i = 0; i < size; i++) {
|
||||
rot[i] = get_sin_cos(phase);
|
||||
phase += phase_inc;
|
||||
}
|
||||
mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, size, 14);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -929,6 +929,17 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
|
||||
sampleShift =
|
||||
nr_adjust_synch_ue(fp, ue, gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384);
|
||||
}
|
||||
|
||||
if (get_nrUE_params()->cont_fo_comp && pbchSuccess == 0) {
|
||||
double freq_offset = nr_ue_pbch_freq_offset(fp, estimateSz, dl_ch_estimates);
|
||||
LOG_D(PHY,"compensated frequency offset = %.3f Hz, detected residual frequency offset = %.3f Hz, accumulated frequency offset = %.3f Hz\n", ue->freq_offset, freq_offset, ue->freq_off_acc);
|
||||
|
||||
// PI controller
|
||||
const double PID_P = get_nrUE_params()->freq_sync_P;
|
||||
const double PID_I = get_nrUE_params()->freq_sync_I;
|
||||
ue->freq_offset += freq_offset * PID_P + ue->freq_off_acc * PID_I;
|
||||
ue->freq_off_acc += freq_offset;
|
||||
}
|
||||
}
|
||||
LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__);
|
||||
nr_ue_rrc_measurements(ue, proc, rxdataF);
|
||||
|
||||
@@ -143,31 +143,6 @@ void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *des
|
||||
|
||||
#else
|
||||
|
||||
void add_noise(c16_t **rxdata,
|
||||
const double **r_re,
|
||||
const double **r_im,
|
||||
const double sigma,
|
||||
const int length,
|
||||
const int slot_offset,
|
||||
const double ts,
|
||||
const int delay,
|
||||
const uint16_t pdu_bit_map,
|
||||
const uint16_t ptrs_bit_map,
|
||||
const uint8_t nb_antennas_rx)
|
||||
{
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (int ap = 0; ap < nb_antennas_rx; ap++) {
|
||||
c16_t *rxd = &rxdata[ap][slot_offset + i + delay];
|
||||
rxd->r = r_re[ap][i] + sqrt(sigma / 2) * gaussZiggurat(0.0, 1.0); // convert to fixed point
|
||||
rxd->i = r_im[ap][i] + sqrt(sigma / 2) * gaussZiggurat(0.0, 1.0);
|
||||
/* Add phase noise if enabled */
|
||||
if (pdu_bit_map & ptrs_bit_map) {
|
||||
phase_noise(ts, &rxdata[ap][slot_offset + i + delay].r, &rxdata[ap][slot_offset + i + delay].i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *desc,
|
||||
double *tx_sig_re[NB_ANTENNAS_TX],
|
||||
double *tx_sig_im[NB_ANTENNAS_TX],
|
||||
|
||||
@@ -23,47 +23,41 @@
|
||||
#include "sim.h"
|
||||
|
||||
|
||||
static uint16_t LUTSin[ResolSinCos+1];
|
||||
/* linear phase noise model */
|
||||
void phase_noise(double ts, int16_t * InRe, int16_t * InIm)
|
||||
void phase_noise(double ts, int16_t *InRe, int16_t *InIm)
|
||||
{
|
||||
static uint64_t i=0;
|
||||
int32_t x=0 ,y=0;
|
||||
double fd = 300;//0.01*30000
|
||||
int16_t SinValue = 0, CosValue= 0;
|
||||
double IdxDouble = (double)(i*fd * ts * ResolSinCos * 4);
|
||||
int16_t IdxModulo = ((int32_t)(IdxDouble>0 ? IdxDouble+0.5 : IdxDouble-0.5)) % (ResolSinCos*4);
|
||||
IdxModulo = IdxModulo<0 ? IdxModulo+ResolSinCos*4 : IdxModulo;
|
||||
|
||||
if(IdxModulo<2*ResolSinCos) {//< 2 check for 1st and 2nd
|
||||
if(IdxModulo < ResolSinCos) {// 1st Quadrant
|
||||
SinValue = LUTSin[IdxModulo];
|
||||
CosValue = LUTSin[ResolSinCos-IdxModulo];
|
||||
}
|
||||
else {// 2nd Quadrant
|
||||
SinValue = LUTSin[2*ResolSinCos-IdxModulo];
|
||||
CosValue = -LUTSin[IdxModulo-ResolSinCos];
|
||||
}
|
||||
}
|
||||
else {// 3rd and 4th Quadrant
|
||||
if(IdxModulo < 3*ResolSinCos) {// 3rd Quadrant
|
||||
SinValue = -LUTSin[IdxModulo-2*ResolSinCos];
|
||||
CosValue = -LUTSin[3*ResolSinCos-IdxModulo];
|
||||
}
|
||||
else {//4th Quadrant
|
||||
SinValue = -LUTSin[4*ResolSinCos-IdxModulo];
|
||||
CosValue = LUTSin[IdxModulo-3*ResolSinCos];
|
||||
}
|
||||
}
|
||||
x = ( ((int32_t)InRe[0] * CosValue) - ((int32_t)InIm[0] * SinValue ));
|
||||
y = ( ((int32_t)InIm[0] * CosValue) + ((int32_t)InRe[0] * SinValue ));
|
||||
InRe[0]= (int16_t)(x>>14);
|
||||
InIm[0]= (int16_t)(y>>14);
|
||||
double phase = (double)(i * fd * ts);
|
||||
c16_t rot = get_sin_cos(phase);
|
||||
c16_t val = {.r = *InRe, .i = *InIm};
|
||||
val = c16mulShift(val, rot, 14);
|
||||
*InRe = val.r;
|
||||
*InIm = val.i;
|
||||
i++;
|
||||
}
|
||||
/* Initialisation function for SIN table values */
|
||||
void InitSinLUT( void ) {
|
||||
for ( int i=0; i<(ResolSinCos+1); i++ ) {
|
||||
LUTSin[i] = sin((double)(M_PI*i)/(2*ResolSinCos)) * (1<<14); //Format: Q14
|
||||
|
||||
void add_noise(c16_t **rxdata,
|
||||
const double **r_re,
|
||||
const double **r_im,
|
||||
const double sigma,
|
||||
const int length,
|
||||
const int slot_offset,
|
||||
const double ts,
|
||||
const int delay,
|
||||
const uint16_t pdu_bit_map,
|
||||
const uint16_t ptrs_bit_map,
|
||||
const uint8_t nb_antennas_rx)
|
||||
{
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (int ap = 0; ap < nb_antennas_rx; ap++) {
|
||||
c16_t *rxd = &rxdata[ap][slot_offset + i + delay];
|
||||
rxd->r = r_re[ap][i] + sqrt(sigma / 2) * gaussZiggurat(0.0, 1.0); // convert to fixed point
|
||||
rxd->i = r_im[ap][i] + sqrt(sigma / 2) * gaussZiggurat(0.0, 1.0);
|
||||
/* Add phase noise if enabled */
|
||||
if (pdu_bit_map & ptrs_bit_map) {
|
||||
phase_noise(ts, &rxdata[ap][slot_offset + i + delay].r, &rxdata[ap][slot_offset + i + delay].i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1663,7 +1663,7 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
||||
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
|
||||
chan_desc->enable_dynamic_Doppler = true;
|
||||
fill_channel_desc(chan_desc,nb_tx,
|
||||
nb_rx,
|
||||
nb_taps,
|
||||
@@ -1762,6 +1762,11 @@ void set_channeldesc_name(channel_desc_t *cdesc,char *modelname) {
|
||||
cdesc->model_name=strdup(modelname);
|
||||
}
|
||||
|
||||
void set_channeldesc_direction(channel_desc_t *cdesc, bool is_uplink)
|
||||
{
|
||||
cdesc->is_uplink = is_uplink;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CH_POWER
|
||||
double accumulated_ch_power = 0;
|
||||
int ch_power_count = 0;
|
||||
|
||||
@@ -139,6 +139,8 @@ typedef struct {
|
||||
float Doppler_phase_inc;
|
||||
/// current Doppler phase of each RX antenna (for continuous phase from one block to the next)
|
||||
float *Doppler_phase_cur;
|
||||
/// flag indicating if channel direction is UL or DL
|
||||
bool is_uplink;
|
||||
} channel_desc_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -358,6 +360,7 @@ void free_channel_desc_scm(channel_desc_t *ch);
|
||||
\param module_id identifies the channel model. should be define as a macro in simu.h
|
||||
*/
|
||||
void set_channeldesc_owner(channel_desc_t *cdesc, channelmod_moduleid_t module_id);
|
||||
|
||||
/**
|
||||
\brief This function set a model name to a model descriptor, can be later used to identify a allocated channel model
|
||||
\param cdesc points to the model descriptor
|
||||
@@ -365,6 +368,13 @@ void set_channeldesc_owner(channel_desc_t *cdesc, channelmod_moduleid_t module_i
|
||||
*/
|
||||
void set_channeldesc_name(channel_desc_t *cdesc,char *modelname);
|
||||
|
||||
/**
|
||||
\brief This function set a channel model direction to either uplink or downlink
|
||||
\param cdesc points to the model descriptor
|
||||
\param is_uplink indicates if this channel is applied in uplink (not downlink) direction
|
||||
*/
|
||||
void set_channeldesc_direction(channel_desc_t *cdesc, bool is_uplink);
|
||||
|
||||
/** \fn void get_cexp_doppler(struct complexd *cexp_doppler, channel_desc_t *chan_desc, const uint32_t length)
|
||||
\brief This routine generates the complex exponential to apply the Doppler shift
|
||||
\param cexp_doppler Output with the complex exponential of Doppler shift
|
||||
@@ -379,32 +389,6 @@ void get_cexp_doppler(struct complexd *cexp_doppler, channel_desc_t *chan_desc,
|
||||
*/
|
||||
int random_channel(channel_desc_t *desc, uint8_t abstraction_flag);
|
||||
|
||||
/**
|
||||
\brief Add AWGN noise and phase noise if enabled
|
||||
\param rxdata output data with noise
|
||||
\param r_re real part of input data without noise
|
||||
\param r_im imaginary part of input data without noise
|
||||
\param sigma noise power
|
||||
\param length number of samples to apply the noise
|
||||
\param slot_offset slot offset to start applying the noise
|
||||
\param ts sampling time
|
||||
\param delay introduce delay in terms of number of samples
|
||||
\param pdu_bit_map bitmap indicating presence of optional PDUs
|
||||
\param ptrs_bit_map
|
||||
\param nb_antennas_rx number of receive antennas
|
||||
*/
|
||||
void add_noise(c16_t **rxdata,
|
||||
const double **r_re,
|
||||
const double **r_im,
|
||||
const double sigma,
|
||||
const int length,
|
||||
const int slot_offset,
|
||||
const double ts,
|
||||
const int delay,
|
||||
const uint16_t pdu_bit_map,
|
||||
const uint16_t ptrs_bit_map,
|
||||
const uint8_t nb_antennas_rx);
|
||||
|
||||
/**\fn void multipath_channel(channel_desc_t *desc,
|
||||
double tx_sig_re[NB_ANTENNAS_TX],
|
||||
double tx_sig_im[NB_ANTENANS_TX],
|
||||
@@ -570,16 +554,38 @@ double N_RB2sampling_rate(uint16_t N_RB);
|
||||
double N_RB2channel_bandwidth(uint16_t N_RB);
|
||||
|
||||
/* Linear phase noise model */
|
||||
/*!
|
||||
/**
|
||||
\brief This function produce phase noise and add to input signal
|
||||
\param ts Sampling time
|
||||
\param ts Sampling time
|
||||
\param *Re *Im Real and Imag part of the signal
|
||||
*/
|
||||
//look-up table for the sine (cosine) function
|
||||
#define ResolSinCos 100
|
||||
void InitSinLUT( void );
|
||||
void phase_noise(double ts, int16_t * InRe, int16_t * InIm);
|
||||
void phase_noise(double ts, int16_t *InRe, int16_t *InIm);
|
||||
|
||||
/**
|
||||
\brief Add AWGN noise and phase noise if enabled
|
||||
\param rxdata output data with noise
|
||||
\param r_re real part of input data without noise
|
||||
\param r_im imaginary part of input data without noise
|
||||
\param sigma noise power
|
||||
\param length number of samples to apply the noise
|
||||
\param slot_offset slot offset to start applying the noise
|
||||
\param ts sampling time
|
||||
\param delay introduce delay in terms of number of samples
|
||||
\param pdu_bit_map bitmap indicating presence of optional PDUs
|
||||
\param ptrs_bit_map
|
||||
\param nb_antennas_rx number of receive antennas
|
||||
*/
|
||||
void add_noise(c16_t **rxdata,
|
||||
const double **r_re,
|
||||
const double **r_im,
|
||||
const double sigma,
|
||||
const int length,
|
||||
const int slot_offset,
|
||||
const double ts,
|
||||
const int delay,
|
||||
const uint16_t pdu_bit_map,
|
||||
const uint16_t ptrs_bit_map,
|
||||
const uint8_t nb_antennas_rx);
|
||||
|
||||
void do_DL_sig(sim_t *sim,
|
||||
uint16_t subframe,
|
||||
|
||||
@@ -50,6 +50,8 @@ void rxAddInput(const c16_t *input_sig,
|
||||
uint32_t CirSize,
|
||||
bool add_noise)
|
||||
{
|
||||
static uint64_t last_TS = 0;
|
||||
|
||||
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.
|
||||
@@ -82,42 +84,76 @@ void rxAddInput(const c16_t *input_sig,
|
||||
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;
|
||||
if (channelDesc->is_uplink) {
|
||||
const double dir_ue_sat_x = pos_sat_x - pos_ue_x;
|
||||
const double dir_ue_sat_y = pos_sat_y - pos_ue_y;
|
||||
const double dir_ue_sat_z = pos_sat_z - pos_ue_z;
|
||||
|
||||
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);
|
||||
const double dist_ue_sat = sqrt(dir_ue_sat_x * dir_ue_sat_x + dir_ue_sat_y * dir_ue_sat_y + dir_ue_sat_z * dir_ue_sat_z);
|
||||
const double vel_ue_sat = (vel_sat_x * dir_ue_sat_x + vel_sat_y * dir_ue_sat_y + vel_sat_z * dir_ue_sat_z) / dist_ue_sat;
|
||||
|
||||
double dist_sat_gnb = 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_sat_gnb_x = pos_gnb_x - pos_sat_x;
|
||||
const double dir_sat_gnb_y = pos_gnb_y - pos_sat_y;
|
||||
const double dir_sat_gnb_z = pos_gnb_z - pos_sat_z;
|
||||
|
||||
dist_sat_gnb = sqrt(dir_sat_gnb_x * dir_sat_gnb_x + dir_sat_gnb_y * dir_sat_gnb_y + dir_sat_gnb_z * dir_sat_gnb_z);
|
||||
}
|
||||
|
||||
const double prop_delay = (dist_ue_sat + dist_sat_gnb) / c;
|
||||
if (channelDesc->enable_dynamic_delay)
|
||||
channelDesc->channel_offset = prop_delay * channelDesc->sampling_rate;
|
||||
|
||||
const double f_Doppler_shift_ue_sat = (-vel_ue_sat / c) * channelDesc->center_freq;
|
||||
if (channelDesc->enable_dynamic_Doppler)
|
||||
channelDesc->Doppler_phase_inc = 2 * M_PI * f_Doppler_shift_ue_sat / channelDesc->sampling_rate;
|
||||
|
||||
if(TS - last_TS >= channelDesc->sampling_rate) {
|
||||
last_TS = TS;
|
||||
LOG_D(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z);
|
||||
LOG_D(HW, "Uplink delay %f ms, Doppler shift UE->SAT %f kHz\n", prop_delay * 1000, f_Doppler_shift_ue_sat / 1000);
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
if (channelDesc->enable_dynamic_Doppler)
|
||||
channelDesc->Doppler_phase_inc = 2 * M_PI * f_Doppler_shift_sat_ue / channelDesc->sampling_rate;
|
||||
|
||||
if(TS - last_TS >= channelDesc->sampling_rate) {
|
||||
last_TS = TS;
|
||||
LOG_D(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z);
|
||||
LOG_D(HW, "Downlink delay %f ms, Doppler shift SAT->UE %f kHz\n", prop_delay * 1000, f_Doppler_shift_sat_ue / 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +167,8 @@ void rxAddInput(const c16_t *input_sig,
|
||||
const double noise_per_sample = add_noise ? pow(10,channelDesc->noise_power_dB/10.0) * 256 : 0;
|
||||
const uint64_t dd = channelDesc->channel_offset;
|
||||
const int nbTx=channelDesc->nb_tx;
|
||||
double Doppler_phase_cur = channelDesc->Doppler_phase_cur[rxAnt];
|
||||
Doppler_phase_cur -= 2 * M_PI * round(Doppler_phase_cur / (2 * M_PI));
|
||||
|
||||
for (int i=0; i<nbSamples; i++) {
|
||||
cf_t *out_ptr = after_channel_sig + i;
|
||||
@@ -161,10 +199,10 @@ void rxAddInput(const c16_t *input_sig,
|
||||
#else
|
||||
double complex in = rx_tmp.r + rx_tmp.i * I;
|
||||
#endif
|
||||
double complex out = in * cexp(channelDesc->Doppler_phase_cur[rxAnt] * I);
|
||||
double complex out = in * cexp(Doppler_phase_cur * I);
|
||||
rx_tmp.r = creal(out);
|
||||
rx_tmp.i = cimag(out);
|
||||
channelDesc->Doppler_phase_cur[rxAnt] += channelDesc->Doppler_phase_inc;
|
||||
Doppler_phase_cur += channelDesc->Doppler_phase_inc;
|
||||
}
|
||||
|
||||
out_ptr->r += rx_tmp.r * pathLossLinear + noise_per_sample * gaussZiggurat(0.0, 1.0);
|
||||
@@ -172,6 +210,8 @@ void rxAddInput(const c16_t *input_sig,
|
||||
out_ptr++;
|
||||
}
|
||||
|
||||
channelDesc->Doppler_phase_cur[rxAnt] = Doppler_phase_cur;
|
||||
|
||||
if ( (TS*nbTx)%CirSize+nbSamples <= CirSize )
|
||||
// Cast to a wrong type for compatibility !
|
||||
LOG_D(HW,"Input power %f, output power: %f, channel path loss %f, noise coeff: %f \n",
|
||||
|
||||
@@ -274,6 +274,7 @@ static int allocCirBuf(rfsimulator_state_t *bridge, int sock)
|
||||
}
|
||||
|
||||
set_channeldesc_owner(ptr->channel_model, RFSIMU_MODULEID);
|
||||
set_channeldesc_direction(ptr->channel_model, bridge->role == SIMU_ROLE_SERVER);
|
||||
random_channel(ptr->channel_model,false);
|
||||
LOG_I(HW, "Random channel %s in rfsimulator activated\n", modelname);
|
||||
}
|
||||
@@ -467,6 +468,7 @@ static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt,
|
||||
t->chan_pathloss,
|
||||
0); // noise_power
|
||||
set_channeldesc_owner(newmodel, RFSIMU_MODULEID);
|
||||
set_channeldesc_direction(newmodel, t->role == SIMU_ROLE_SERVER);
|
||||
set_channeldesc_name(newmodel,modelname);
|
||||
random_channel(newmodel,false);
|
||||
channel_desc_t *oldmodel=b->channel_model;
|
||||
|
||||
Reference in New Issue
Block a user