Files
openairinterface5g/openair1/SIMULATION/LOLA_DaF_D42/colabsim.c
T
2013-06-25 09:05:02 +00:00

2127 lines
78 KiB
C

//**************************************************************
// Compile with:
// $ make colabsim
//**************************************************************
#include <string.h>
#include <math.h>
#include <execinfo.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include "SIMULATION/TOOLS/defs.h"
#include "PHY/types.h"
#include "PHY/defs.h"
#include "PHY/vars.h"
#include "MAC_INTERFACE/vars.h"
#include "ARCH/CBMIMO1/DEVICE_DRIVER/vars.h"
#include "SCHED/defs.h"
#include "SCHED/vars.h"
#include "LAYER2/MAC/vars.h"
#include "OCG_vars.h"
#ifndef RA_RNTI
#define RA_RNTI 0xfffe
#endif
typedef unsigned char bool;
const bool false = 0;
const bool true = 1;
#define BW 7.68
#define N_PRB 25
#define RBG_SIZE 2
#define NID_CELL 0
#define MAX_RELAYS 8
#define MAX_HARQ_ROUNDS 4
#define MAX_FRAMES 2*MAX_HARQ_ROUNDS+1
const u8 cp_type = 0; // Normal cyclic prefix
const u8 n_txantenna_ch = 1; // Number of CH transmit antennas
const u8 n_rxantenna_ch = 1; // Number of CH receive antennas
const u8 n_txantenna_mr = 1; // Number of MR transmit antennas
const u8 n_rxantenna_mr = 1; // Number of MR receive antennas
const u8 oversampling = 1;
const u8 subframe_hop1 = 1; // Subframe for CH1 PDCCH+PDSCH transmission
const u8 subframe_hop2 = 7; // Subframe for MR PDU to CH2
const u8 n_pdcch_symbols = 3; // Number of PDCCH symbols in DL subframes
typedef enum {
analysis_single, // Simulate one SNR point
analysis_snrsweep_a, // Sweep SNR of first relay from negative to positive
// for both hops
analysis_snrsweep_b, // Sweep SNR of first relay from negative to positive
// for hop 1 and from postive to negative for hop 2
analysis_snrsweep_c
} analysis_t;
typedef enum {
strategy_wait_all, // Wait for all relays to decode before starting hop 2
strategy_wait_one // Start hop 2 when one relay has decoded
} strategy_t;
// Structure for command line parsed arguments
typedef struct {
bool debug_output; // Output MATLAB signal files
int verbose; // Verbosity level
analysis_t analysis; // Analysis mode
int range; // Sweep range
double step; // Sweep step size
strategy_t strategy; // HARQ strategy
int n_relays; // Number of relays
int n_pdu; // Number of MAC PDUs to simulate
int n_harq; // Maximum number of HARQ rounds
int mcs_hop1; // MCS for hop 1
int mcs_hop2; // MCS for hop 2
int n_prb_hop1; // Number of PRB utilized in hop 1
int n_prb_hop2; // Number of PRB utilized in hop 2
bool autorb; // Reduce number of PRB to balance TBS
SCM_t channel_model; // Channel model
double channel_correlation; // Channel reutilization factor
double snr_hop1[MAX_RELAYS]; // SNR used in hop 1 for all links
double snr_hop2[MAX_RELAYS]; // SNR used in hop 2 for all links
const char* results_fn; // File to save simulation results to
} args_t;
// Structure containing link simulation results for one test
// Note: mcs_hop*, tbs_hop*, n_prb_hop* are matrices containing values for each
// transmission attempt in the simulation. The first index is the MAC PDU
// index and the second is the HARQ round index. Currently no AMC is
// implemented, and all these values are the same for each MAC PDU.
// Note: The meaning of n_harq_success_hop1 is dependent on the HARQ strategy.
// In HARQ strategy 1, both relays must be decode.
// Other HARQ strategies are not implemented yet.
typedef struct {
int n_relays; // number of relays
int n_pdu; // number of transmitted MAC PDUs
int n_harq; // number of HARQ rounds
SCM_t channel_model; // used channel model
double* snr_hop1; // SNRs for each link in hop 1
double* snr_hop2; // SNRs for each link in hop 2
int** mcs_hop1; // MCS used in hop 1
int** mcs_hop2; // MCS used in hop 2
int** tbs_hop1; // transport block size for hop 1
int** tbs_hop2; // transport block size for hop 2
int** n_prb_hop1; // number of used PRBs in hop 1
int** n_prb_hop2; // number of used PRBs in hop 2
int n_frames_hop1; // number of transmitted LTE frames in hop 1
int n_frames_hop2; // number of transmitted LTE frames in hop 2
int n_bits_hop1; // number of correctly received information bits over hop 1
int n_bits_hop2; // number of correctly received information bits over hop 2
double ber_hop1[MAX_RELAYS]; // raw BER in hop 1
double ber_hop2; // raw BER in hop 2
int n_pdu_success_hop1; // number of correctly received MAC PDUs in hop 1
int n_pdu_success_hop2; // number of correctly received MAC PDUs in hop 2
int n_harq_tries_hop1[MAX_HARQ_ROUNDS]; // number of transmitted MAC PDUs in each HARQ round in hop 1
int n_harq_success_hop1[MAX_HARQ_ROUNDS]; // number of successfully decoded MAC PDUs in each HARQ round in hop 1
int n_harq_tries_hop2[MAX_HARQ_ROUNDS]; // number of transmitted MAC PDUs in each HARQ round in hop 2
int n_harq_success_hop2[MAX_HARQ_ROUNDS]; // number of successfully decoded MAC PDUs in each HARQ round in hop 2
int n_transmissions[MAX_HARQ_ROUNDS][MAX_HARQ_ROUNDS]; // PDF of number of transmissions in the two hops for
// MAC PDUs correctly received at CH2
int* relay_activity; // PDF of relay activity, [1]: MR1 active, [2]: MR2 active, [3]: MR1+MR2 active
} results_t;
// Relay role in distributed Alamouti coding
typedef enum {
RELAY_ROLE_STANDARD, // Relay sends [ x1 x2 ]
RELAY_ROLE_ALTERNATE // Relay sends [-x2* x1*]
} relay_role_t;
typedef struct {
double* s_re[1];
double* s_im[1];
double* r_re[1];
double* r_im[1];
double* r_re_t[1];
double* r_im_t[1];
} channel_vars_t;
typedef struct {
channel_vars_t* cvars;
channel_desc_t* channel;
} sh_channel_t;
// Simulation context
typedef struct {
LTE_DL_FRAME_PARMS* frame_parms;
PHY_VARS_eNB* phy_vars_ch_src;
PHY_VARS_eNB* phy_vars_ch_dest;
PHY_VARS_UE** phy_vars_mr;
sh_channel_t** channels_hop1;
sh_channel_t** channels_hop2;
s32* rxdata[1];
double* snr_hop1;
double* snr_hop2;
int mcs_hop1;
int mcs_hop2;
u32 tbs_hop1;
u32 tbs_hop2;
u32 tbs_col;
u16 rnti_hop1;
u16 rnti_hop2;
int input_buffer_length;
u8* input_buffer;
int mr_buffer_length;
u8* mr_buffer[MAX_RELAYS];
u32 n_coded_bits_hop1;
u32 n_coded_bits_hop2;
int n_ber_frames_hop1[MAX_RELAYS];
int n_ber_frames_hop2;
u8 n_avail_pdcch_symbols;
u8 subframe_hop1;
u8 subframe_hop2;
u8 harq_pid_hop2;
} context_t;
void transmit_one_pdu(args_t* args, context_t* context, int pdu, results_t* results);
int parse_args(int argc, char** argv, args_t* args);
int parse_channel_model(const char* str, SCM_t* model);
bool parse_snr(const char* str, double* snr, int n);
void print_usage(const char* prog);
void print_channel_usage();
void signal_handler(int sig);
void setup_single(double** snrs, int* n_tests, double* snr_hop1, double* snr_hop2, int n_relays);
void setup_snrsweep_a(double** snrs, int* n_tests, double* snr_hop1, double* snr_hop2, int n_relays, double step, int start, int end);
void setup_snrsweep_b(double** snrs, int* n_tests, double* snr_hop1, double* snr_hop2, int n_relays, double step, int start, int end);
void setup_snrsweep_c(double** snrs, int* n_tests, double* snr_hop1, double* snr_hop2, int n_relays, double step, int start, int end);
void setup_frame_params(LTE_DL_FRAME_PARMS* frame_parms, unsigned char transmission_mode);
void setup_phy_vars(LTE_DL_FRAME_PARMS* frame_parms, PHY_VARS_eNB* phy_vars_ch_src,
PHY_VARS_UE** phy_vars_mr, PHY_VARS_eNB* phy_vars_ch_dest, int n_relays);
u16 rballoc_type0(int n_rb, int rbg_size);
void setup_broadcast_dci(DCI_ALLOC_t* dci, u16 rnti, int harq_round, int mcs, int n_rb);
void setup_distributed_dci(DCI_ALLOC_t* dci, u16 rnti, int harq_round, int mcs, int n_rb);
void alloc_broadcast_transport_channel(PHY_VARS_eNB* phy_vars_ch, PHY_VARS_UE** phy_vars_mr, int n_relays, u16 rnti);
void free_broadcast_transport_channel(PHY_VARS_eNB* phy_vars_ch, PHY_VARS_UE** phy_vars_mr, int n_relays);
void alloc_distributed_transport_channel(PHY_VARS_eNB* phy_vars_ch, PHY_VARS_UE** phy_vars_mr, int n_relays, u16 rnti);
void free_distributed_transport_channel(PHY_VARS_eNB* phy_vars_ch, PHY_VARS_UE** phy_vars_mr, int n_relays);
void ofdm_modulation(mod_sym_t** tx_f, s32** tx_t, LTE_DL_FRAME_PARMS* frame_parms, u8 subframe, u8 nsymb);
channel_vars_t alloc_channel_vars(LTE_DL_FRAME_PARMS* frame_parms);
void free_channel_vars(channel_vars_t v);
sh_channel_t* alloc_sh_channel(channel_vars_t* cvars, SCM_t channel_model, int n_txantennas, int n_rxantennas, double channel_correlation);
void free_sh_channel(sh_channel_t* c);
void transmit_subframe(sh_channel_t* channel, s32** src, LTE_DL_FRAME_PARMS* frame_parms, u8 subframe, u8 nsymb, double ampl, bool accumulate);
void deliver_subframe(sh_channel_t* channel, s32** dst, LTE_DL_FRAME_PARMS* frame_parms, u8 subframe, u8 nsymb, double stddev);
void ofdm_fep(PHY_VARS_UE* phy_vars_mr, u8 subframe);
int rx_dlsch_symbol(PHY_VARS_UE* phy_vars, u8 subframe, u8 symbol, u8 first_symbol);
u32 get_ulsch_G(LTE_UE_ULSCH_t *ulsch, u8 harq_pid);
double compute_ber_soft(u8* ref, s16* rec, int n);
void print_dlsch_eNB_stats(LTE_eNB_DLSCH_t* d);
void print_dlsch_ue_stats(LTE_UE_DLSCH_t* d);
void print_ulsch_ue_stats(LTE_UE_ULSCH_t* d);
void print_ulsch_eNB_stats(LTE_eNB_ULSCH_t* d);
int block_valid(u8* ref, u8* rec, int n);
void init_results(results_t* r, args_t* a);
void clear_results(results_t* r);
void free_results(results_t* r);
void print_results(results_t* r);
void write_results_header(FILE* f, results_t* r, int n_tests);
void write_results_data(FILE* f, results_t* r);
double calc_delay(int* n_frames, int n_harq);
// Function declarations missing in LTE_TRANSPORT/proto.h:
u8 pdcch_alloc2ul_subframe(LTE_DL_FRAME_PARMS* frame_parms, u8 n);
u8 ul_subframe2pdcch_alloc_subframe(LTE_DL_FRAME_PARMS* frame_parms, u8 n);
int main(int argc, char **argv) {
args_t args;
results_t results;
context_t context;
DCI_ALLOC_t dci_hop1;
DCI_ALLOC_t dci_hop2;
channel_vars_t channel_vars;
double* snrs;
int n_tests;
int test; // Current test
int pdu; // Current MAC PDU
int k;
bool store_results = false;
FILE* results_file = 0;
// Parse arguments
k = parse_args(argc, argv, &args);
if(k == 1) {
print_usage(argv[0]);
exit(1);
}
else if(k == 2) {
print_channel_usage();
exit(1);
}
// Check argument bounds
if(args.n_relays > MAX_RELAYS) {
printf("Too many relays, increase MAX_RELAYS\n");
exit(1);
}
if(args.n_harq > MAX_HARQ_ROUNDS) {
printf("Too many HARQ rounds, increase MAX_HARQ_ROUNDS\n");
exit(1);
}
// General setup
signal(SIGSEGV, signal_handler);
randominit(0);
set_taus_seed(0);
// Allocate memory for frame parameters and node structures
context.frame_parms = malloc(sizeof(LTE_DL_FRAME_PARMS));
memset(context.frame_parms, 0, sizeof(LTE_DL_FRAME_PARMS));
context.phy_vars_ch_src = malloc(sizeof(PHY_VARS_eNB));
context.phy_vars_ch_dest = malloc(sizeof(PHY_VARS_eNB));
context.phy_vars_mr = malloc(args.n_relays*sizeof(PHY_VARS_UE*));
for(k = 0; k < args.n_relays; k++) {
context.phy_vars_mr[k] = malloc(sizeof(PHY_VARS_UE));
memset(context.phy_vars_mr[k], 0, sizeof(PHY_VARS_UE));
}
memset(context.phy_vars_ch_src, 0, sizeof(PHY_VARS_eNB));
memset(context.phy_vars_ch_dest, 0, sizeof(PHY_VARS_eNB));
// Initialize log
logInit();
// Initialize result data
init_results(&results, &args);
// Allocate channel structures
context.channels_hop1 = malloc(args.n_relays*sizeof(sh_channel_t*));
context.channels_hop2 = malloc(args.n_relays*sizeof(sh_channel_t*));
memset(context.channels_hop1, 0, args.n_relays*sizeof(sh_channel_t*));
memset(context.channels_hop2, 0, args.n_relays*sizeof(sh_channel_t*));
// Setup analysis structures
switch(args.analysis) {
case analysis_single:
setup_single(&snrs, &n_tests, args.snr_hop1, args.snr_hop2, args.n_relays);
break;
case analysis_snrsweep_a:
setup_snrsweep_a(&snrs, &n_tests, args.snr_hop1, args.snr_hop2, args.n_relays, args.step, -args.range, args.range);
break;
case analysis_snrsweep_b:
setup_snrsweep_b(&snrs, &n_tests, args.snr_hop1, args.snr_hop2, args.n_relays, args.step, -args.range, args.range);
break;
case analysis_snrsweep_c:
setup_snrsweep_c(&snrs, &n_tests, args.snr_hop1, args.snr_hop2, args.n_relays, args.step, -args.range, args.range);
break;
}
// Open results file (if requested)
if(args.results_fn) {
store_results = true;
results_file = fopen(args.results_fn, "w");
if(!results_file) {
perror("fopen");
exit(1);
}
}
if(store_results) {
write_results_header(results_file, &results, n_tests);
}
// Setup PHY structures
setup_frame_params(context.frame_parms, 1);
setup_phy_vars(context.frame_parms, context.phy_vars_ch_src, context.phy_vars_mr, context.phy_vars_ch_dest, args.n_relays);
// Setup simulation context
context.rnti_hop1 = 0x1515;
context.rnti_hop2 = 0x1516;
context.mcs_hop1 = args.mcs_hop1;
context.mcs_hop2 = args.mcs_hop2;
context.n_avail_pdcch_symbols = n_pdcch_symbols;
context.subframe_hop1 = subframe_hop1;
context.subframe_hop2 = subframe_hop2;
// Allocate temporary signal structures
context.rxdata[0] = malloc(10*context.frame_parms->samples_per_tti);
// Allocate first hop transport channel
alloc_broadcast_transport_channel(context.phy_vars_ch_src, context.phy_vars_mr, args.n_relays, context.rnti_hop1);
// Allocate second hop transport channel
alloc_distributed_transport_channel(context.phy_vars_ch_dest, context.phy_vars_mr, args.n_relays, context.rnti_hop2);
// Setup channel structures
channel_vars = alloc_channel_vars(context.frame_parms);
for(k = 0; k < args.n_relays; k++) {
context.channels_hop1[k] = alloc_sh_channel(&channel_vars, args.channel_model, n_txantenna_ch, n_rxantenna_mr, args.channel_correlation);
context.channels_hop2[k] = alloc_sh_channel(&channel_vars, args.channel_model, n_txantenna_mr, n_rxantenna_ch, args.channel_correlation);
}
// Create broadcast DCI and generate transport channel parameters,
// in order to determine hop 1 transfer block size and number of coded bits
setup_broadcast_dci(&dci_hop1, context.rnti_hop1, 0, args.mcs_hop1, args.n_prb_hop1);
generate_eNB_dlsch_params_from_dci(subframe_hop1, dci_hop1.dci_pdu,
context.rnti_hop1, format1, context.phy_vars_ch_src->dlsch_eNB[0], context.frame_parms,
SI_RNTI, RA_RNTI, P_RNTI,
context.phy_vars_ch_src->eNB_UE_stats[0].DL_pmi_single);
context.tbs_hop1 = context.phy_vars_ch_src->dlsch_eNB[0][0]->harq_processes[0]->TBS;
context.n_coded_bits_hop1 = get_G(context.frame_parms, context.phy_vars_ch_src->dlsch_eNB[0][0]->nb_rb,
context.phy_vars_ch_src->dlsch_eNB[0][0]->rb_alloc,
get_Qm(context.phy_vars_ch_src->dlsch_eNB[0][0]->harq_processes[0]->mcs),
context.n_avail_pdcch_symbols, subframe_hop1);
// Create distributed DCI and generate transport channel parameters,
// in order to determine hop 2 transfer block size and number of coded bits
context.harq_pid_hop2 = subframe2harq_pid(context.frame_parms, 0, subframe_hop2);
setup_distributed_dci(&dci_hop2, context.rnti_hop2, 0, args.mcs_hop2, args.n_prb_hop2);
generate_ue_ulsch_params_from_dci(dci_hop2.dci_pdu, context.rnti_hop2,
ul_subframe2pdcch_alloc_subframe(context.frame_parms, subframe_hop2),
format0, context.phy_vars_mr[0], SI_RNTI, RA_RNTI, P_RNTI, 0, 0);
context.tbs_hop2 = context.phy_vars_mr[0]->ulsch_ue[0]->harq_processes[context.harq_pid_hop2]->TBS;
context.n_coded_bits_hop2 = get_ulsch_G(context.phy_vars_mr[0]->ulsch_ue[0], context.harq_pid_hop2);
if(args.verbose > 1) {
print_dlsch_eNB_stats(context.phy_vars_ch_src->dlsch_eNB[0][0]);
print_ulsch_ue_stats(context.phy_vars_mr[0]->ulsch_ue[0]);
dump_dci(context.frame_parms, &dci_hop1);
dump_dci(context.frame_parms, &dci_hop2);
}
printf("Hop 1: TBS=%d, G=%d, rate=%f. Hop 2: TBS=%d, G=%d, rate=%f\n",
context.tbs_hop1, context.n_coded_bits_hop1, (float)context.tbs_hop1/(float)context.n_coded_bits_hop1,
context.tbs_hop2, context.n_coded_bits_hop2, (float)context.tbs_hop2/(float)context.n_coded_bits_hop2);
context.tbs_col = context.tbs_hop1 < context.tbs_hop2 ? context.tbs_hop1 : context.tbs_hop2;
// Allocate input buffer
context.input_buffer_length = context.tbs_hop1/8;
context.input_buffer = malloc(context.input_buffer_length+4);
memset(context.input_buffer, 0, context.input_buffer_length+4);
if(args.verbose > 0)
printf("Input buffer: %d bytes\n", context.input_buffer_length);
// Allocate MR data buffers
context.mr_buffer_length = context.tbs_hop2/8;
for(k = 0; k < args.n_relays; k++) {
context.mr_buffer[k] = malloc(context.mr_buffer_length+4);
memset(context.mr_buffer[k], 0, context.mr_buffer_length+4);
}
for(test = 0; test < n_tests; test++) {
// Set SNRs
context.snr_hop1 = &snrs[2*args.n_relays*test];
context.snr_hop2 = &snrs[2*args.n_relays*test + args.n_relays];
// Clear results
clear_results(&results);
for(k = 0; k < args.n_relays; k++) {
context.n_ber_frames_hop1[k] = 0;
}
context.n_ber_frames_hop2 = 0;
results.snr_hop1 = context.snr_hop1;
results.snr_hop2 = context.snr_hop2;
// Print test info.
printf("\n*** Test %d/%d ***\n", test+1, n_tests);
for(pdu = 0; pdu < args.n_pdu; pdu++) {
transmit_one_pdu(&args, &context, pdu, &results);
}
// Compute average BER for the links
for(k = 0; k < args.n_relays; k++)
if(context.n_ber_frames_hop1[k] > 0)
results.ber_hop1[k] /= (double)context.n_ber_frames_hop1[k];
else
results.ber_hop1[k] = 0.0;
if(context.n_ber_frames_hop2 > 0)
results.ber_hop2 /= (double)context.n_ber_frames_hop2;
else
results.ber_hop2 = 0.0;
print_results(&results);
if(store_results)
write_results_data(results_file, &results);
}
if(store_results)
fclose(results_file);
free_results(&results);
free(context.input_buffer);
free(context.rxdata[0]);
free_broadcast_transport_channel(context.phy_vars_ch_src, context.phy_vars_mr, args.n_relays);
free_distributed_transport_channel(context.phy_vars_ch_dest, context.phy_vars_mr, args.n_relays);
free(snrs);
for(k = 0; k < args.n_relays; k++) {
free_sh_channel(context.channels_hop1[k]);
free_sh_channel(context.channels_hop2[k]);
}
free_channel_vars(channel_vars);
free(context.channels_hop1);
free(context.channels_hop2);
free(context.phy_vars_ch_src);
free(context.phy_vars_ch_dest);
for(k = 0; k < args.n_relays; k++)
free(context.phy_vars_mr[k]);
free(context.phy_vars_mr);
free(context.frame_parms);
return 0;
}
void transmit_one_pdu(args_t* args, context_t* context, int pdu, results_t* results)
{
// State variables:
int frame = 0; // Current LTE frame
bool hop1_active = false;
bool hop2_active = false;
bool start_hop2;
int round_hop1 = 0; // Current HARQ round in hop 1
int round_hop2 = 0; // Current HARQ round in hop 2
int rounds_hop1; // Number of rounds in hop 1 before hop 2 started
int rounds_hop2; // Number of rounds in hop 2 until CH decoded
relay_role_t relay_role[MAX_RELAYS]; // the roles of the relays in Alamouti coding
bool decoded_at_all_mr;
bool decoded_at_mr[MAX_RELAYS];
bool activate_mr[MAX_RELAYS];
bool decoded_at_ch;
LTE_DL_FRAME_PARMS* frame_parms = context->frame_parms;
PHY_VARS_eNB* phy_vars_ch_src = context->phy_vars_ch_src;
PHY_VARS_eNB* phy_vars_ch_dest = context->phy_vars_ch_dest;
PHY_VARS_UE** phy_vars_mr = context->phy_vars_mr;
DCI_ALLOC_t dci_hop1;
DCI_ALLOC_t dci_hop2;
int n_symbols_per_slot = (cp_type == 0 ? 7 : 6);
int pilot1_symbol = (cp_type == 0 ? 4 : 3);
// Temporary variables
int n_re_hop1;
int n_re_hop2;
int n_active_relays;
u8 n_used_pdcch_symbols;
u32 tx_energy;
//double awgn_stddev;
double tx_ampl;
double raw_ber;
double awgn_stddev;
bool accumulate_at_rx;
int i;
int k;
int l;
int n_iter;
// Temporary strings
char fnbuf[80];
char varbuf[80];
if(args->verbose == 0) {
printf("Transmitting MAC PDU %d\r", pdu);
fflush(stdout);
} else
printf("Transmitting MAC PDU %d\n", pdu);
for(k = 0; k < args->n_relays; k++)
decoded_at_mr[k] = false;
decoded_at_ch = false;
// Set role of each relay (alternating STANDARD and ALTERNATE)
for(k = 0; k < args->n_relays; k++) {
relay_role[k] = k & 1;
}
// Generate input data
for(k = 0; k < context->input_buffer_length; k++)
context->input_buffer[k] = (u8)(taus()&0xff);
hop1_active = true;
while(hop1_active || hop2_active) {
if(args->verbose > 0) {
fprintf(stderr, "LTE frame %d: hop 1 %s, hop 2 %s, decoded at relays: ", frame,
hop1_active ? "active" : "inactive",
hop2_active ? "active" : "inactive");
for(k = 0; k < args->n_relays; k++)
fprintf(stderr, "%s", decoded_at_mr[k] ? "X" : ".");
fprintf(stderr, "\n");
}
for(k = 0; k < args->n_relays; k++)
activate_mr[k] = false;
// Do hop 1 transmission if hop 1 is active
if(hop1_active) {
// Clear txdataF vector
memset(&phy_vars_ch_src->lte_eNB_common_vars.txdataF[0][0][0], 0,
FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t));
// Fill results
results->mcs_hop1[pdu][round_hop1] = context->mcs_hop1;
results->tbs_hop1[pdu][round_hop1] = context->tbs_hop1;
results->n_prb_hop1[pdu][round_hop1] = args->n_prb_hop1;
// Create first hop DCI
setup_broadcast_dci(&dci_hop1, context->rnti_hop1, round_hop1, context->mcs_hop1, args->n_prb_hop1);
if(args->verbose > 1)
dump_dci(frame_parms, &dci_hop1);
// Generate eNB transport channel parameters
generate_eNB_dlsch_params_from_dci(context->subframe_hop1, dci_hop1.dci_pdu,
context->rnti_hop1, format1, phy_vars_ch_src->dlsch_eNB[0], frame_parms,
SI_RNTI, RA_RNTI, P_RNTI,
phy_vars_ch_src->eNB_UE_stats[0].DL_pmi_single);
// Create PDCCH
n_used_pdcch_symbols = generate_dci_top(1, 0, &dci_hop1, 0, 1024, frame_parms,
phy_vars_ch_src->lte_eNB_common_vars.txdataF[0], context->subframe_hop1);
if(n_used_pdcch_symbols > context->n_avail_pdcch_symbols) {
printf("Need %d PDCCH symbols\n", n_used_pdcch_symbols);
exit(1);
}
// Encode source data
if(dlsch_encoding(context->input_buffer, frame_parms, context->n_avail_pdcch_symbols,
phy_vars_ch_src->dlsch_eNB[0][0], context->subframe_hop1) < 0)
exit(-1);
// Scramble data
dlsch_scrambling(frame_parms, context->n_avail_pdcch_symbols,
phy_vars_ch_src->dlsch_eNB[0][0], context->n_coded_bits_hop1, 0, context->subframe_hop1 << 1);
// Modulate data
n_re_hop1 = dlsch_modulation(phy_vars_ch_src->lte_eNB_common_vars.txdataF[0],
1024, context->subframe_hop1, frame_parms, context->n_avail_pdcch_symbols,
phy_vars_ch_src->dlsch_eNB[0][0]);
if(args->verbose > 0)
printf("Hop 1, HARQ round %d: %d coded bits, Modulated %d REs\n", round_hop1, context->n_coded_bits_hop1, n_re_hop1);
if(args->verbose > 2)
print_dlsch_eNB_stats(phy_vars_ch_src->dlsch_eNB[0][0]);
// Generate pilots
generate_pilots(phy_vars_ch_src, phy_vars_ch_src->lte_eNB_common_vars.txdataF[0],
1024, LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
// OFDM modulation
ofdm_modulation(phy_vars_ch_src->lte_eNB_common_vars.txdataF[0],
phy_vars_ch_src->lte_eNB_common_vars.txdata[0],
frame_parms, context->subframe_hop1, frame_parms->symbols_per_tti/2*3);
// Compute transmitter signal energy ( E{abs(X)^2} )
tx_energy = signal_energy(&phy_vars_ch_src->lte_eNB_common_vars.txdata[0][0]
[context->subframe_hop1*frame_parms->samples_per_tti], frame_parms->samples_per_tti);
// Transmit over channel
for(k = 0; k < args->n_relays; k++) {
//awgn_stddev = sqrt((double)tx_energy*((double)frame_parms->ofdm_symbol_size/(args->n_prb_hop1*12))/pow(10.0, ((double)context->snr_hop1[k])/10.0)/2.0);
awgn_stddev = sqrt((double)tx_energy)/pow(10.0, ((double)context->snr_hop1[k])/20.0);
tx_ampl = awgn_stddev/sqrt((double)tx_energy)*pow(10.0, ((double)context->snr_hop1[k])/20.0);
//printf("hop 1: E=%d, ampl=%f, awgn=%f\n", tx_energy, tx_ampl, awgn_stddev);
transmit_subframe(context->channels_hop1[k],
phy_vars_ch_src->lte_eNB_common_vars.txdata[0],
frame_parms, context->subframe_hop1, frame_parms->symbols_per_tti+1, tx_ampl, false);
deliver_subframe(context->channels_hop1[k],
phy_vars_mr[k]->lte_ue_common_vars.rxdata,
frame_parms, context->subframe_hop1, frame_parms->symbols_per_tti+1, awgn_stddev);
}
results->n_frames_hop1++;
if(!hop2_active)
results->n_harq_tries_hop1[round_hop1]++;
// Decode at all relays that have not yet decoded
for(k = 0; k < args->n_relays; k++) {
if(decoded_at_mr[k])
continue;
// Front end processor up to first pilot
for(l = 0; l <= pilot1_symbol; l++)
slot_fep(phy_vars_mr[k], l, context->subframe_hop1<<1, 0, 0);
// Skip decoding of DCI
phy_vars_mr[k]->lte_ue_pdcch_vars[0]->crnti = context->rnti_hop1;
phy_vars_mr[k]->lte_ue_pdcch_vars[0]->num_pdcch_symbols = context->n_avail_pdcch_symbols;
generate_ue_dlsch_params_from_dci(context->subframe_hop1, dci_hop1.dci_pdu, context->rnti_hop1,
format1, phy_vars_mr[k]->dlsch_ue[0], frame_parms, SI_RNTI, RA_RNTI, P_RNTI);
// Receive DLSCH data
// Front end processor up to second pilot
for(l = pilot1_symbol+1; l < n_symbols_per_slot; l++)
slot_fep(phy_vars_mr[k], l, context->subframe_hop1<<1, 0, 0);
slot_fep(phy_vars_mr[k], 0, (context->subframe_hop1<<1)+1, 0, 0);
// Receive DLSCH for first slot
if(rx_dlsch_symbol(phy_vars_mr[k], context->subframe_hop1, context->n_avail_pdcch_symbols, 1) == -1)
break;
for(l = context->n_avail_pdcch_symbols + 1; l < n_symbols_per_slot; l++)
if(rx_dlsch_symbol(phy_vars_mr[k], context->subframe_hop1, l, 0) == -1)
break;
// Front end processor up to third pilot
for(l = 1; l <= pilot1_symbol; l++)
slot_fep(phy_vars_mr[k], l, (context->subframe_hop1<<1)+1, 0, 0);
// Receive DLSCH up to third pilot
for(l = n_symbols_per_slot; l < n_symbols_per_slot+pilot1_symbol; l++)
if(rx_dlsch_symbol(phy_vars_mr[k], context->subframe_hop1, l, 0) == -1)
break;
// Front end processor for rest of subframe
for(l = pilot1_symbol+1; l < n_symbols_per_slot; l++)
slot_fep(phy_vars_mr[k], l, (context->subframe_hop1<<1)+1, 0, 0);
slot_fep(phy_vars_mr[k], 0, (context->subframe_hop1<<1)+2, 0, 0);
// Receive DLSCH for rest of subframe
for(l = n_symbols_per_slot+pilot1_symbol; l < 2*n_symbols_per_slot; l++)
if(rx_dlsch_symbol(phy_vars_mr[k], context->subframe_hop1, l, 0) == -1)
break;
// Compute raw bit error rate
raw_ber = compute_ber_soft(phy_vars_ch_src->dlsch_eNB[0][0]->e,
phy_vars_mr[k]->lte_ue_pdsch_vars[0]->llr[0], context->n_coded_bits_hop1);
results->ber_hop1[k] += raw_ber;
context->n_ber_frames_hop1[k]++;
if(args->verbose > 0)
printf("Received %d bits at MR %d, raw BER: %f\n", context->n_coded_bits_hop1, k, raw_ber);
// Unscramble received bits
dlsch_unscrambling(frame_parms, phy_vars_mr[k]->lte_ue_pdcch_vars[0]->num_pdcch_symbols,
phy_vars_mr[k]->dlsch_ue[0][0], context->n_coded_bits_hop1, phy_vars_mr[k]->lte_ue_pdsch_vars[0]->llr[0],
0, context->subframe_hop1 << 1);
// Decode received bits
n_iter = dlsch_decoding(phy_vars_mr[k]->lte_ue_pdsch_vars[0]->llr[0],
frame_parms, phy_vars_mr[k]->dlsch_ue[0][0], context->subframe_hop1,
phy_vars_mr[k]->lte_ue_pdcch_vars[0]->num_pdcch_symbols);
if(args->verbose > 2)
print_dlsch_ue_stats(phy_vars_mr[k]->dlsch_ue[0][0]);
if(n_iter <= MAX_TURBO_ITERATIONS) {
if(args->verbose > 0)
printf("Successfully decoded at MR %d\n", k);
activate_mr[k] = true;
// copy received data to intermediate buffer
memcpy(context->mr_buffer[k], phy_vars_mr[k]->dlsch_ue[0][0]->harq_processes[0]->b, context->tbs_col>>3);
//memset(&context->mr_buffer[k][context->tbs_col>>3], 0, context->mr_buffer_length+4-(context->tbs_col>>3));
}
}
// Write debug signals if required
if(args->debug_output) {
if(round_hop1 == 0)
write_output("hop1_e.m", "e", phy_vars_ch_src->dlsch_eNB[0][0]->e, context->n_coded_bits_hop1, 1, 4);
snprintf(fnbuf, 80, "hop1_r%d_ch_txdataFv.m", round_hop1);
snprintf(varbuf, 80, "hop1_r%d_ch_txdataF", round_hop1);
write_output(fnbuf, varbuf, phy_vars_ch_src->lte_eNB_common_vars.txdataF[0][0],
FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX, 1, 1);
snprintf(fnbuf, 80, "hop1_r%d_ch_txdatav.m", round_hop1);
snprintf(varbuf, 80, "hop1_r%d_ch_txdata", round_hop1);
write_output(fnbuf, varbuf, phy_vars_ch_src->lte_eNB_common_vars.txdata[0][0],
10*frame_parms->samples_per_tti, 1, 1);
for(k = 0; k < args->n_relays; k++) {
snprintf(fnbuf, 80, "hop1_r%d_mr%d_rxdatav.m", round_hop1, k);
snprintf(varbuf, 80, "hop1_r%d_mr%d_rxdata", round_hop1, k);
write_output(fnbuf, varbuf, phy_vars_mr[k]->lte_ue_common_vars.rxdata[0],
10*frame_parms->samples_per_tti, 1, 1);
snprintf(fnbuf, 80, "hop1_r%d_mr%d_rxdataFv.m", round_hop1, k);
snprintf(varbuf, 80, "hop1_r%d_mr%d_rxdataF", round_hop1, k);
write_output(fnbuf, varbuf, phy_vars_mr[k]->lte_ue_common_vars.rxdataF[0],
2*frame_parms->ofdm_symbol_size*2*n_symbols_per_slot, 2, 1);
}
}
}
if(hop2_active) {
// Fill results
results->mcs_hop2[pdu][round_hop2] = context->mcs_hop2;
results->tbs_hop2[pdu][round_hop2] = context->tbs_hop2;
results->n_prb_hop2[pdu][round_hop2] = args->n_prb_hop2;
l = 0;
for(k = args->n_relays-1; k >= 0; k--)
if(decoded_at_mr[k])
l = (l << 1) + 1;
else
l = (l << 1);
results->relay_activity[l]++;
// create second hop dci
setup_distributed_dci(&dci_hop2, context->rnti_hop2, round_hop2, context->mcs_hop2, args->n_prb_hop2);
if(args->verbose > 1)
dump_dci(frame_parms, &dci_hop2);
if(args->verbose > 0)
printf("Hop 2, HARQ round %d\n", round_hop2);
// Clear eNB receive vector
memset(phy_vars_ch_dest->lte_eNB_common_vars.rxdata[0][0], 0, FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(int));
// Determine how many relays are active for this transmission, split the total power between them
n_active_relays = 0;
for(k = 0; k < args->n_relays; k++)
if(decoded_at_mr[k])
n_active_relays++;
// Normalization of received signal, fix this..
tx_energy = 300.0e3;
// awgn_stddev = sqrt((double)tx_energy)/pow(10.0, ((double)context->snr_hop2[0])/20.0);
awgn_stddev = pow(10,.05*40);
// for(k = 1; k < args->n_relays; k++)
// awgn_stddev = min(sqrt((double)tx_energy)/pow(10.0, ((double)context->snr_hop2[k])/20.0), awgn_stddev);
// printf("hop2 awgn_stddev %f\n",10*log10(awgn_stddev));
// transmit from all active relays
accumulate_at_rx = false;
for(k = 0; k < args->n_relays; k++) {
if(!decoded_at_mr[k])
continue;
// Clear txdataF vector
memset(phy_vars_mr[k]->lte_ue_common_vars.txdataF[0], 0,
FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t));
// Generate transport channel parameters
generate_ue_ulsch_params_from_dci(dci_hop2.dci_pdu, context->rnti_hop2,
ul_subframe2pdcch_alloc_subframe(&phy_vars_mr[k]->lte_frame_parms,context->subframe_hop2),//(context->subframe_hop2+6)%10,
format0, phy_vars_mr[k], SI_RNTI, RA_RNTI, P_RNTI, 0, 0);
// Set relay role in Alamouti coding (this could be done better)
if(relay_role[k] == RELAY_ROLE_STANDARD) {
phy_vars_mr[k]->ulsch_ue[0]->cooperation_flag = 0;
}
else {
phy_vars_mr[k]->ulsch_ue[0]->cooperation_flag = 2;
}
// Generate uplink reference signal
generate_drs_pusch(phy_vars_mr[k], 0, AMP, context->subframe_hop2, 0, args->n_prb_hop2);
// Encode ULSCH data
// printf("transmit_one_pdu 1 : ulsch_encoding mr %d\n",k);
if(ulsch_encoding(context->mr_buffer[k], frame_parms, phy_vars_mr[k]->ulsch_ue[0],
context->harq_pid_hop2, 1, 0, 1) == -1) {
printf("ulsch_encoding failed\n");
exit(1);
}
// Modulate ULSCH data
ulsch_modulation(phy_vars_mr[k]->lte_ue_common_vars.txdataF, AMP, 0, context->subframe_hop2,
frame_parms, phy_vars_mr[k]->ulsch_ue[0]);
// Compute number of resource elements from coded bits and modulation order
n_re_hop2 = context->n_coded_bits_hop2/get_Qm(context->mcs_hop2);
if(args->verbose > 2)
print_ulsch_ue_stats(phy_vars_mr[k]->ulsch_ue[0]);
// OFDM modulation
ofdm_modulation(phy_vars_mr[k]->lte_ue_common_vars.txdataF,
phy_vars_mr[k]->lte_ue_common_vars.txdata, frame_parms, context->subframe_hop2, frame_parms->symbols_per_tti);
tx_energy = signal_energy(&phy_vars_mr[k]->lte_ue_common_vars.txdata[0]
[frame_parms->samples_per_tti*context->subframe_hop2], frame_parms->samples_per_tti);
// Transmit over channel
// Redo this in a more intuitive manner:
//awgn_stddev = sqrt((double)tx_energy*((double)frame_parms->ofdm_symbol_size/(args->n_prb_hop2*12))/pow(10.0, ((double)context->snr_hop2[k])/10.0)/2.0);
tx_ampl = awgn_stddev/sqrt((double)tx_energy)*pow(10.0, ((double)context->snr_hop2[k])/20.0)/sqrt((double)n_active_relays);
// printf("hop 2 (%d): E=%d, ampl=%f, awgn=%f (accum %d)\n", k,tx_energy, tx_ampl, awgn_stddev,(unsigned char)accumulate_at_rx);
transmit_subframe(context->channels_hop2[k],
phy_vars_mr[k]->lte_ue_common_vars.txdata, frame_parms,
//context->subframe_hop2, frame_parms->symbols_per_tti, 256.0/sqrt((double)n_active_relays)/awgn_stddev, accumulate_at_rx);
context->subframe_hop2, frame_parms->symbols_per_tti, tx_ampl, accumulate_at_rx);
accumulate_at_rx = true;
}
// This is ugly. Fix it.
deliver_subframe(context->channels_hop2[0],
phy_vars_ch_dest->lte_eNB_common_vars.rxdata[0], frame_parms,
context->subframe_hop2, frame_parms->symbols_per_tti, awgn_stddev);
results->n_harq_tries_hop2[round_hop2]++;
// Fill the last symbol of the frame with random data (used for SNR estimation?)
for (i=0;i<OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES;i++) {
((short*) &phy_vars_ch_dest->lte_eNB_common_vars.rxdata[0][0]
[(frame_parms->samples_per_tti<<1) -frame_parms->ofdm_symbol_size])[2*i] =
(short) ((awgn_stddev*0.707*gaussdouble(0.0,1.0)));
((short*) &phy_vars_ch_dest->lte_eNB_common_vars.rxdata[0][0]
[(frame_parms->samples_per_tti<<1) -frame_parms->ofdm_symbol_size])[2*i+1] =
(short) ((awgn_stddev*0.707*gaussdouble(0.0,1.0)));
}
// Generate eNB transport channel parameters
generate_eNB_ulsch_params_from_dci(dci_hop2.dci_pdu, context->rnti_hop2,
ul_subframe2pdcch_alloc_subframe(&phy_vars_ch_dest->lte_frame_parms,context->subframe_hop2),//(context->subframe_hop2+6)%10,
format0, 0, phy_vars_ch_dest, SI_RNTI, RA_RNTI, P_RNTI, 0);
// Front end processing at destination CH
for(l = 0; l < frame_parms->symbols_per_tti>>1; l++)
slot_fep_ul(frame_parms, &phy_vars_ch_dest->lte_eNB_common_vars, l, 2*context->subframe_hop2, 0, 0);
for(l = 0; l < frame_parms->symbols_per_tti>>1; l++)
slot_fep_ul(frame_parms, &phy_vars_ch_dest->lte_eNB_common_vars, l, 2*context->subframe_hop2+1, 0, 0);
// Receive ULSCH data
rx_ulsch(phy_vars_ch_dest, context->subframe_hop2, 0, 0, phy_vars_ch_dest->ulsch_eNB, 2);
// Compute uncoded bit error rate
k = 0;
while(!decoded_at_mr[k])
k++;
raw_ber = compute_ber_soft(phy_vars_mr[k]->ulsch_ue[0]->b_tilde,
phy_vars_ch_dest->lte_eNB_pusch_vars[0]->llr, context->n_coded_bits_hop2);
results->ber_hop2 += raw_ber;
context->n_ber_frames_hop2++;
results->n_frames_hop2++;
if(args->verbose > 0) {
printf("Received %d bits at dest CH, raw BER: %f\n", context->n_coded_bits_hop2, raw_ber);
}
// Decode ULSCH data
n_iter = ulsch_decoding(phy_vars_ch_dest, 0, context->subframe_hop2, 0, 1);
if(args->verbose > 2)
print_ulsch_eNB_stats(phy_vars_ch_dest->ulsch_eNB[0]);
if(n_iter <= MAX_TURBO_ITERATIONS) {
if(args->verbose > 0)
printf("Successfully decoded at dest CH\n");
decoded_at_ch = true;
}
// Write debug output if requested
if(args->debug_output) {
for(k = 0; k < args->n_relays; k++) {
snprintf(fnbuf, 80, "hop2_r%d_mr%d_txdataFv.m", round_hop2, k);
snprintf(varbuf, 80, "hop2_r%d_mr%d_txdataF", round_hop2, k);
write_output(fnbuf, varbuf, phy_vars_mr[k]->lte_ue_common_vars.txdataF[0],
FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX, 1, 1);
snprintf(fnbuf, 80, "hop2_r%d_mr%d_txdatav.m", round_hop2, k);
snprintf(varbuf, 80, "hop2_r%d_mr%d_txdata", round_hop2, k);
write_output(fnbuf, varbuf, phy_vars_mr[k]->lte_ue_common_vars.txdata[0],
10*frame_parms->samples_per_tti, 1, 1);
}
snprintf(fnbuf, 80, "hop2_r%d_ch_rxdatav.m", round_hop2);
snprintf(varbuf, 80, "hop2_r%d_ch_rxdata", round_hop2);
write_output(fnbuf, varbuf, phy_vars_ch_dest->lte_eNB_common_vars.rxdata[0][0],
10*frame_parms->samples_per_tti, 1, 1);
snprintf(fnbuf, 80, "hop2_r%d_ch_rxdataFv.m", round_hop2);
snprintf(varbuf, 80, "hop2_r%d_ch_rxdataF", round_hop2);
write_output(fnbuf, varbuf, phy_vars_ch_dest->lte_eNB_common_vars.rxdataF[0][0],
20*frame_parms->ofdm_symbol_size*2*n_symbols_per_slot, 2, 1);
snprintf(fnbuf, 80, "hop2_r%d_ch_rxdataF_ext2v.m", round_hop2);
snprintf(varbuf, 80, "hop2_r%d_ch_rxdataF_ext2", round_hop2);
write_output(fnbuf, varbuf, phy_vars_ch_dest->lte_eNB_pusch_vars[0]->rxdataF_ext2[0][0],
12*phy_vars_ch_dest->lte_frame_parms.N_RB_UL*n_symbols_per_slot*2, 1, 1);
snprintf(fnbuf, 80, "hop2_r%d_ch_rxdataF_comp.m", round_hop2);
snprintf(varbuf, 80, "hop2_r%d_ch_rxdataF_comp", round_hop2);
write_output(fnbuf, varbuf, phy_vars_ch_dest->lte_eNB_pusch_vars[0]->rxdataF_comp[0][0],
12*phy_vars_ch_dest->lte_frame_parms.N_RB_UL*n_symbols_per_slot*2, 1, 1);
snprintf(fnbuf, 80, "hop2_r%d_ch_rxdataF_comp_0.m", round_hop2);
snprintf(varbuf, 80, "hop2_r%d_ch_rxdataF_comp_0", round_hop2);
write_output(fnbuf, varbuf, phy_vars_ch_dest->lte_eNB_pusch_vars[0]->rxdataF_comp_0[0][0],
12*phy_vars_ch_dest->lte_frame_parms.N_RB_UL*n_symbols_per_slot*2, 1, 1);
snprintf(fnbuf, 80, "hop2_r%d_ch_rxdataF_comp_1.m", round_hop2);
snprintf(varbuf, 80, "hop2_r%d_ch_rxdataF_comp_1", round_hop2);
write_output(fnbuf, varbuf, phy_vars_ch_dest->lte_eNB_pusch_vars[0]->rxdataF_comp_1[0][0],
12*phy_vars_ch_dest->lte_frame_parms.N_RB_UL*n_symbols_per_slot*2, 1, 1);
snprintf(fnbuf, 80, "hop2_r%d_ch_drs_ch_estimates_0.m", round_hop2);
snprintf(varbuf, 80, "hop2_r%d_ch_drs_ch_estimates_0", round_hop2);
write_output(fnbuf, varbuf, phy_vars_ch_dest->lte_eNB_pusch_vars[0]->drs_ch_estimates_0[0][0],
12*phy_vars_ch_dest->lte_frame_parms.N_RB_UL*n_symbols_per_slot*2, 1, 1);
snprintf(fnbuf, 80, "hop2_r%d_ch_drs_ch_estimates_1.m", round_hop2);
snprintf(varbuf, 80, "hop2_r%d_ch_drs_ch_estimates_1", round_hop2);
write_output(fnbuf, varbuf, phy_vars_ch_dest->lte_eNB_pusch_vars[0]->drs_ch_estimates_1[0][0],
12*phy_vars_ch_dest->lte_frame_parms.N_RB_UL*n_symbols_per_slot*2, 1, 1);
}
}
// Activate MRs that decoded during this frame
for(k = 0; k < args->n_relays; k++)
if(activate_mr[k]) {
setup_distributed_dci(&dci_hop2, context->rnti_hop2, 0, context->mcs_hop2, args->n_prb_hop2);
// Generate transport channel parameters
generate_ue_ulsch_params_from_dci(dci_hop2.dci_pdu, context->rnti_hop2,
ul_subframe2pdcch_alloc_subframe(&phy_vars_mr[k]->lte_frame_parms,context->subframe_hop2),//(context->subframe_hop2+6)%10,
format0, phy_vars_mr[k], SI_RNTI, RA_RNTI, P_RNTI, 0, 0);
// Set relay role in Alamouti coding (this could be done better)
if(relay_role[k] == RELAY_ROLE_STANDARD) {
phy_vars_mr[k]->ulsch_ue[0]->cooperation_flag = 0;
}
else {
phy_vars_mr[k]->ulsch_ue[0]->cooperation_flag = 2;
}
// Encode ULSCH data
// printf("transmit one pdu 2 : ulsch_encoding mr %d\n",k);
if(ulsch_encoding(context->mr_buffer[k], frame_parms, phy_vars_mr[k]->ulsch_ue[0],
context->harq_pid_hop2, 1, 0, 1) == -1) {
printf("ulsch_encoding failed\n");
exit(1);
}
decoded_at_mr[k] = true;
}
// Do strategy logic
start_hop2 = false;
switch(args->strategy) {
case strategy_wait_all:
if(hop1_active && !hop2_active) {
// Start hop 2 if all relays have decoded
start_hop2 = true;
for(k = 0; k < args->n_relays; k++)
if(!decoded_at_mr[k])
start_hop2 = false;
}
break;
case strategy_wait_one:
if(hop1_active && !hop2_active) {
// Start hop 2 if at least one relay has decoded
for(k = 0; k < args->n_relays; k++)
if(decoded_at_mr[k])
start_hop2 = true;
}
break;
default:
exit(1);
}
// If we start hop 2 now, save statistics for hop 1
if(start_hop2) {
results->n_harq_success_hop1[round_hop1]++;
results->n_pdu_success_hop1++;
results->n_bits_hop1 += context->tbs_hop1;
rounds_hop1 = round_hop1;
}
if(hop1_active) {
// Check if all relays decoded the PDU
decoded_at_all_mr = true;
for(k = 0; k < args->n_relays; k++)
if(!decoded_at_mr[k])
decoded_at_all_mr = false;
// Disable hop 1 if all relays decoded or the maximum HARQ round was reached
round_hop1++;
if(decoded_at_all_mr || round_hop1 == args->n_harq)
hop1_active = false;
}
if(hop2_active) {
// If successfully decoded at CH2, save statistics
if(decoded_at_ch) {
results->n_harq_success_hop2[round_hop2]++;
results->n_pdu_success_hop2++;
results->n_bits_hop2 += context->tbs_hop2;
rounds_hop2 = round_hop2;
if(rounds_hop1 < 0 || rounds_hop1 >= MAX_HARQ_ROUNDS)
fprintf(stderr, "rounds_hop1 has invalid value %d\n", rounds_hop1);
else if(rounds_hop2 < 0 || rounds_hop2 >= MAX_HARQ_ROUNDS)
fprintf(stderr, "rounds_hop2 has invalid value %d\n", rounds_hop2);
else
results->n_transmissions[rounds_hop1][rounds_hop2]++;
if(!block_valid(context->input_buffer, phy_vars_ch_dest->ulsch_eNB[0]->harq_processes[context->harq_pid_hop2]->b,
context->tbs_col/8)) {
printf("MAC PDU %d decoded successfully, but contained errors\n", pdu);
}
}
// If successfully decoded at CH2 or the maximum HARQ round was reached, disable both hops
round_hop2++;
if(decoded_at_ch || round_hop2 == args->n_harq) {
hop1_active = false;
hop2_active = false;
}
}
if(start_hop2)
hop2_active = true;
frame++;
/*
if(!decoded_at_all_mr) {
if(args.verbose > 0)
printf("Not decoded at all relays, dropping block\n");
continue;
}
*/
}
}
int parse_args(int argc, char** argv, args_t* args)
{
int c;
int k;
bool snr_set;
const struct option long_options[] = {
{"mcs1", required_argument, NULL, 256},
{"mcs2", required_argument, NULL, 257},
{"snr", required_argument, NULL, 258},
{"snr1", required_argument, NULL, 259},
{"snr2", required_argument, NULL, 260},
{"single", no_argument, NULL, 261},
{"sweep", no_argument, NULL, 262},
{"bsweep", no_argument, NULL, 263},
{"csweep", no_argument, NULL, 271},
{"strategy", required_argument, NULL, 264},
{"rb1", required_argument, NULL, 265},
{"rb2", required_argument, NULL, 266},
{"autorb", no_argument, NULL, 267},
{"range", required_argument, NULL, 268},
{"step", required_argument, NULL, 269},
{"corr", required_argument, NULL, 270},
{NULL, 0, NULL, 0}};
args->n_relays = 2;
args->debug_output = false;
args->verbose = 0;
args->n_pdu = 1;
args->n_harq = 4;
args->mcs_hop1 = 0;
args->mcs_hop2 = 0;
args->n_prb_hop1 = N_PRB;
args->n_prb_hop2 = N_PRB;
args->autorb = false;
args->channel_model = AWGN;
args->channel_correlation = 0.0;
args->results_fn = 0;
args->analysis = analysis_single;
args->strategy = strategy_wait_all;
args->range = 10.0;
args->step = 1.0;
for(k = 0; k < args->n_relays; k++)
args->snr_hop1[k] = 10.0;
for(k = 0; k < args->n_relays; k++)
args->snr_hop2[k] = 10.0;
snr_set = false;
while((c = getopt_long(argc, argv, "hovN:n:m:r:H:C:", long_options, NULL)) != -1) {
switch(c) {
case 'h':
return 1;
case 'o':
args->debug_output = true;
break;
case 'v':
args->verbose++;
break;
case 'N':
args->n_relays = atoi(optarg);
if(args->n_relays <= 0)
return 1;
break;
case 'n':
args->n_pdu = atoi(optarg);
if(args->n_pdu <= 0)
return 1;
break;
case 'H':
args->n_harq = atoi(optarg);
break;
case 'C':
if(strcmp(optarg, "help") == 0)
return 2;
if(!parse_channel_model(optarg, &args->channel_model))
return 1;
break;
case 'm':
args->mcs_hop1 = args->mcs_hop2 = atoi(optarg);
break;
case 'r':
args->results_fn = optarg;
break;
case 256:
args->mcs_hop1 = atoi(optarg);
break;
case 257:
args->mcs_hop2 = atoi(optarg);
break;
case 258:
for(k = 0; k < args->n_relays; k++)
args->snr_hop1[k] = atof(optarg);
for(k = 0; k < args->n_relays; k++)
args->snr_hop2[k] = atof(optarg);
snr_set = true;
break;
case 259:
if(!parse_snr(optarg, args->snr_hop1, args->n_relays))
return 1;
snr_set = true;
break;
case 260:
if(!parse_snr(optarg, args->snr_hop2, args->n_relays))
return 1;
snr_set = true;
break;
case 261:
args->analysis = analysis_single;
break;
case 262:
args->analysis = analysis_snrsweep_a;
break;
case 263:
args->analysis = analysis_snrsweep_b;
break;
case 271:
args->analysis = analysis_snrsweep_c;
break;
case 264:
switch(atoi(optarg)) {
case 1:
args->strategy = strategy_wait_all;
break;
case 2:
args->strategy = strategy_wait_one;
break;
default:
return 1;
}
break;
case 265: // --rb1
args->n_prb_hop1 = atoi(optarg);
if(args->n_prb_hop1 <= 0 || args->n_prb_hop1 > N_PRB)
return 1;
break;
case 266: // --rb2
args->n_prb_hop2 = atoi(optarg);
if(args->n_prb_hop2 <= 0 || args->n_prb_hop2 > N_PRB)
return 1;
break;
case 267: // --autorb
args->autorb = true;
break;
case 268: // --range
args->range = atof(optarg);
if(args->range <= 0.0)
return 1;
break;
case 269: // --step
args->step = atof(optarg);
if(args->step <= 0.0)
return 1;
break;
case 270: // --corr
args->channel_correlation = atof(optarg);
if(args->channel_correlation < 0.0 || args->channel_correlation > 1.0)
return 1;
break;
default:
return 1;
}
}
return 0;
}
bool parse_snr(const char* str, double* snr, int n)
{
char* p;
int k;
for(k = 0; k < n; k++) {
snr[k] = strtod(str, &p);
if(p == str)
break;
str = p;
}
if(k == 0)
for(k = 1; k < n; k++)
snr[k] = snr[0];
else if(k < n-1)
return false;
return true;
}
int parse_channel_model(const char* str, SCM_t* model)
{
if(strcmp(str, "0") == 0) *model = AWGN;
else if(strcmp(str, "A") == 0) *model = SCM_A;
else if(strcmp(str, "B") == 0) *model = SCM_B;
else if(strcmp(str, "C") == 0) *model = SCM_C;
else if(strcmp(str, "D") == 0) *model = SCM_D;
else if(strcmp(str, "E") == 0) *model = EPA;
else if(strcmp(str, "F") == 0) *model = EVA;
else if(strcmp(str, "G") == 0) *model = ETU;
else if(strcmp(str, "H") == 0) *model = Rayleigh8;
else if(strcmp(str, "I") == 0) *model = Rayleigh1;
else if(strcmp(str, "J") == 0) *model = Rayleigh1_corr;
else if(strcmp(str, "K") == 0) *model = Rayleigh1_anticorr;
else if(strcmp(str, "L") == 0) *model = Rice8;
else if(strcmp(str, "M") == 0) *model = Rice1;
else return false;
return true;
}
void print_usage(const char* prog)
{
printf("Usage: %s [options]\n", prog);
printf("\n");
printf(" General options:\n");
printf(" -h : print usage\n");
printf(" -v : increase verbosity level [0]\n");
printf(" -o : output MATLAB signal files (implies -n 1) [no]\n");
printf(" -r FILE : write results to FILE\n");
printf(" -N NRELAYS : simulate using NRELAYS relays [2]\n");
printf(" -n NUM : simulate NUM MAC PDUs [1]\n");
printf(" -H NUM : do NUM HARQ rounds in each hop [4]\n");
printf(" note: the hop 1 RVs are 0,0,1,1,2,2,3,3,0,0,..., the hop 2 RVs are 0,2,3,1,...\n");
printf(" -C CHANNEL : set the channel model, use -C help for available models [AWGN]\n");
printf(" --corr CORR : set channel realization correlation (0.0 .. 1.0) [0.0]\n");
printf(" --strategy X : set the HARQ strategy to X [1]\n");
printf(" 1: decode at all relays before starting hop 2\n");
printf(" 2: start hop 2 when at least one relay has decoded\n");
printf("\n");
printf(" SNR options:\n");
printf(" --snr SNR : set snr for all links to SNR [10.0]\n");
printf(" --snr1 SNR : set snr for hop 1 to SNR\n");
printf(" --snr2 SNR : set snr for hop 2 to SNR\n");
printf(" for --snr1 and --snr2, SNR may be either a single value or a vector with n_relays elements\n");
printf(" e.g.: --snr1 \"4.0 6.0\" sets the SNR from CH1 to MR1 and MR2 to 4.0 and 6.0, respectively\n");
printf("\n");
printf(" Analysis setup (only one may be specified):\n");
printf(" --single : single point analysis [default]\n");
printf(" --sweep : sweep snr of first relay of both hops [-RANGE*STEP..+RANGE*STEP]\n");
printf(" --bsweep : sweep first relay of hop 1 [-RANGE*STEP..+RANGE*STEP],\n");
printf(" sweep first relay of hop 2 [+RANGE*STEP..-RANGE*STEP]\n");
printf(" --range RANGE : set sweep range [10]\n");
printf(" --step STEP : set sweep step size [1.0]\n");
printf(" note: the swept range is relative to SNR specified with --snr* options\n");
printf("\n");
printf(" Link and resource parameters:\n");
printf(" -m MCS : set mcs for both hops to MCS [0]\n");
printf(" --mcs1 MCS : set mcs for hop 1 to MCS\n");
printf(" --mcs2 MCS : set mcs for hop 2 to MCS\n");
printf(" --rb1 NUM : set number of resource blocks for hop 1 [%d]\n", N_PRB);
printf(" --rb2 NUM : set number of resource blocks for hop 2 [%d]\n", N_PRB);
//printf(" --autorb : adjust the hop bandwidths to have similar TBS\n");
printf("\n");
printf(" Definition of results:\n");
printf(" BLER is the fraction of MAC PDUs that are not successfully delivered from CH1 to CH2\n");
printf(" BER is the fraction of coded bits that are incorrectly received for each link\n");
printf(" avg bits/frame is TBS*n_pdu/n_frames, where n_pdu is the number of successfully received MAC PDUs\n");
printf(" (for hop 1: decoded by both MR), and n_frames is the number of LTE frames transmitted for the hop\n");
printf(" norm. delay is the average number of LTE frames required for the successful transmission of a MAC PDU\n");
}
void print_channel_usage()
{
printf("Available channel models:\n");
printf(" 0: AWGN\n");
printf(" A: SCM-A\n");
printf(" B: SCM-B\n");
printf(" C: SCM-C\n");
printf(" D: SCM-D\n");
printf(" E: EPA\n");
printf(" F: EVA\n");
printf(" G: ETU\n");
printf(" H: Rayleigh8\n");
printf(" I: Rayleigh1\n");
printf(" J: Rayleigh1_corr\n");
printf(" K: Rayleigh1_anticorr\n");
printf(" L: Rice8\n");
printf(" M: Rice1\n");
}
void signal_handler(int sig)
{
void *array[10];
size_t size;
size = backtrace(array, 10);
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, 2);
exit(1);
}
void setup_single(double** snrs, int* n_tests, double* snr_hop1, double* snr_hop2, int n_relays)
{
int k;
*snrs = malloc(2*n_relays*sizeof(double));
for(k = 0; k < n_relays; k++)
(*snrs)[k] = snr_hop1[k];
for(k = 0; k < n_relays; k++)
(*snrs)[k+n_relays] = snr_hop2[k];
*n_tests = 1;
}
void setup_snrsweep_a(double** snrs, int* n_tests, double* snr_hop1, double* snr_hop2, int n_relays, double step, int start, int end)
{
int l;
int k;
*n_tests = end-start+1;
*snrs = malloc((*n_tests)*2*n_relays*sizeof(double));
for(l = 0; l < *n_tests; l++) {
(*snrs)[2*n_relays*l] = snr_hop1[0] + step*(start+l);
(*snrs)[2*n_relays*l + n_relays] = snr_hop2[0] + step*(start+l);
for(k = 1; k < n_relays; k++) {
(*snrs)[2*n_relays*l + k] = snr_hop1[k];
(*snrs)[2*n_relays*l + n_relays + k] = snr_hop2[k];
}
}
}
void setup_snrsweep_b(double** snrs, int* n_tests, double* snr_hop1, double* snr_hop2, int n_relays, double step, int start, int end)
{
int l;
int k;
*n_tests = end-start+1;
*snrs = malloc((*n_tests)*2*n_relays*sizeof(double));
for(l = 0; l < *n_tests; l++) {
(*snrs)[2*n_relays*l] = snr_hop1[0] + step*(start+l);
(*snrs)[2*n_relays*l + n_relays] = snr_hop2[0] + step*(end-l);
for(k = 1; k < n_relays; k++) {
(*snrs)[2*n_relays*l + k] = snr_hop1[k];
(*snrs)[2*n_relays*l + n_relays + k] = snr_hop2[k];
}
}
}
void setup_snrsweep_c(double** snrs, int* n_tests, double* snr_hop1, double* snr_hop2, int n_relays, double step, int start, int end)
{
int l;
int k;
*n_tests = end-start+1;
*snrs = malloc((*n_tests)*2*n_relays*sizeof(double));
for(l = 0; l < *n_tests; l++) {
for(k = 0; k < n_relays; k++) {
(*snrs)[2*n_relays*l + k] = snr_hop1[k] + step*(start+l);
(*snrs)[2*n_relays*l + n_relays + k] = snr_hop2[k] + step*(start+l);
}
}
}
void setup_frame_params(LTE_DL_FRAME_PARMS* frame_parms, unsigned char transmission_mode)
{
frame_parms->N_RB_DL = N_PRB;
frame_parms->N_RB_UL = N_PRB;
frame_parms->Nid_cell = NID_CELL;
frame_parms->Ncp = cp_type;
frame_parms->Ncp_UL = cp_type;
frame_parms->nushift = 0;
frame_parms->frame_type = 1; // TDD frames
frame_parms->tdd_config = 1; // TDD frame type 1
frame_parms->mode1_flag = (transmission_mode == 1 ? 1 : 0);
frame_parms->nb_antennas_tx = n_txantenna_ch;
frame_parms->nb_antennas_rx = n_rxantenna_mr;
init_frame_parms(frame_parms, oversampling);
phy_init_top(frame_parms);
frame_parms->twiddle_fft = twiddle_fft;
frame_parms->twiddle_ifft = twiddle_ifft;
frame_parms->rev = rev;
phy_init_lte_top(frame_parms);
frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 1;
frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0;
frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0;
init_ul_hopping(frame_parms);
//dump_frame_parms(frame_parms);
}
void setup_phy_vars(LTE_DL_FRAME_PARMS* frame_parms, PHY_VARS_eNB* phy_vars_ch_src,
PHY_VARS_UE** phy_vars_mr, PHY_VARS_eNB* phy_vars_ch_dest, int n_relays)
{
int k;
phy_vars_ch_src->lte_frame_parms = *frame_parms;
phy_vars_ch_src->frame = 1;
phy_init_lte_eNB(phy_vars_ch_src, 0, 0, 0);
for(k = 0; k < n_relays; k++) {
phy_vars_mr[k]->lte_frame_parms = *frame_parms;
phy_vars_mr[k]->frame = 1;
lte_gold(frame_parms, phy_vars_mr[k]->lte_gold_table[0], 0);
lte_gold(frame_parms, phy_vars_mr[k]->lte_gold_table[1], 1);
lte_gold(frame_parms, phy_vars_mr[k]->lte_gold_table[2], 2);
phy_init_lte_ue(phy_vars_mr[k], 0);
phy_vars_mr[k]->pucch_config_dedicated[0].tdd_AckNackFeedbackMode = bundling;
phy_vars_mr[k]->pusch_config_dedicated[0].betaOffset_ACK_Index = 0;
phy_vars_mr[k]->pusch_config_dedicated[0].betaOffset_RI_Index = 0;
phy_vars_mr[k]->pusch_config_dedicated[0].betaOffset_CQI_Index = 2;
}
phy_vars_ch_dest->lte_frame_parms = *frame_parms;
phy_vars_ch_dest->frame = 1;
phy_init_lte_eNB(phy_vars_ch_dest, 0, 2, 0);
phy_vars_ch_dest->transmission_mode[0] = 2;
phy_vars_ch_dest->pucch_config_dedicated[0].tdd_AckNackFeedbackMode = bundling;
phy_vars_ch_dest->pusch_config_dedicated[0].betaOffset_ACK_Index = 0;
phy_vars_ch_dest->pusch_config_dedicated[0].betaOffset_RI_Index = 0;
phy_vars_ch_dest->pusch_config_dedicated[0].betaOffset_CQI_Index = 2;
}
void alloc_broadcast_transport_channel(PHY_VARS_eNB* phy_vars_ch, PHY_VARS_UE** phy_vars_mr, int n_relays, u16 rnti)
{
int k;
// Workaround for memory leak:
phy_vars_ch->dlsch_eNB[0][0] = new_eNB_dlsch(1, 8, 0);
free(phy_vars_ch->dlsch_eNB[0][0]->harq_processes[0]->b);
for(k = 0; k < n_relays; k++) {
phy_vars_mr[k]->dlsch_ue[0][0] = new_ue_dlsch(1, 8, 0);
phy_vars_mr[k]->dlsch_ue[0][0]->mode1_flag = 0;
memset(phy_vars_mr[k]->dlsch_ue[0][0]->rb_alloc, 0, 16);
}
}
void free_broadcast_transport_channel(PHY_VARS_eNB* phy_vars_ch, PHY_VARS_UE** phy_vars_mr, int n_relays)
{
int k;
// Workaround for memory leak:
phy_vars_ch->dlsch_eNB[0][0]->harq_processes[0]->b = 0;
free_eNB_dlsch(phy_vars_ch->dlsch_eNB[0][0]);
for(k = 0; k < n_relays; k++) {
free_ue_dlsch(phy_vars_mr[k]->dlsch_ue[0][0]);
}
}
void alloc_distributed_transport_channel(PHY_VARS_eNB* phy_vars_ch, PHY_VARS_UE** phy_vars_mr, int n_relays, u16 rnti)
{
int k;
int l;
for(k = 0; k < n_relays; k++) {
phy_vars_mr[k]->ulsch_ue[0] = new_ue_ulsch(8, 0);
phy_vars_mr[k]->ulsch_ue[0]->o_ACK[0] = 0;
phy_vars_mr[k]->ulsch_ue[0]->o_ACK[1] = 0;
phy_vars_mr[k]->ulsch_ue[0]->o_ACK[2] = 0;
phy_vars_mr[k]->ulsch_ue[0]->o_ACK[3] = 0;
for(l = 0; l < 3; l++)
if(phy_vars_mr[k]->ulsch_ue[0]->harq_processes[l]) {
phy_vars_mr[k]->ulsch_ue[0]->harq_processes[l]->status = DISABLED;
phy_vars_mr[k]->ulsch_ue[0]->harq_processes[l]->B = 0;
}
}
phy_vars_ch->ulsch_eNB[0] = new_eNB_ulsch(8, 0);
}
void free_distributed_transport_channel(PHY_VARS_eNB* phy_vars_ch, PHY_VARS_UE** phy_vars_mr, int n_relays)
{
int k;
for(k = 0; k < n_relays; k++) {
free_ue_ulsch(phy_vars_mr[k]->ulsch_ue[0]);
}
//free_eNB_ulsch(phy_vars_ch->ulsch_eNB[0]);
}
u16 rballoc_type0(int n_rb, int rbg_size)
{
int rb = 0;
int k;
for(k = 0; k < n_rb; k += rbg_size)
rb = (rb << 1) + 1;
return rb;
}
void setup_broadcast_dci(DCI_ALLOC_t* dci, u16 rnti, int harq_round, int mcs, int n_rb)
{
DCI1_5MHz_TDD_t* dci_data = (DCI1_5MHz_TDD_t*) dci->dci_pdu;
memset(dci, 0, sizeof(DCI_ALLOC_t));
dci_data->dai = 1;
dci_data->TPC = 0;
dci_data->rv = (harq_round >> 1) & 0x03;
dci_data->ndi = (harq_round == 0 ? 1 : 0);
dci_data->harq_pid = 0;
dci_data->mcs = mcs;
dci_data->rballoc = rballoc_type0(n_rb, RBG_SIZE);
dci_data->rah = 0;
dci->dci_length = sizeof_DCI1_5MHz_TDD_t;
dci->L = 1;
dci->rnti = rnti;
dci->format = format1;
}
void setup_distributed_dci(DCI_ALLOC_t* dci, u16 rnti, int harq_round, int mcs, int n_rb)
{
DCI0_5MHz_TDD_1_6_t* dci_data = (DCI0_5MHz_TDD_1_6_t*) dci->dci_pdu;
memset(dci, 0, sizeof(DCI_ALLOC_t));
dci_data->cqi_req = 0;
dci_data->dai = 1;
dci_data->cshift = 0;
dci_data->TPC = 0;
if(harq_round == 0) {
dci_data->ndi = 1;
dci_data->mcs = mcs;
} else {
dci_data->ndi = 0;
switch(harq_round % 4) {
case 0:
dci_data->mcs = mcs;
break;
case 1:
// dci_data->mcs = 30;
dci_data->mcs = mcs;
break;
case 2:
// dci_data->mcs = 31;
dci_data->mcs = 29;
break;
case 3:
dci_data->mcs = 29;
break;
}
}
dci_data->rballoc = computeRIV(N_PRB,0,n_rb);
dci_data->hopping = 0;
dci_data->type = 0;
dci->dci_length = sizeof_DCI0_5MHz_TDD_1_6_t;
dci->L = 1;
dci->rnti = rnti;
dci->format = format0;
}
void ofdm_modulation(mod_sym_t** tx_f, s32** tx_t, LTE_DL_FRAME_PARMS* frame_parms, u8 subframe, u8 nsymb)
{
mod_sym_t* src;
s32* dst;
if(frame_parms->Ncp == 0) { // Normal prefix
src = &tx_f[0][subframe*14*frame_parms->ofdm_symbol_size];
dst = &tx_t[0][subframe*frame_parms->samples_per_tti];
normal_prefix_mod(src, dst, nsymb, frame_parms);
} else { // Extended prefix
src = &tx_f[0][subframe*12*frame_parms->ofdm_symbol_size];
dst = &tx_t[0][subframe*frame_parms->samples_per_tti];
PHY_ofdm_mod(src, dst, frame_parms->log2_symbol_size,
nsymb, frame_parms->nb_prefix_samples, frame_parms->twiddle_ifft,
frame_parms->rev, CYCLIC_PREFIX);
}
}
channel_vars_t alloc_channel_vars(LTE_DL_FRAME_PARMS* frame_parms)
{
channel_vars_t v;
v.s_re[0] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
v.s_im[0] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
v.r_re[0] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
v.r_im[0] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
v.r_re_t[0] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
v.r_im_t[0] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
return v;
}
void free_channel_vars(channel_vars_t v)
{
free(v.s_re[0]);
free(v.s_im[0]);
free(v.r_re[0]);
free(v.r_im[0]);
free(v.r_re_t[0]);
free(v.r_im_t[0]);
}
sh_channel_t* alloc_sh_channel(channel_vars_t* cvars, SCM_t channel_model, int n_txantennas, int n_rxantennas,
double channel_correlation)
{
sh_channel_t* ch = malloc(sizeof(sh_channel_t));
ch->cvars = cvars;
ch->channel = new_channel_desc_scm(n_txantennas, n_rxantennas, channel_model, BW, channel_correlation, 0, 0.0);
return ch;
}
void free_sh_channel(sh_channel_t* c)
{
free(c->channel);
}
void transmit_subframe(sh_channel_t* channel, s32** src, LTE_DL_FRAME_PARMS* frame_parms,
u8 subframe, u8 nsymb, double ampl, bool accumulate)
{
int k;
int symbols_per_slot = (frame_parms->Ncp == 0 ? 7 : 6);
int nsamples = 0;
for(k = 0; k < nsymb; k++) {
if(k % symbols_per_slot == 0)
nsamples += frame_parms->nb_prefix_samples0;
else
nsamples += frame_parms->nb_prefix_samples;
nsamples += frame_parms->ofdm_symbol_size;
}
for(k = 0; k < nsamples; k++) {
channel->cvars->s_re[0][k] = (double)((s16*)src[0])[2*subframe*frame_parms->samples_per_tti + (k<<1)];
channel->cvars->s_im[0][k] = (double)((s16*)src[0])[2*subframe*frame_parms->samples_per_tti + (k<<1) + 1];
/*
if(accumulate) {
channel->cvars->r_re_t[0][k] = channel->cvars->s_re[0][k];
channel->cvars->r_im_t[0][k] = channel->cvars->s_im[0][k];
} else {
channel->cvars->r_re[0][k] = channel->cvars->s_re[0][k];
channel->cvars->r_im[0][k] = channel->cvars->s_im[0][k];
}
*/
//channel->cvars->s_re[1][k] = 0;
//channel->cvars->s_im[1][k] = 0;
}
if(accumulate) {
multipath_channel(channel->channel, channel->cvars->s_re, channel->cvars->s_im,
channel->cvars->r_re_t, channel->cvars->r_im_t, nsamples, 0);
for(k = 0; k < nsamples; k++) {
channel->cvars->r_re[0][k] += channel->cvars->r_re_t[0][k] * ampl;
channel->cvars->r_im[0][k] += channel->cvars->r_im_t[0][k] * ampl;
}
} else {
multipath_channel(channel->channel, channel->cvars->s_re, channel->cvars->s_im,
channel->cvars->r_re, channel->cvars->r_im, nsamples, 0);
for(k = 0; k < nsamples; k++) {
channel->cvars->r_re[0][k] *= ampl;
channel->cvars->r_im[0][k] *= ampl;
}
}
}
void deliver_subframe(sh_channel_t* channel, s32** dst, LTE_DL_FRAME_PARMS* frame_parms,
u8 subframe, u8 nsymb, double stddev)
{
int k;
int symbols_per_slot = (frame_parms->Ncp == 0 ? 7 : 6);
int nsamples = 0;
for(k = 0; k < nsymb; k++) {
// printf("deliver_subframe symbol k %d\n",k);
if(k % symbols_per_slot == 0)
nsamples += frame_parms->nb_prefix_samples0;
else
nsamples += frame_parms->nb_prefix_samples;
nsamples += frame_parms->ofdm_symbol_size;
}
for(k = 0; k < nsamples; k++) {
((s16*)dst[0])[2*subframe*frame_parms->samples_per_tti + (k<<1)] =
(s16) (channel->cvars->r_re[0][k] + stddev*0.707*gaussdouble(0.0, 1.0));
((s16*)dst[0])[2*subframe*frame_parms->samples_per_tti + (k<<1) + 1] =
(s16) (channel->cvars->r_im[0][k] + stddev*0.707*gaussdouble(0.0, 1.0));
}
}
void ofdm_fep(PHY_VARS_UE* phy_vars_mr, u8 subframe)
{
int n_symbols_per_slot = (phy_vars_mr->lte_frame_parms.Ncp == 0 ? 7 : 6);
int slot;
int symbol;
//slot = subframe;
for(slot = 2*subframe; slot < 2*subframe+2; slot++)
for(symbol = 0; symbol < n_symbols_per_slot; symbol++)
slot_fep(phy_vars_mr, symbol, slot, 0, 0);
slot_fep(phy_vars_mr, 0, 2*subframe+2, 0, 0);
}
int rx_dlsch_symbol(PHY_VARS_UE* phy_vars, u8 subframe, u8 symbol, u8 first_symbol)
{
int s;
s = rx_pdsch(phy_vars, PDSCH, 0, 0, subframe, symbol, first_symbol, 0, 0);
if(s == -1)
printf("DLSCH receiver error\n");
return s;
}
u32 get_ulsch_G(LTE_UE_ULSCH_t *ulsch, u8 harq_pid)
{
u8 Q_m = 0;
u32 Kr = 0;
int r;
u32 sumKr = 0;
u32 Qprime;
u32 L;
u32 G;
u32 Q_CQI = 0;
u32 Q_RI = 0;
Q_m = get_Qm(ulsch->harq_processes[harq_pid]->mcs);
sumKr = 0;
for (r=0;r<ulsch->harq_processes[harq_pid]->C;r++) {
if (r<ulsch->harq_processes[harq_pid]->Cminus)
Kr = ulsch->harq_processes[harq_pid]->Kminus;
else
Kr = ulsch->harq_processes[harq_pid]->Kplus;
sumKr += Kr;
}
Qprime = ulsch->O_RI * ulsch->harq_processes[harq_pid]->Msc_initial *
ulsch->harq_processes[harq_pid]->Nsymb_initial * ulsch->beta_offset_ri_times8;
if (Qprime > 0) {
if ((Qprime % (8*sumKr)) > 0)
Qprime = 1+(Qprime/(8*sumKr));
else
Qprime = Qprime/(8*sumKr);
if (Qprime > 4*ulsch->harq_processes[harq_pid]->nb_rb * 12)
Qprime = 4*ulsch->harq_processes[harq_pid]->nb_rb * 12;
}
Q_RI = Q_m*Qprime;
if (ulsch->O < 12)
L=0;
else
L=8;
Qprime = (ulsch->O + L) * ulsch->harq_processes[harq_pid]->Msc_initial *
ulsch->harq_processes[harq_pid]->Nsymb_initial * ulsch->beta_offset_cqi_times8;
if (Qprime > 0) {
if ((Qprime % (8*sumKr)) > 0)
Qprime = 1+(Qprime/(8*sumKr));
else
Qprime = Qprime/(8*sumKr);
}
G = ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch);
if (Qprime > (G - ulsch->O_RI))
Qprime = G - ulsch->O_RI;
Q_CQI = Q_m * Qprime;
G = G - Q_RI - Q_CQI;
return G;
}
double compute_ber_soft(u8* ref, s16* rec, int n)
{
int k;
int e = 0;
for(k = 0; k < n; k++) {
if((ref[k]==1) != (rec[k]<0)) {
//printf("error pos %d ( %d => %d)\n",k,ref[k],rec[k]);
e++;
}
}
return (double)e / (double)n;
}
void print_dlsch_eNB_stats(LTE_eNB_DLSCH_t* d)
{
int k;
LTE_DL_eNB_HARQ_t* h;
if(d)
{
printf("eNB dlsch: rnti=%04x, active=%d, current_harq_pid=%d, rb_alloc=%08x %08x %08x %08x, nb_rb=%d, G=%d, layer_index=%d, codebook_index=%d, Mdlharq=%d, Kmimo=%d\n",
d->rnti, d->active, d->current_harq_pid,
d->rb_alloc[0], d->rb_alloc[1], d->rb_alloc[2], d->rb_alloc[3], d->nb_rb, d->G,
d->layer_index, d->codebook_index, d->Mdlharq, d->Kmimo);
for(k = 0; k < 8; k++) {
if(d->harq_processes[k]) {
h = d->harq_processes[k];
if(h->status == ACTIVE) {
printf("HARQ process %d: Ndi=%d, status=%d, TBS=%d, B=%d, round=%d, mcs=%d, rvidx=%d, Nl=%d\n",
k, h->Ndi, h->status, h->TBS, h->B, h->round, h->mcs, h->rvidx, h->Nl);
}
}
}
}
}
void print_dlsch_ue_stats(LTE_UE_DLSCH_t* d)
{
int k;
LTE_DL_UE_HARQ_t* h;
if(d)
{
printf("UE dlsch: rnti=%04x, active=%d, mode1_flag=%d, current_harq_pid=%d, rb_alloc=%08x %08x %08x %08x, nb_rb=%d, G=%d, layer_index=%d, Mdlharq=%d, Kmimo=%d\n",
d->rnti, d->active, d->mode1_flag, d->current_harq_pid,
d->rb_alloc[0], d->rb_alloc[1], d->rb_alloc[2], d->rb_alloc[3], d->nb_rb, d->G,
d->layer_index, d->Mdlharq, d->Kmimo);
for(k = 0; k < 8; k++) {
if(d->harq_processes[k]) {
h = d->harq_processes[k];
if(h->status == ACTIVE || h->TBS > 0) {
printf("HARQ process %d: Ndi=%d, status=%d, TBS=%d, B=%d, round=%d, mcs=%d, rvidx=%d, Nl=%d\n",
k, h->Ndi, h->status, h->TBS, h->B, h->round, h->mcs, h->rvidx, h->Nl);
}
}
}
}
}
void print_ulsch_ue_stats(LTE_UE_ULSCH_t* d)
{
int k;
LTE_UL_UE_HARQ_t* h;
if(d) {
printf("UE ulsch: Nsymb_pusch=%d, O=%d, o_ACK=%d %d %d %d, O_ACK=%d, Mdlharq=%d, n_DMRS2=%d, cooperation_flag=%d\n",
d->Nsymb_pusch, d->O, d->o_ACK[0], d->o_ACK[1], d->o_ACK[2], d->o_ACK[3], d->O_ACK, d->Mdlharq, d->n_DMRS2, d->cooperation_flag);
for(k = 0; k < 3; k++) {
if(d->harq_processes[k]) {
h = d->harq_processes[k];
if(h->status == ACTIVE) {
printf("HARQ process %d: Ndi=%d, status=%d, subframe_scheduling_flag=%d, first_rb=%d, nb_rb=%d, TBS=%d, B=%d, round=%d, mcs=%d, rvidx=%d\n",
k, h->Ndi, h->status, h->subframe_scheduling_flag, h->first_rb, h->nb_rb, h->TBS, h->B, h->round, h->mcs, h->rvidx);
}
}
}
}
}
void print_ulsch_eNB_stats(LTE_eNB_ULSCH_t* d)
{
int k;
LTE_UL_eNB_HARQ_t* h;
if(d) {
printf("eNB ulsch: Nsymb_pusch=%d, Mdlharq=%d, cqi_crc_status=%d, Or1=%d, Or2=%d, o_RI=%d %d, O_RI=%d, o_ACK=%d %d %d %d, O_ACK=%d, o_RCC=%d, beta_offset_cqi_times8=%d, beta_offset_ri_times8=%d, beta_offset_harqack_times8=%d, rnti=%x, n_DMRS2=%d, cyclicShift=%d, cooperation_flag=%d\n",
d->Nsymb_pusch, d->Mdlharq, d->cqi_crc_status, d->Or1, d->Or2, d->o_RI[0], d->o_RI[1], d->O_RI, d->o_ACK[0], d->o_ACK[1], d->o_ACK[2], d->o_ACK[3], d->O_ACK, d->o_RCC, d->beta_offset_cqi_times8, d->beta_offset_ri_times8, d->beta_offset_harqack_times8, d->rnti, d->n_DMRS2, d->cyclicShift, d->cooperation_flag);
for(k = 0; k < 3; k++) {
if(d->harq_processes[k]) {
h = d->harq_processes[k];
if(h->status == ACTIVE) {
printf("HARQ process %d: Ndi=%d, status=%d, subframe_scheduling_flag=%d, phich_active=%d, phich_ACK=%d, TPC=%d, first_rb=%d, nb_rb=%d, TBS=%d, B=%d, round=%d, mcs=%d, rvidx=%d\n",
k, h->Ndi, h->status, h->subframe_scheduling_flag, h->phich_active, h->phich_ACK, h->TPC, h->first_rb, h->nb_rb, h->TBS, h->B, h->round, h->mcs, h->rvidx);
}
}
}
}
}
int block_valid(u8* ref, u8* rec, int n)
{
int k;
for(k = 0; k < n; k++) {
if(ref[k] != rec[k])
return 0;
//printf("%d ",k);
}
//printf("\n");
return 1;
}
void init_results(results_t* r, args_t* a)
{
int k;
r->n_relays = a->n_relays;
r->n_pdu = a->n_pdu;
r->n_harq = a->n_harq;
r->channel_model = a->channel_model;
r->mcs_hop1 = malloc(a->n_pdu*sizeof(int*));
r->mcs_hop2 = malloc(a->n_pdu*sizeof(int*));
r->tbs_hop1 = malloc(a->n_pdu*sizeof(int*));
r->tbs_hop2 = malloc(a->n_pdu*sizeof(int*));
r->n_prb_hop1 = malloc(a->n_pdu*sizeof(int*));
r->n_prb_hop2 = malloc(a->n_pdu*sizeof(int*));
for(k = 0; k < a->n_pdu; k++) {
r->mcs_hop1[k] = malloc(a->n_harq*sizeof(int));
r->mcs_hop2[k] = malloc(a->n_harq*sizeof(int));
r->tbs_hop1[k] = malloc(a->n_harq*sizeof(int));
r->tbs_hop2[k] = malloc(a->n_harq*sizeof(int));
r->n_prb_hop1[k] = malloc(a->n_harq*sizeof(int));
r->n_prb_hop2[k] = malloc(a->n_harq*sizeof(int));
}
r->relay_activity = malloc((1 << a->n_relays)*sizeof(int));
}
void clear_results(results_t* r)
{
int k;
r->snr_hop1 = 0;
r->snr_hop2 = 0;
r->n_frames_hop1 = 0;
r->n_frames_hop2 = 0;
r->n_bits_hop1 = 0;
r->n_bits_hop2 = 0;
for(k = 0; k < MAX_RELAYS; k++) {
r->ber_hop1[k] = 0.0;
}
r->ber_hop2 = 0.0;
r->n_pdu_success_hop1 = 0;
r->n_pdu_success_hop2 = 0;
for(k = 0; k < MAX_HARQ_ROUNDS; k++) {
r->n_harq_tries_hop1[k] = 0;
r->n_harq_tries_hop2[k] = 0;
r->n_harq_success_hop1[k] = 0;
r->n_harq_success_hop2[k] = 0;
}
for(k = 0; k < r->n_pdu; k++) {
memset(r->mcs_hop1[k], 0, r->n_harq*sizeof(int));
memset(r->mcs_hop2[k], 0, r->n_harq*sizeof(int));
memset(r->tbs_hop1[k], 0, r->n_harq*sizeof(int));
memset(r->tbs_hop2[k], 0, r->n_harq*sizeof(int));
memset(r->n_prb_hop1[k], 0, r->n_harq*sizeof(int));
memset(r->n_prb_hop2[k], 0, r->n_harq*sizeof(int));
}
memset(r->n_transmissions, 0, MAX_HARQ_ROUNDS*MAX_HARQ_ROUNDS*sizeof(int));
memset(r->relay_activity, 0, (1 << (r->n_relays))*sizeof(int));
}
void free_results(results_t* r)
{
int k;
for(k = 0; k < r->n_pdu; k++) {
free(r->mcs_hop1[k]);
free(r->mcs_hop2[k]);
free(r->tbs_hop1[k]);
free(r->tbs_hop2[k]);
free(r->n_prb_hop1[k]);
free(r->n_prb_hop2[k]);
}
free(r->mcs_hop1);
free(r->mcs_hop2);
free(r->tbs_hop1);
free(r->tbs_hop2);
free(r->n_prb_hop1);
free(r->n_prb_hop2);
free(r->relay_activity);
}
void print_results(results_t* r)
{
int k;
printf("Hop 1: SNR (");
for(k = 0; k < r->n_relays; k++)
printf("%.1f%s", r->snr_hop1[k], k < r->n_relays-1 ? ", " : "");
printf("), BER (");
for(k = 0; k < r->n_relays; k++)
printf("%f%s", r->ber_hop1[k], k < r->n_relays-1 ? ", " : "");
printf(")\n");
printf(" avg bits/frame %f, avg frames/received PDU %f, avg delay %f\n",
(double)r->n_bits_hop1/(double)r->n_frames_hop1,
(double)r->n_frames_hop1/(double)r->n_pdu_success_hop1,
calc_delay(r->n_harq_success_hop1, r->n_harq));
//(double)(r->n_frames_hop1-(r->n_harq_tries_hop1[0]-r->n_pdu_success_hop1)*r->n_harq)/(double)r->n_pdu_success_hop1);
printf(" HARQ (n_success/n_tries):");
for(k = 0; k < r->n_harq; k++)
printf(" %d/%d", r->n_harq_success_hop1[k], r->n_harq_tries_hop1[k]);
printf("\n");
printf("Hop 2: SNR (");
for(k = 0; k < r->n_relays; k++)
printf("%.1f%s", r->snr_hop2[k], k < r->n_relays-1 ? ", " : "");
printf("), BER %f\n", r->ber_hop2);
printf(" avg bits/frame %f, avg frames/received PDU %f, avg delay %f\n",
(double)r->n_bits_hop2/(double)r->n_frames_hop2,
(double)r->n_frames_hop2/(double)r->n_pdu_success_hop2,
calc_delay(r->n_harq_success_hop2, r->n_harq));
//(double)(r->n_frames_hop2-(r->n_harq_tries_hop2[0]-r->n_pdu_success_hop2)*r->n_harq)/(double)r->n_pdu_success_hop2);
printf(" HARQ (n_success/n_tries):");
for(k = 0; k < r->n_harq; k++)
printf(" %d/%d", r->n_harq_success_hop2[k], r->n_harq_tries_hop2[k]);
printf("\n");
printf("Collaborative link BLER: %d/%d\n", r->n_pdu-r->n_pdu_success_hop2, r->n_pdu);
printf("Relay activity:");
if(r->n_relays == 2)
printf(" MR1(%d) MR2(%d) MR1+MR2(%d)\n", r->relay_activity[1], r->relay_activity[2], r->relay_activity[3]);
else {
for(k = 1; k < (1 << r->n_relays); k++)
printf(" %d", r->relay_activity[k]);
printf("\n");
}
}
void write_results_header(FILE* f, results_t* r, int n_tests)
{
fprintf(f, "%d %d %d %d %d\n", r->n_relays, r->channel_model, n_tests, r->n_pdu, r->n_harq);
}
void write_results_data(FILE* f, results_t* r)
{
int k;
int l;
for(k = 0; k < r->n_relays; k++)
fprintf(f, "%f ", r->snr_hop1[k]);
fprintf(f, "\n");
for(k = 0; k < r->n_relays; k++)
fprintf(f, "%f ", r->snr_hop2[k]);
fprintf(f, "\n");
fprintf(f, "%d %d %d %d %d %d\n", r->n_frames_hop1, r->n_frames_hop2,
r->n_bits_hop1, r->n_bits_hop2, r->n_pdu_success_hop1, r->n_pdu_success_hop2);
for(k = 0; k < r->n_relays; k++)
fprintf(f, "%f ", r->ber_hop1[k]);
fprintf(f, "%f\n", r->ber_hop2);
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->n_harq_tries_hop1[k]);
fprintf(f, "\n");
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->n_harq_success_hop1[k]);
fprintf(f, "\n");
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->n_harq_tries_hop2[k]);
fprintf(f, "\n");
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->n_harq_success_hop2[k]);
fprintf(f, "\n");
for(l = 0; l < r->n_pdu; l++) {
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->mcs_hop1[l][k]);
fprintf(f, "\n");
}
for(l = 0; l < r->n_pdu; l++) {
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->mcs_hop2[l][k]);
fprintf(f, "\n");
}
for(l = 0; l < r->n_pdu; l++) {
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->tbs_hop1[l][k]);
fprintf(f, "\n");
}
for(l = 0; l < r->n_pdu; l++) {
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->tbs_hop2[l][k]);
fprintf(f, "\n");
}
for(l = 0; l < r->n_pdu; l++) {
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->n_prb_hop1[l][k]);
fprintf(f, "\n");
}
for(l = 0; l < r->n_pdu; l++) {
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->n_prb_hop2[l][k]);
fprintf(f, "\n");
}
for(l = 0; l < r->n_harq; l++) {
for(k = 0; k < r->n_harq; k++)
fprintf(f, "%d ", r->n_transmissions[l][k]);
fprintf(f, "\n");
}
for(k = 0; k < (1 << r->n_relays); k++)
fprintf(f, "%d ", r->relay_activity[k]);
fprintf(f, "\n");
}
double calc_delay(int* n_frames, int n_harq)
{
int n = 0;
int f = 0;
int k;
for(k = 0; k < n_harq; k++) {
n += n_frames[k]*(k+1);
f += n_frames[k];
}
return (double)n/(double)f;
}