free5GRAN  V1.0
phy.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Telecom Paris
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16 
17 #include "phy.h"
18 #include "../../lib/phy/synchronization/synchronization.h"
19 #include "../../lib/phy/libphy/libphy.h"
20 #include "../../lib/variables/common_variables/common_variables.h"
21 #include "../../lib/utils/sequence_generator/sequence_generator.h"
22 #include "../../lib/phy/transport_channel/transport_channel.h"
23 #include <iostream>
24 #include <vector>
25 #include <fftw3.h>
26 #include <fstream>
27 #include <boost/log/core.hpp>
28 #include <boost/log/trivial.hpp>
29 #include <boost/log/expressions.hpp>
30 #include <boost/log/utility/setup/file.hpp>
31 #include <boost/log/utility/setup/common_attributes.hpp>
32 #include "../../lib/asn1c/nr_rrc/BCCH-DL-SCH-Message.h"
33 #include "../../lib/variables/common_structures/common_structures.h"
34 #include "../../lib/phy/physical_channel/physical_channel.h"
35 #include "../../lib/utils/common_utils/common_utils.h"
36 #include "../../lib/asn1c/nr_rrc/BCCH-DL-SCH-Message.h"
37 #include "../../lib/asn1c/nr_rrc/FrequencyInfoUL-SIB.h"
38 
39 using namespace std;
40 
41 phy::phy(rf *rf_dev, double ssb_period, int fft_size, int scs, free5GRAN::band band_obj) {
50  this->rf_device = rf_dev;
51  this->ssb_period = ssb_period;
52  this->fft_size = fft_size;
53  this->scs = scs;
54  this->band_object = band_obj;
55  l_max = band_obj.l_max;
56  this->is_extended_cp = 0;
57  common_cp_length = 0;
58 }
59 
60 int phy::cell_synchronization(float &received_power) {
71  BOOST_LOG_TRIVIAL(trace) << "PSS synchronization";
72 
73  int n_id_2,synchronisation_index;
74  float peak_value;
75  received_power = 0;
76 
77  size_t num_samples = 2 * ssb_period * rf_device->getSampleRate();
78 
79  // Create buffer
80  vector<complex<float>> buff_2_ssb_periods(num_samples);
81  buff.clear();
82  buff.resize(num_samples / 2);
83 
84  complex<float> j(0, 1);
85  // Get samples from RF layer and put them in buff variable
86  time_first_pss = chrono::high_resolution_clock::now();
87  try {
88  double time_first_sample;
89  rf_device->get_samples(&buff_2_ssb_periods, time_first_sample);
90  }catch (const exception& e) {
91  return 1;
92  }
93  int num_symbols_per_subframe_pbch = free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP * scs/15e3;
94  int cp_lengths_pbch[num_symbols_per_subframe_pbch];
95  int cum_sum_pbch[num_symbols_per_subframe_pbch];
96 
97  free5GRAN::phy::signal_processing::compute_cp_lengths((int) scs/1e3, fft_size, 0, num_symbols_per_subframe_pbch, cp_lengths_pbch, cum_sum_pbch);
98  /*
99  * Take second symbol CP as common CP as SSB is never transmitted at long CP symbols (long CP are transmitted every 0.5ms)
100  */
101  common_cp_length = cp_lengths_pbch[1];
102  /*
103  * Extract first half of buffer (= 1 SSB period)
104  */
105  for (int i = 0; i < num_samples / 2; i ++){
106  buff[i] = buff_2_ssb_periods[i];
107  }
108 
109  /*
110  * Get PSS correlation result
111  */
112  free5GRAN::phy::synchronization::search_pss(n_id_2,synchronisation_index,peak_value, common_cp_length, buff, fft_size);
113  BOOST_LOG_TRIVIAL(trace) << "Peak value: "+ to_string(peak_value/common_cp_length);
114  /*
115  * Computing symbol length and first sample index of PSS in buff
116  */
117  int symbol_duration = fft_size + common_cp_length;
118  int pss_start_index = synchronisation_index - symbol_duration + 1;
119  int sss_init_index = pss_start_index + 2 * symbol_duration + common_cp_length; // = (synchronisation_index - symbol_duration + 1) + 2 * symbol_duration;
120  /*
121  * If highest correlation peak is not fully in buffer, cell is not found
122  */
123  if (pss_start_index < 0){
124  return 1;
125  }
126 
127  index_first_pss = pss_start_index;
128 
129  vector<complex<float>> sss_signal(fft_size);
130  /*
131  * Extracting the SSS signal based on sss_init_index and cp_length
132  */
133  for (int i = 0; i < fft_size; i++){
134  sss_signal[i] = buff[i + sss_init_index];
135  }
136  /*
137  * Computing received power
138  */
139  for (int i = 0; i < 4 * symbol_duration; i ++){
140  received_power += pow(abs(buff[pss_start_index + i]),2);
141  }
142  received_power /= 4 * symbol_duration;
143  received_power = 10 * log10(received_power);
144  int n_id_1;
145  float peak_value_sss;
146 
147  /*
148  * Get SSS correlation result
149  */
150  BOOST_LOG_TRIVIAL(trace) << "SSS synchronization";
151  free5GRAN::phy::synchronization::get_sss(n_id_1, peak_value_sss, sss_signal, fft_size, n_id_2);
152  BOOST_LOG_TRIVIAL(trace) << "Peak value: "+ to_string(peak_value_sss);
153  pci = 3 * n_id_1 + n_id_2;
154  BOOST_LOG_TRIVIAL(trace) << "PCI : "+ to_string(pci);
155 
156 
157  /*
158  * Retreive first SSB symbol of second SSB period
159  */
160  vector<complex<float>> second_pss(fft_size + common_cp_length), second_sss(fft_size);
161  int second_pss_index = pss_start_index + num_samples / 2;
162  int n_id_1_2, n_id_2_2, sync_index_pss_2;
163  float peak_value_pss_2;
164  for (int i = 0; i < fft_size + common_cp_length; i++){
165  second_pss[i] = buff_2_ssb_periods[i + second_pss_index];
166  }
167  /*
168  * Retrieve N ID 2 value from second SSB
169  */
170  free5GRAN::phy::synchronization::search_pss(n_id_2_2,sync_index_pss_2,peak_value_pss_2, common_cp_length, second_pss, fft_size);
171 
172  /*
173  * Extract SSS symbol from second SSB
174  */
175  for (int i = 0; i < fft_size; i++){
176  second_sss[i] = buff_2_ssb_periods[i + second_pss_index + 2 * symbol_duration + common_cp_length];
177  }
178 
179  free5GRAN::phy::synchronization::get_sss(n_id_1_2, peak_value_sss, second_sss, fft_size, n_id_2_2);
180 
181  if (3 * n_id_1_2 + n_id_2_2 == pci){
182  return 0;
183  }else {
184  return 1;
185  }
186 }
187 
207  BOOST_LOG_TRIVIAL(trace) << "Extracting PBCH";
208  // Get at least 30ms of signal (=3 frames, at least 2 complete ones)
209  size_t num_samples = max(0.03, ssb_period) * rf_device->getSampleRate();
210  //vector<complex<float>> buff(num_samples);
211  buff.clear();
212  buff.resize(num_samples);
213 
214  // Getting samples
215  auto now = chrono::high_resolution_clock::now();
216  try {
217  double second_frame_time;
218  rf_device->get_samples(&buff, second_frame_time);
219  }catch (const exception& e) {
220  return 1;
221  }
222 
223  /*
224  * SYNCHRONIZING IN THE NEW RECEIVED FRAME
225  * Computing approximate PSS index inside the received buffer using the time reference of the first PSS index SSB initial search
226  */
227  auto time_window = chrono::duration_cast<chrono::microseconds>(now - time_first_pss);
228  int offset_to_ssb_period = (int)(time_window.count() - index_first_pss / (128*scs *1e-6)) % ((int) (ssb_period * 1e6));
229  int index_second_pss = (ssb_period * 1e6 - offset_to_ssb_period) * rf_device->getSampleRate() * 1e-6;
230 
231  ofstream data;
232  data.open("data.txt");
233  for (int i = 0; i < num_samples; i ++){
234  data << buff[i];
235  data << "\n";
236  }
237  data.close();
238 
239  /*
240  * Compute PBCH CP length
241  */
242  int num_symbols_per_subframe_pbch = free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP * scs/15e3;
243  int cp_lengths_pbch[num_symbols_per_subframe_pbch];
244  int cum_sum_pbch[num_symbols_per_subframe_pbch];
245 
246  free5GRAN::phy::signal_processing::compute_cp_lengths((int) scs/1e3, fft_size, 0, num_symbols_per_subframe_pbch, cp_lengths_pbch, cum_sum_pbch);
247  common_cp_length = cp_lengths_pbch[1];
248  int symbol_duration = fft_size + common_cp_length;
249 
250  vector<complex<float>> pss_signal(48 * symbol_duration);
251 
252  /*
253  * Isolate PSS signal around calculated new PSS occurence (based on timestamp of first synchronization step)
254  */
255  int begin_offset = 0;
256  int end_offset = 0;
257  if (pss_signal.size()/2 <= index_second_pss && pss_signal.size()/2 <= num_samples - index_second_pss){
258  begin_offset = pss_signal.size()/2;
259  end_offset = pss_signal.size()/2;
260  } else if (pss_signal.size()/2 > index_second_pss){
261  begin_offset = index_second_pss;
262  end_offset = pss_signal.size() - index_second_pss;
263  } else if (pss_signal.size()/2 > num_samples - index_second_pss) {
264  end_offset = num_samples - index_second_pss;
265  begin_offset = pss_signal.size() - (num_samples - index_second_pss);
266  }
267 
268  // Extracting the signal around the PSS approximation
269  int count = 0;
270  for (int i = -begin_offset; i < end_offset; i ++){
271  pss_signal[count] = buff[(int) index_second_pss + i];
272  count ++;
273  }
274 
275  int synchronisation_index;
276  float peak_value;
277 
278  /*
279  * Downsample signal for better performance
280  */
281  int downsampling_factor = fft_size / free5GRAN::PSS_SSS_FFT_SIZE;
282  BOOST_LOG_TRIVIAL(trace) << "PSS synchronization downsampling factor: " << downsampling_factor;
283  int symbol_duration_downsampled = symbol_duration / downsampling_factor;
284 
285  vector<complex<float>> pss_signal_downsampled(48 * symbol_duration_downsampled);
286  for (int i = 0; i < 48 * symbol_duration_downsampled; i ++){
287  pss_signal_downsampled[i] = pss_signal[(size_t) downsampling_factor * i];
288  }
289 
290  free5GRAN::phy::synchronization::search_pss(this->n_id_2,synchronisation_index,peak_value, common_cp_length / downsampling_factor, pss_signal_downsampled,fft_size / downsampling_factor);
291 
292  int pss_start_index = downsampling_factor * (synchronisation_index - symbol_duration_downsampled + 1);
293 
294  /*
295  * Once synchronization is made on downsampled signal, it can be performed on full signal for finer results
296  */
297  vector<complex<float>> fine_pss_signal(symbol_duration + (2 * downsampling_factor + 1));
298  count = 0;
299  for (int i = pss_start_index - downsampling_factor; i < pss_start_index + symbol_duration + (downsampling_factor + 1); i ++){
300  fine_pss_signal[count] = pss_signal[i];
301  count ++;
302  }
303  free5GRAN::phy::synchronization::search_pss(this->n_id_2,synchronisation_index,peak_value, common_cp_length, fine_pss_signal,fft_size);
304 
305  pss_start_index = pss_start_index + (synchronisation_index - symbol_duration + 1 - downsampling_factor);
306  int buffer_pss_index = pss_start_index + index_second_pss - begin_offset;
307  index_first_pss = buffer_pss_index;
308  int sss_init_index = buffer_pss_index + 2 * symbol_duration + common_cp_length;
309 
310  vector<complex<float>> sss_signal(fft_size);
311  /*
312  * Extracting the SSS signal based on sss_init_index and common_cp_length
313  */
314  for (int i = 0; i < fft_size; i++){
315  sss_signal[i] = buff[i + sss_init_index];
316  }
317 
318  float peak_value_sss;
319  /*
320  * Get SSS correlation result
321  */
322  free5GRAN::phy::synchronization::get_sss(this->n_id_1, peak_value_sss, sss_signal,fft_size,this->n_id_2);
323  if (pci == 3 * n_id_1 + n_id_2){
324  BOOST_LOG_TRIVIAL(trace) << "PCI confirmed";
325  cell_confirmed = true;
326  }else{
327  BOOST_LOG_TRIVIAL(trace) << "PCI not confirmed";
328  cell_confirmed = false;
329  return 1;
330  }
331  /*
332  * WE ARE NOW SYNCHONIZED IN OUR NEW FRAME
333  * Trying to extract DMRS AND PBCH
334  */
335 
336  vector<complex<float>> ssb_signal(4 * symbol_duration);
337 
338  // Extract SSB signal
339  for (int i = 0; i < free5GRAN::NUM_SYMBOLS_SSB * symbol_duration; i ++){
340  ssb_signal[i] = buff[i + buffer_pss_index];
341  }
342 
343  /*
344  * Fine frequency correlation
345  * Getting phase offset between CP and corresponding part of the OFDM symbol for each of the 4 symbols.
346  * phase_offset is the mean phase offset
347  */
348  free5GRAN::phy::signal_processing::compute_fine_frequency_offset(ssb_signal, symbol_duration, fft_size, common_cp_length, scs, freq_offset, free5GRAN::NUM_SYMBOLS_SSB);
349 
350  // Correcting signal based on frequency offset
351  free5GRAN::phy::signal_processing::transpose_signal(&buff, freq_offset, rf_device->getSampleRate(), buff.size());
352 
353  vector<complex<float>> final_pbch_modulation_symbols(free5GRAN::SIZE_SSB_PBCH_SYMBOLS);
354 
355  /*
356  * Extracting DMRS AND PBCH modulation symbols
357  * ref is the reference grid for resource element demapper
358  */
359  vector<complex<float>> temp_mod_symbols, temp_mod_symbols2,temp_mod_symbols_dmrs;
360 
361  complex<float> pbch_symbols[free5GRAN::SIZE_SSB_PBCH_SYMBOLS];
362  complex<float> dmrs_symbols[free5GRAN::SIZE_SSB_DMRS_SYMBOLS];
363  complex<float> sss_symbols[free5GRAN::SIZE_PSS_SSS_SIGNAL];
364  /*
365  * ref[0] -> indexes of PBCH resource elements
366  * ref[1] -> indexes of DMRS resource elements
367  */
368  vector<vector<vector<int>>> ref(3, vector<vector<int>>(free5GRAN::SIZE_SSB_DMRS_SYMBOLS, vector<int>(free5GRAN::NUM_SC_SSB)));
369  /*
370  * channel_indexes[0] contains PBCH samples indexes
371  * channel_indexes[1] contains DMRS samples indexes
372  * channel_indexes[2] contains SSS samples indexes
373  */
374  vector<vector<vector<int>>> channel_indexes = {vector<vector<int>>(2, vector<int>(free5GRAN::SIZE_SSB_PBCH_SYMBOLS)), vector<vector<int>>(2, vector<int>(free5GRAN::SIZE_SSB_DMRS_SYMBOLS)), vector<vector<int>>(2, vector<int>(free5GRAN::SIZE_PSS_SSS_SIGNAL))};
375 
376  vector<vector<complex<float>>> ssb_symbols(free5GRAN::NUM_SYMBOLS_SSB - 1, vector<complex<float>>(free5GRAN::NUM_SC_SSB));
377 
378  int cum_sum_fft[free5GRAN::NUM_SYMBOLS_SSB];
379  for (int symbol = 0; symbol < free5GRAN::NUM_SYMBOLS_SSB; symbol ++){
380  cum_sum_fft[symbol] = symbol * symbol_duration;
381  }
382 
383  /*
384  * Recover RE grid from time domain signal
385  */
386  free5GRAN::phy::signal_processing::fft(ssb_signal, ssb_symbols,fft_size,cp_lengths_pbch,&cum_sum_fft[0],free5GRAN::NUM_SYMBOLS_SSB - 1,free5GRAN::NUM_SC_SSB,1,0);
387 
389  /*
390  * Channel demapping using computed ref grid
391  */
392  complex<float>* output_channels[] = {pbch_symbols, dmrs_symbols, sss_symbols};
394 
395  /*
396  * Channel estimation and equalization
397  * Creating coefficients arrays
398  */
399  vector<vector<vector<complex<float>>>> coefficients(free5GRAN::MAX_I_BAR_SSB, vector<vector<complex<float>>>(free5GRAN::NUM_SYMBOL_PBCH_SSB, vector<complex<float>>(free5GRAN::NUM_SC_SSB)));
400 
401 
402  complex<float> dmrs_sequence[free5GRAN::SIZE_SSB_DMRS_SYMBOLS];
403  float snr[free5GRAN::MAX_I_BAR_SSB];
404 
405  /*
406  * For each possible iBarSSB value, estimate the corresponding transport_channel
407  */
408  for (int i = 0; i < free5GRAN::MAX_I_BAR_SSB; i ++){
411  }
412  /*
413  * Choose the iBarSSB value that maximizes the SNR
414  */
415  max_snr = snr[0];
416  int i_b_ssb = 0;
417  for (int i = 1; i < free5GRAN::MAX_I_BAR_SSB ; i ++){
418  if (snr[i] > max_snr){
419  max_snr = snr[i];
420  i_b_ssb = i;
421  }
422  }
423 
424  // Equalize transport_channel
425  for (int i = 0; i < free5GRAN::SIZE_SSB_PBCH_SYMBOLS; i ++){
426  final_pbch_modulation_symbols[i] = (pbch_symbols[i]) * conj(coefficients[i_b_ssb][channel_indexes[0][0][i]][channel_indexes[0][1][i]]) / (float) pow(abs(coefficients[i_b_ssb][channel_indexes[0][0][i]][channel_indexes[0][1][i]]),2);
427  }
428 
429  ss_pwr.ss_rsrp = 0;
430  for (int i = 0; i < free5GRAN::SIZE_PSS_SSS_SIGNAL; i ++){
431  ss_pwr.ss_rsrp +=pow(abs(sss_symbols[i]),2);
432  }
433  for (int i = 0; i < free5GRAN::SIZE_SSB_DMRS_SYMBOLS; i ++){
434  ss_pwr.ss_rsrp +=pow(abs(dmrs_symbols[i]),2);
435  }
436  ss_pwr.ss_rsrp /= (free5GRAN::SIZE_PSS_SSS_SIGNAL + free5GRAN::SIZE_SSB_DMRS_SYMBOLS);
437 
438  ss_pwr.ss_rssi = 0;
439  for (int symb = 0 ; symb < free5GRAN::NUM_SYMBOLS_SSB - 1; symb++){
440  for (int sc = 0; sc < free5GRAN::NUM_SC_SSB; sc ++){
441  ss_pwr.ss_rssi += pow(abs(ssb_symbols[symb][sc]),2);
442  }
443  }
444  // 20 is the number of RB in SSB block
445  int n_rb = 20;
446  ss_pwr.ss_rssi /= n_rb;
447  ss_pwr.ss_rsrq = 10 * log(n_rb * ss_pwr.ss_rsrp / ss_pwr.ss_rssi);
448  // Converting RSRP and RSSI from W to dBm
449  ss_pwr.ss_rsrp = 10 * log10(ss_pwr.ss_rsrp) + 30;
450  ss_pwr.ss_rssi = 10 * log10(ss_pwr.ss_rssi) + 30;
451  ss_pwr.ss_sinr = max_snr;
452 
453  this->i_b_ssb = i_b_ssb;
454  if (l_max == 4){
455  this-> i_ssb = i_b_ssb % 4;
456  }else {
457  this-> i_ssb = i_b_ssb;
458  }
459 
460  /*
461  * Physical and transport channel decoding
462  * MIB parsing
463  */
464  int bch_bits[free5GRAN::SIZE_SSB_PBCH_SYMBOLS * 2];
465  free5GRAN::phy::physical_channel::decode_pbch(final_pbch_modulation_symbols, i_ssb, pci, bch_bits);
466  int mib_bits[free5GRAN::BCH_PAYLOAD_SIZE];
467  free5GRAN::phy::transport_channel::decode_bch(bch_bits, crc_validated, mib_bits, pci);
468  free5GRAN::utils::common_utils::parse_mib(mib_bits, mib_object);
469  return 0;
470 }
471 
473 
474 }
475 
481  cout << "\n";
482  cout << "###### RADIO" << endl;
483  cout << "# SS-RSRP: " + to_string(ss_pwr.ss_rsrp) + " dbm" << endl;
484  cout << "# SS-RSSI: " + to_string(ss_pwr.ss_rssi) + " dbm" << endl;
485  cout << "# SS-RSRQ: " + to_string(ss_pwr.ss_rsrq) + " db" << endl;
486  cout << "# SS-SNR: " + to_string(ss_pwr.ss_sinr) + " db" << endl;
487  cout << "# Frequency offset: " + to_string(freq_offset) + " Hz" << endl;
488  cout << "\n";
489  cout << "###### CELL" << endl;
490  cout << "## PCI: " + to_string(pci) + ((cell_confirmed) ? " (confirmed)" : " (not confirmed)") << endl;
491  cout << "## CP: ";
492  cout << ((is_extended_cp == 0 ) ? "Normal" : "Extended") << endl;
493  cout << "## I_B_SSB: " + to_string(i_b_ssb) << endl;
494  cout << "## I_SSB: " + to_string(i_ssb) << endl;
495  cout << "\n";
496  cout << "###### MIB" << endl;
497  cout << "## Frame number: " + to_string(mib_object.sfn) << endl;
498  cout << "## PDCCH configuration: " + to_string(mib_object.pdcch_config) << endl;
499  cout << "## Subcarrier spacing common: " + to_string(mib_object.scs) << endl;
500  cout << "## Cell barred: " + to_string(mib_object.cell_barred) << endl;
501  cout << "## DMRS type A position : " + to_string(mib_object.dmrs_type_a_position) << endl;
502  cout << "## k SSB: " + to_string(mib_object.k_ssb) << endl;
503  cout << "## Intra freq reselection: " + to_string(mib_object.intra_freq_reselection) << endl;
504  cout << "## CRC ";
505  cout << ((crc_validated) ? "validated" : "not validated") << endl;
506  cout << "\n";
507  cout << "#######################################################################" << endl;
508  cout << "\n";
509 }
510 
511 void phy::reconfigure(int fft_size) {
512  this->fft_size = fft_size;
513 }
514 
515 void phy::search_pdcch(bool &dci_found) {
538  /*
539  * If SSB offset is greater than 23, PDCCH is not present in the current BWP
540  */
541  if(mib_object.k_ssb > 23){
542  dci_found = false;
543  return;
544  }
545  mu = log2(mib_object.scs/15);
546  int symbol_in_frame = band_object.ssb_symbols[this->i_ssb];
547  frame_size = 0.01 * rf_device->getSampleRate();
548  num_slots_per_frame = 10 * mib_object.scs/15;
549 
550 
551  /*
552  * Computing CP lengths of SSB/PBCH and recovering SSB position in frame
553  */
554  int num_symbols_per_subframe_pbch = free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP * (int) (scs/15e3);
555  int cp_lengths_pbch[num_symbols_per_subframe_pbch];
556  int cum_sum_pbch[num_symbols_per_subframe_pbch];
557 
558  free5GRAN::phy::signal_processing::compute_cp_lengths((int) scs/1e3, fft_size, is_extended_cp, num_symbols_per_subframe_pbch, &cp_lengths_pbch[0], &cum_sum_pbch[0]);
559 
560  int num_samples_before_pss = (symbol_in_frame / free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP) * (15e3/scs * frame_size / 10.0) + cum_sum_pbch[symbol_in_frame % free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP];
561  int num_samples_after_pss = frame_size - num_samples_before_pss;
562 
563  /*
564  * Computing new FFT size, based on MIB common SCS
565  */
566  fft_size = (int) (rf_device->getSampleRate() / (1e3 * mib_object.scs));
567 
568  BOOST_LOG_TRIVIAL(trace) << "###### PDCCH Search & decode";
569  BOOST_LOG_TRIVIAL(trace) << "## INDEX_1: " + to_string(mib_object.pdcch_config/16);
570  BOOST_LOG_TRIVIAL(trace) << "## INDEX_2: " + to_string(mib_object.pdcch_config%16);
571  BOOST_LOG_TRIVIAL(trace) << "## SYMBOL IN FRAME: " + to_string(symbol_in_frame);
572  BOOST_LOG_TRIVIAL(trace) << "## FRAME SIZE: " + to_string(frame_size);
573  BOOST_LOG_TRIVIAL(trace) << "## INDEX PSS: " + to_string(index_first_pss);
574  BOOST_LOG_TRIVIAL(trace) << "## SLOTS PER FRAME: " + to_string(num_slots_per_frame);
575  BOOST_LOG_TRIVIAL(trace) << "## SAMPLES AFTER PSS: " + to_string(num_samples_after_pss);
576  BOOST_LOG_TRIVIAL(trace) << "## BUFFER SIZE: " + to_string(buff.size());
577  BOOST_LOG_TRIVIAL(trace) << "## FFT SIZE: " + to_string(fft_size);
578 
579  /*
580  * Getting two candidate frames in received signal.
581  * frame_indexes are the beginning and ending indexes of the two candidate frames
582  * frame_numbers stores SFN for each candidate frame
583  */
584  vector<vector<int>> frame_indexes(2, vector<int>(2));
585  int frame_numbers[2];
586  free5GRAN::phy::signal_processing::get_candidates_frames_indexes(frame_indexes,frame_numbers,mib_object.sfn, index_first_pss,num_samples_before_pss, frame_size);
587 
588  BOOST_LOG_TRIVIAL(trace) << "## FRAME 1 FROM: " + to_string(1e3 * frame_indexes[0][0]/rf_device->getSampleRate()) + " TO: " + to_string(1e3 * frame_indexes[0][1]/rf_device->getSampleRate()) + " ms";
589  BOOST_LOG_TRIVIAL(trace) << "## FRAME 2 FROM: " + to_string(1e3 * frame_indexes[1][0]/rf_device->getSampleRate()) + " TO: " + to_string(1e3 * frame_indexes[1][1]/rf_device->getSampleRate()) + " ms";
590 
591  /*
592  * Computing PDCCH Search Space information
593  */
594  pdcch_ss_mon_occ = free5GRAN::phy::signal_processing::compute_pdcch_t0_ss_monitoring_occasions(mib_object.pdcch_config, scs, mib_object.scs * 1e3, i_ssb);
595  pdcch_ss_mon_occ.n0 = (int)(pdcch_ss_mon_occ.O * pow(2, mu) + floor(i_ssb * pdcch_ss_mon_occ.M)) % num_slots_per_frame;
596  pdcch_ss_mon_occ.sfn_parity = (int)((pdcch_ss_mon_occ.O * pow(2, mu) + floor(i_ssb * pdcch_ss_mon_occ.M)) / num_slots_per_frame) % 2;
597 
598  BOOST_LOG_TRIVIAL(trace) << "## n0: " + to_string(pdcch_ss_mon_occ.n0) ;
599  BOOST_LOG_TRIVIAL(trace) << "## ODD/EVEN ?: " + to_string(pdcch_ss_mon_occ.sfn_parity);
600 
601  /*
602  * Getting candidate frame which satisfies Search Space SFN parity
603  */
604  int frame;
605  if (frame_numbers[0] % 2 == pdcch_ss_mon_occ.sfn_parity){
606  frame = 0;
607  }else {
608  frame = 1;
609  }
610 
611  BOOST_LOG_TRIVIAL(trace) << "## FRAME: " + to_string(frame);
612 
613  /*
614  * Normalizing signal
615  */
616  complex<float> rms = 0;
617  frame_data.resize(frame_size);
618  for (int i = 0; i < frame_size; i ++){
619  frame_data[i] = buff[i + frame_indexes[frame][0]];
620  rms += abs(pow(frame_data[i],2));
621  }
622  rms = sqrt(rms/complex<float>(frame_size,0));
623  for (int i = 0; i < frame_size; i ++){
624  frame_data[i] = frame_data[i] / rms;
625  }
626 
627  /*
628  * Computing phase offset from SSB, based on RB offset and k_ssb and transposing signal to center on current BWP (which is here CORESET0)
629  */
630  float freq_diff = 12 * 1e3 * mib_object.scs * (pdcch_ss_mon_occ.n_rb_coreset / 2 - (10 * ((float) scs / (1e3*mib_object.scs)) + pdcch_ss_mon_occ.offset));
631  float freq_diff2 = - 15e3 * mib_object.k_ssb;
632  free5GRAN::phy::signal_processing::transpose_signal(&frame_data, freq_diff + freq_diff2 , rf_device->getSampleRate(), frame_size);
633 
634  BOOST_LOG_TRIVIAL(trace) << "## FREQ DIFF 1: " + to_string(freq_diff);
635  BOOST_LOG_TRIVIAL(trace) << "## FREQ DIFF 2: " + to_string(freq_diff2);
636 
637  /*
638  * Logging frame data to text file for plotting
639  */
640  ofstream data;
641  data.open("output_files/studied_frame.txt");
642  for (int i = 0; i < frame_size; i ++){
643  data << frame_data[i];
644  data << "\n";
645  }
646  data.close();
647 
648  /*
649  * Plotting 4 slots around PDCCH monitoring slots
650  */
651  int begin_index = (pdcch_ss_mon_occ.n0-1) * frame_size / num_slots_per_frame;
652  begin_index = max(begin_index,0);
653  ofstream data2;
654  data2.open("output_files/moniroting_slots.txt");
655  for (int i = 0; i < 4 * frame_size / num_slots_per_frame; i ++){
656  data2 << frame_data[i + begin_index];
657  data2 << "\n";
658  }
659  data2.close();
660 
661  /*
662  * Initialize arrays
663  */
664  int num_sc_coreset_0 = 12 * pdcch_ss_mon_occ.n_rb_coreset;
665 
666  /*
667  * Compute CCE-to-REG mapping From TS38.211 7.3.2.2
668  */
669  int height_reg_rb = free5GRAN::NUMBER_REG_PER_CCE / pdcch_ss_mon_occ.n_symb_coreset;
670  int R = 2;
671  int C = pdcch_ss_mon_occ.n_rb_coreset / (height_reg_rb * R);
672  int j;
673  int reg_index[C * R];
674  for (int c = 0; c < C; c ++){
675  for (int r = 0; r < R; r ++){
676  j = c * R + r;
677  reg_index[j] = (r * C + c + this->pci) % (pdcch_ss_mon_occ.n_rb_coreset/height_reg_rb);
678  }
679  }
680  for (int i = 0 ; i < C * R ; i ++){
681  BOOST_LOG_TRIVIAL(trace) << "## CCE"+ to_string(i) + ": REG" + to_string(reg_index[i]);
682  }
683 
684  /*
685  * Computing current BWP CP lengths
686  */
687  int num_symbols_per_subframe_pdcch = free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP * mib_object.scs/15;
688  int cp_lengths_pdcch[num_symbols_per_subframe_pdcch];
689  int cum_sum_pdcch[num_symbols_per_subframe_pdcch];
690  free5GRAN::phy::signal_processing::compute_cp_lengths(mib_object.scs, fft_size, is_extended_cp, num_symbols_per_subframe_pdcch, &cp_lengths_pdcch[0], &cum_sum_pdcch[0]);
691 
692  ofstream data_pdcch;
693 
694  int K, freq_domain_ra_size;
695  /*
696  * Number of bits for Frequency domain allocation in DCI
697  */
698  freq_domain_ra_size = ceil(log2(pdcch_ss_mon_occ.n_rb_coreset*(pdcch_ss_mon_occ.n_rb_coreset+1) / 2));
699  /*
700  * K is the DCI payload size including CRC
701  */
702  K = freq_domain_ra_size + 4 + 1 + 5 + 2 + 1 + 15 + 24;
703 
704  float snr;
705  bool validated = false;
706  int agg_level, num_candidates, dci_decoded_bits[K-24];
707  vector<vector<complex<float>>> global_sequence(pdcch_ss_mon_occ.n_symb_coreset, vector<complex<float>>(pdcch_ss_mon_occ.n_rb_coreset * 3));
708  vector<vector<vector<int>>> ref(2, vector<vector<int>>(pdcch_ss_mon_occ.n_symb_coreset, vector<int>(12 * pdcch_ss_mon_occ.n_rb_coreset)));
709  vector<vector<complex<float>>> coreset_0_samples(pdcch_ss_mon_occ.n_symb_coreset, vector<complex<float>>(num_sc_coreset_0));
710  vector<vector<complex<float>>> coefficients(pdcch_ss_mon_occ.n_symb_coreset, vector<complex<float>>(num_sc_coreset_0));
711 
712  /*
713  * PDCCH blind search. First, loop over every monitoring slot
714  */
715  BOOST_LOG_TRIVIAL(trace) << "### PDCCH BLIND SEARCH";
716  for (int monitoring_slot = 0; monitoring_slot < 2; monitoring_slot ++){
717  pdcch_ss_mon_occ.monitoring_slot = monitoring_slot;
718  BOOST_LOG_TRIVIAL(trace) << "## MONITORING SLOT: "+ to_string(monitoring_slot);
719 
720  /*
721  * Extract corresponding CORESET0 samples. CORESET0 number of symbols is given by PDCCH config in MIB
722  * Recover RE grid from time domain signal
723  */
724  free5GRAN::phy::signal_processing::fft(frame_data, coreset_0_samples,fft_size,cp_lengths_pdcch,cum_sum_pdcch,pdcch_ss_mon_occ.n_symb_coreset,num_sc_coreset_0,pdcch_ss_mon_occ.first_symb_index, (pdcch_ss_mon_occ.n0 + monitoring_slot) * frame_size / num_slots_per_frame);
725  for (int symb = 0; symb < pdcch_ss_mon_occ.n_symb_coreset; symb ++){
726  /*
727  * Generate DMRS sequence for corresponding symbols
728  */
729  free5GRAN::utils::sequence_generator::generate_pdcch_dmrs_sequence(pci, pdcch_ss_mon_occ.n0 + monitoring_slot, pdcch_ss_mon_occ.first_symb_index + symb, global_sequence[symb], pdcch_ss_mon_occ.n_rb_coreset * 3);
730  }
731  /*
732  * Loop over possible aggregation level (from 2 to 4 included) and candidates
733  */
734  for (int i = 2; i < 5; i ++){
735  agg_level = pow(2, i);
736  if (agg_level <= pdcch_ss_mon_occ.n_rb_coreset / height_reg_rb){
737  vector<vector<vector<int>>> channel_indexes = {vector<vector<int>>(2, vector<int>((size_t) agg_level * free5GRAN::NUMBER_REG_PER_CCE * 9)), vector<vector<int>>(2, vector<int>((size_t) agg_level * free5GRAN::NUMBER_REG_PER_CCE * 3))};
738  vector<complex<float>> pdcch_symbols((size_t) agg_level * free5GRAN::NUMBER_REG_PER_CCE * 9);
739  complex<float> temp_pdcch_symbols[agg_level * free5GRAN::NUMBER_REG_PER_CCE * 9];
740  complex<float> dmrs_symbols[agg_level * free5GRAN::NUMBER_REG_PER_CCE * 3];
741  complex<float> dmrs_sequence[agg_level * free5GRAN::NUMBER_REG_PER_CCE * 3];
742  int reg_bundles[agg_level];
743  int reg_bundles_ns[agg_level];
744  int dci_bits[agg_level * free5GRAN::NUMBER_REG_PER_CCE * 9 * 2];
745 
746  BOOST_LOG_TRIVIAL(trace) << "## AGGREGATION LEVEL"+ to_string(agg_level);
747  num_candidates = pdcch_ss_mon_occ.n_rb_coreset / (agg_level * height_reg_rb);
748  /*
749  * Loop over candidates of current aggregation level
750  */
751  for (int p = 0; p < num_candidates; p ++){
752  BOOST_LOG_TRIVIAL(trace) << "## CANDIDATE "+ to_string(p);
753  /*
754  * Extract REG bundles for current candidate and aggregation level
755  */
756  for (int l = 0; l < agg_level; l ++){
757  reg_bundles[l] = reg_index[l + p * agg_level];
758  reg_bundles_ns[l] = reg_index[l + p * agg_level];
759  }
760  sort(reg_bundles, reg_bundles+agg_level);
761  /*
762  * PDCCH samples extraction
763  */
764  for (int symbol = 0; symbol < pdcch_ss_mon_occ.n_symb_coreset; symbol ++) {
765  for (int sc = 0; sc < 12 * pdcch_ss_mon_occ.n_rb_coreset; sc ++){
766  ref[1][symbol][sc] = 0;
767  ref[0][symbol][sc] = 0;
768  }
769  }
770  /*
771  * Computing PDCCH candidate position in RE grid
772  */
773  free5GRAN::phy::physical_channel::compute_pdcch_indexes(ref, pdcch_ss_mon_occ, agg_level, reg_bundles, height_reg_rb);
774  /*
775  * Channel de-mapping
776  */
777  complex<float>* output_channels[] = {temp_pdcch_symbols,dmrs_symbols};
778  free5GRAN::phy::signal_processing::channel_demapper(coreset_0_samples, ref, output_channels, channel_indexes, 2, pdcch_ss_mon_occ.n_symb_coreset, 12 * pdcch_ss_mon_occ.n_rb_coreset);
779  /*
780  * DMRS CCE-to-REG de-mapping/de-interleaving
781  */
782  for (int k = 0 ; k < agg_level; k ++){
783  for (int reg = 0; reg < free5GRAN::NUMBER_REG_PER_CCE; reg ++){
784  dmrs_sequence[((agg_level * free5GRAN::NUMBER_REG_PER_CCE * 3) / pdcch_ss_mon_occ.n_symb_coreset) * (reg%pdcch_ss_mon_occ.n_symb_coreset) + k * height_reg_rb * 3 + (reg/pdcch_ss_mon_occ.n_symb_coreset) * 3] = global_sequence[reg%pdcch_ss_mon_occ.n_symb_coreset][reg_bundles[k] * height_reg_rb * 3 + (reg/pdcch_ss_mon_occ.n_symb_coreset) * 3];
785  dmrs_sequence[((agg_level * free5GRAN::NUMBER_REG_PER_CCE * 3) / pdcch_ss_mon_occ.n_symb_coreset) * (reg%pdcch_ss_mon_occ.n_symb_coreset) + k * height_reg_rb * 3 + (reg/pdcch_ss_mon_occ.n_symb_coreset) * 3 + 1] = global_sequence[reg%pdcch_ss_mon_occ.n_symb_coreset][reg_bundles[k] * height_reg_rb * 3 + (reg/pdcch_ss_mon_occ.n_symb_coreset) * 3 + 1];
786  dmrs_sequence[((agg_level * free5GRAN::NUMBER_REG_PER_CCE * 3) / pdcch_ss_mon_occ.n_symb_coreset) * (reg%pdcch_ss_mon_occ.n_symb_coreset) + k * height_reg_rb * 3 + (reg/pdcch_ss_mon_occ.n_symb_coreset) * 3 + 2] = global_sequence[reg%pdcch_ss_mon_occ.n_symb_coreset][reg_bundles[k] * height_reg_rb * 3 + (reg/pdcch_ss_mon_occ.n_symb_coreset) * 3 + 2];
787  }
788  }
789  /*
790  * Channel estimation
791  */
792  free5GRAN::phy::signal_processing::channelEstimation(dmrs_symbols, dmrs_sequence, channel_indexes[1],coefficients, snr, 12 * pdcch_ss_mon_occ.n_rb_coreset, pdcch_ss_mon_occ.n_symb_coreset , agg_level * free5GRAN::NUMBER_REG_PER_CCE * 3);
793  /*
794  * Channel equalization
795  */
796  for (int sc = 0; sc < agg_level * free5GRAN::NUMBER_REG_PER_CCE * 9; sc ++){
797  pdcch_symbols[sc] = (temp_pdcch_symbols[sc]) * conj(coefficients[channel_indexes[0][0][sc]][channel_indexes[0][1][sc]]) / (float) pow(abs(coefficients[channel_indexes[0][0][sc]][channel_indexes[0][1][sc]]),2);
798  }
799  /*
800  * PDCCH and DCI decoding
801  */
802  free5GRAN::phy::physical_channel::decode_pdcch(pdcch_symbols,dci_bits,agg_level, reg_bundles_ns, reg_bundles, pci);
803  free5GRAN::phy::transport_channel::decode_dci(dci_bits, agg_level * free5GRAN::NUMBER_REG_PER_CCE * 9 * 2, K, free5GRAN::SI_RNTI, validated, dci_decoded_bits);
804  /*
805  * If DCI CRC is validated, candidate is validated, blind search ends
806  */
807  if (validated){
808  data_pdcch.open("output_files/pdcch_constellation.txt");
809  for (int sc = 0; sc < agg_level * free5GRAN::NUMBER_REG_PER_CCE * 9; sc ++){
810  data_pdcch << pdcch_symbols[sc];
811  data_pdcch << "\n";
812  }
813  data_pdcch.close();
814  goto dci_found_and_validated;
815  }
816 
817  }
818  }else {
819  break;
820  }
821  }
822  }
823 
824  dci_found_and_validated:
825  BOOST_LOG_TRIVIAL(trace) << "## DCI FOUND AND " << ((validated) ? "VALIDATED" : "NOT VALIDATED");
826 
827  dci_found = false;
828  if (validated){
829  parse_dci_1_0_si_rnti(dci_decoded_bits,freq_domain_ra_size,dci_1_0_si_rnti);
830  n_size_bwp = pdcch_ss_mon_occ.n_rb_coreset;
831  /*
832  * In current version, only redundancy version 0 and 3 are supported for DL-SCH decoding
833  */
834  if (dci_1_0_si_rnti.rv == 0 || dci_1_0_si_rnti.rv == 3){
835  dci_found = true;
836  }
837 
838  }
839 }
840 
846  cout << "###### DCI" << endl;
847  cout << "# RIV: " + to_string(dci_1_0_si_rnti.RIV)<< endl;
848  cout << "# Time Domain RA: " + to_string(dci_1_0_si_rnti.TD_ra) << endl;
849  cout << ((dci_1_0_si_rnti.vrb_prb_interleaving == 0 ) ? "# Non-interleaved VRB to PRB" : "# Interleaved VRB to PRB") << endl;
850  cout << "# Modulation coding scheme: " + to_string(dci_1_0_si_rnti.mcs) << endl;
851  cout << "# Redudancy version: " + to_string(dci_1_0_si_rnti.rv) << endl;
852  cout << ((dci_1_0_si_rnti.si == 0 ) ? "# SIB1 message" : "# Other SIB message") << endl;
853  cout << "#######################################################################" << endl;
854  if (dci_1_0_si_rnti.rv == 1 || dci_1_0_si_rnti.rv == 2){
855  cout << "WARNING: Redudancy version " + to_string(dci_1_0_si_rnti.rv) << " is not supported by current decoder. To decode SIB1 data on this cell, please use CELL_SEARCH function in config and specify the cell frequency. Retry until redundancy version is not 1 or 2" << endl;
856  cout << "#######################################################################" << endl;
857  }
858  cout << "\n";
859 }
860 
861 void phy::parse_dci_1_0_si_rnti(int *dci_bits, int freq_domain_ra_size, free5GRAN::dci_1_0_si_rnti &dci) {
870  dci.RIV = 0;
871  for (int i = 0 ; i < freq_domain_ra_size; i ++){
872  dci.RIV += dci_bits[i] * pow(2, freq_domain_ra_size - i - 1);
873  }
874  dci.TD_ra = 0;
875  for (int i = 0; i < 4; i ++){
876  dci.TD_ra += dci_bits[i + freq_domain_ra_size] * pow(2, 4 - i - 1);
877  }
878 
879  dci.vrb_prb_interleaving = dci_bits[freq_domain_ra_size + 4];
880 
881  dci.mcs = 0;
882  for (int i = 0; i < 5; i ++){
883  dci.mcs += dci_bits[i + freq_domain_ra_size + 4 + 1] * pow(2, 5 - i - 1);
884  }
885 
886  dci.rv = 0;
887  for (int i = 0; i < 2; i ++){
888  dci.rv += dci_bits[i + freq_domain_ra_size + 4 + 1 + 5] * pow(2, 2 - i - 1);
889  }
890 
891  dci.si = dci_bits[freq_domain_ra_size + 4 + 1 + 5 + 2];
892 }
893 
909  BOOST_LOG_TRIVIAL(trace) << "#### DECODING PDSCH";
910  /*
911  * Extracting PDSCH time and frequency position
912  */
913  int lrb, rb_start, k0, S, L, mod_order, code_rate, l0;
915  k0 = free5GRAN::TS_38_214_TABLE_5_1_2_1_1_2[dci_1_0_si_rnti.TD_ra][mib_object.dmrs_type_a_position - 2][1];
916  S = free5GRAN::TS_38_214_TABLE_5_1_2_1_1_2[dci_1_0_si_rnti.TD_ra][mib_object.dmrs_type_a_position - 2][2];
917  L = free5GRAN::TS_38_214_TABLE_5_1_2_1_1_2[dci_1_0_si_rnti.TD_ra][mib_object.dmrs_type_a_position - 2][3];
918  string mapping_type = ((free5GRAN::TS_38_214_TABLE_5_1_2_1_1_2[dci_1_0_si_rnti.TD_ra][mib_object.dmrs_type_a_position - 2][0] == 0 ) ? "A" : "B");
921  BOOST_LOG_TRIVIAL(trace) << "## Frequency domain RA: RB Start " + to_string(rb_start) + " and LRB " + to_string(lrb) ;
922  BOOST_LOG_TRIVIAL(trace) << "## Time domain RA: K0 " + to_string(k0) + ", S " + to_string(S) + " and L " + to_string(L) + " (mapping type "+mapping_type+")";
923  BOOST_LOG_TRIVIAL(trace) << "## MCS: Order " + to_string(mod_order) + " and code rate " + to_string(code_rate);
924  BOOST_LOG_TRIVIAL(trace) << "## Slot number " + to_string(pdcch_ss_mon_occ.n0 + pdcch_ss_mon_occ.monitoring_slot + k0);
925 
926  /*
927  * Compute number of additionnal DMRS positions
928  */
929  int additionnal_position;
930  if (mapping_type == "A"){
931  additionnal_position = 2;
932  }else {
933  if (L == 2 || L == 4){
934  additionnal_position = 0;
935  }else if(L == 7){
936  additionnal_position = 1;
937  }else {
938  additionnal_position = 0;
939  }
940  }
941 
942  int *dmrs_symbols, num_symbols_dmrs;
943  /*
944  * Get PDSCH DMRS symbols indexes
945  */
946  free5GRAN::phy::signal_processing::get_pdsch_dmrs_symbols(mapping_type, L + S, additionnal_position, mib_object.dmrs_type_a_position, &dmrs_symbols, num_symbols_dmrs);
947 
948  float snr;
949 
950  complex<float> dmrs_sequence[6 * lrb * num_symbols_dmrs];
951 
952  int count_dmrs_symbol = 0;
953 
954 
955  int num_symbols_per_subframe_pdsch = free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP * mib_object.scs/15;
956  int cp_lengths_pdsch[num_symbols_per_subframe_pdsch];
957  int cum_sum_pdsch[num_symbols_per_subframe_pdsch];
958 
959  vector<vector<complex<float>>> pdsch_ofdm_symbols(L, vector<complex<float>>(12 * pdcch_ss_mon_occ.n_rb_coreset)), pdsch_samples(L, vector<complex<float>>(12 * lrb));
960  vector<vector<vector<int>>> ref(2, vector<vector<int>>(L, vector<int>(12 * lrb)));
961  vector<vector<vector<int>>> channel_indexes = {vector<vector<int>>(2, vector<int>((size_t) 12 * lrb * (L - num_symbols_dmrs))), vector<vector<int>>(2, vector<int>((size_t) 6 * lrb * num_symbols_dmrs))};
962  vector<vector<complex<float>>> coefficients(L, vector<complex<float>>(12 * lrb));
963  complex<float> temp_dmrs_sequence[6 * pdcch_ss_mon_occ.n_rb_coreset], pdsch_samples_only[12 * lrb * (L - num_symbols_dmrs)], dmrs_samples_only[6 * lrb * num_symbols_dmrs];
964 
965  /*
966  * Compute PDSCH CP lengths (same as PDCCH, as it is the same BWP)
967  */
968  free5GRAN::phy::signal_processing::compute_cp_lengths(mib_object.scs, fft_size, is_extended_cp, num_symbols_per_subframe_pdsch, cp_lengths_pdsch, cum_sum_pdsch);
969 
970  /*
971  * Recover RE grid from time domain signal
972  */
973  free5GRAN::phy::signal_processing::fft(frame_data, pdsch_ofdm_symbols,fft_size,cp_lengths_pdsch,cum_sum_pdsch,L,12 * pdcch_ss_mon_occ.n_rb_coreset,S, (pdcch_ss_mon_occ.n0 + pdcch_ss_mon_occ.monitoring_slot + k0) * frame_size / num_slots_per_frame);
974 
975  bool dmrs_symbol_array[L];
976  /*
977  * PDSCH extraction
978  */
979  for (int symb = 0; symb < L; symb ++){
980  bool dmrs_symbol = false;
981  /*
982  * Check if studied symbol is a DMRS
983  */
984  for (int j = 0; j < num_symbols_dmrs; j ++){
985  if (symb + S == dmrs_symbols[j]){
986  dmrs_symbol = true;
987  break;
988  }
989  }
990  dmrs_symbol_array[symb] = dmrs_symbol;
991  /*
992  * Get DMRS sequence
993  */
994  free5GRAN::utils::sequence_generator::generate_pdsch_dmrs_sequence(free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP, pdcch_ss_mon_occ.n0 + pdcch_ss_mon_occ.monitoring_slot + k0, symb + S, 0, pci, temp_dmrs_sequence, 6 * pdcch_ss_mon_occ.n_rb_coreset);
995  if (dmrs_symbol){
996  for (int i = 0; i < 6 * lrb; i ++){
997  dmrs_sequence[count_dmrs_symbol * 6 * lrb + i] = temp_dmrs_sequence[rb_start * 6 + i];
998  }
999  count_dmrs_symbol += 1;
1000  }
1001 
1002  for (int i = 0; i < 12 * lrb; i ++){
1003  pdsch_samples[symb][i] = pdsch_ofdm_symbols[symb][12 * rb_start + i];
1004  }
1005  }
1006  free5GRAN::phy::physical_channel::compute_pdsch_indexes(ref, dmrs_symbol_array, L, lrb);
1007  /*
1008  * Channel de-mapping
1009  */
1010  complex<float>* output_channels[] = {pdsch_samples_only,dmrs_samples_only};
1011  free5GRAN::phy::signal_processing::channel_demapper(pdsch_samples, ref, output_channels, channel_indexes, 2, L, 12 * lrb);
1012  bool validated;
1013  float f0 = 0;
1014  /*
1015  * Phase decompensator. As phase compensation is not known a priori, we have to loop over different possibles phase compensation for decoding
1016  */
1017  for (int phase_decomp_index = 0; phase_decomp_index < 50; phase_decomp_index++){
1018  /*
1019  * Compute phase decomp value
1020  */
1021  f0 += (phase_decomp_index % 2) * pow(2,mu) * 1e3;
1022  float phase_offset = (phase_decomp_index % 2) ? f0 : -f0;
1023  BOOST_LOG_TRIVIAL(trace) << "PHASE DECOMP " << phase_offset ;
1024  complex<float> phase_decomp[num_symbols_per_subframe_pdsch];
1025  /*
1026  * Compute phase decompensation value for each symbol in a subframe
1027  */
1028  free5GRAN::phy::signal_processing::compute_phase_decomp(cp_lengths_pdsch, cum_sum_pdsch, rf_device->getSampleRate(),phase_offset,num_symbols_per_subframe_pdsch,phase_decomp);
1029  /*
1030  * Phase de-compensation
1031  */
1032  for (int samp = 0; samp < 12 * lrb * (L - num_symbols_dmrs); samp ++){
1033  pdsch_samples_only[samp] = pdsch_samples_only[samp] * phase_decomp[((pdcch_ss_mon_occ.n0 + pdcch_ss_mon_occ.monitoring_slot + k0) % (num_slots_per_frame / 10)) * free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP + S + channel_indexes[0][0][samp]];
1034  }
1035  for (int samp = 0; samp < 6 * lrb * num_symbols_dmrs; samp ++){
1036  dmrs_samples_only[samp] = dmrs_samples_only[samp] * phase_decomp[((pdcch_ss_mon_occ.n0 + pdcch_ss_mon_occ.monitoring_slot + k0) % (num_slots_per_frame / 10)) * free5GRAN::NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP + S + channel_indexes[1][0][samp]];
1037  }
1038  /*
1039  * Channel estimation
1040  */
1041  free5GRAN::phy::signal_processing::channelEstimation(dmrs_samples_only, dmrs_sequence, channel_indexes[1],coefficients, snr, 12 * lrb, L, 6 * lrb * num_symbols_dmrs);
1042  /*
1043  * Channel equalization
1044  */
1045  vector<complex<float>> pdsch_samples_vector((size_t) 12 * lrb * (L - num_symbols_dmrs));
1046  for (int sc = 0; sc < 12 * lrb * (L - num_symbols_dmrs); sc ++){
1047  pdsch_samples_vector[sc] = (pdsch_samples_only[sc]) * conj(coefficients[channel_indexes[0][0][sc]][channel_indexes[0][1][sc]]) / (float) pow(abs(coefficients[channel_indexes[0][0][sc]][channel_indexes[0][1][sc]]),2);
1048  }
1049 
1050  ofstream data_pdsch;
1051  data_pdsch.open("output_files/pdsch_constellation.txt");
1052  for (int i = 0; i < 12 * lrb * (L - num_symbols_dmrs); i ++){
1053  data_pdsch << pdsch_samples_vector[i];
1054  data_pdsch << "\n";
1055  }
1056  data_pdsch.close();
1057 
1058  /*
1059  * PDSCH and DL-SCH decoding
1060  */
1061  double dl_sch_bits[2 * pdsch_samples_vector.size()];
1062  free5GRAN::phy::physical_channel::decode_pdsch(pdsch_samples_vector, dl_sch_bits, pci);
1063  int n_re = free5GRAN::phy::signal_processing::compute_nre(L, num_symbols_dmrs);
1064 
1065  vector<int> desegmented = free5GRAN::phy::transport_channel::decode_dl_sch(dl_sch_bits, n_re, (float) code_rate / (float) 1024, lrb,2 * pdsch_samples_vector.size(), validated, dci_1_0_si_rnti);
1066  /*
1067  * If DL-SCH CRC is validated, Phase decompensation is validated
1068  */
1069  if (validated){
1070  for (int i =0; i < desegmented.size(); i ++){
1071  cout << desegmented[i];
1072  }
1073  cout << "\n";
1074  int bytes_size = (int) ceil(desegmented.size()/8.0);
1075  uint8_t dl_sch_bytes[bytes_size];
1076  for (int i = 0; i < desegmented.size(); i ++){
1077  if (i % 8 == 0){
1078  dl_sch_bytes[i/8] = 0;
1079  }
1080  dl_sch_bytes[i/8] += desegmented[i] * pow(2, 8 - (i%8) - 1);
1081  }
1082  asn_dec_rval_t dec_rval = asn_decode(0, ATS_UNALIGNED_BASIC_PER, &asn_DEF_BCCH_DL_SCH_Message,(void **) &sib1, dl_sch_bytes, bytes_size);
1083  if (dec_rval.code == RC_OK) {
1084  BOOST_LOG_TRIVIAL(trace) << "SIB1 parsing succeeded";
1085  }
1086  else {
1087  BOOST_LOG_TRIVIAL(trace) << "SIB1 parsing failed";
1088  }
1089  break;
1090  }
1091  }
1092 
1093 }
1094 
1095 BCCH_DL_SCH_Message_t *phy::getSib() {
1096  return this->sib1;
1097 }
1098 
1100  asn_fprint(stdout, &asn_DEF_BCCH_DL_SCH_Message, sib1);
1101 }
1102 
1104  return dci_1_0_si_rnti.rv;
1105 }
void compute_phase_decomp(int *cp_lengths, int *cum_sum_symb, float sampling_rate, float f0, int num_symb_per_subframes, complex< float > *phase_decomp_factor)
Definition: libphy.cpp:511
int NUMBER_SYMBOLS_PER_SLOT_NORMAL_CP
void get_candidates_frames_indexes(vector< vector< int >> &frame_indexes, int *frame_numbers, int sfn, int index_first_pss, int num_samples_before_pss, int frame_size)
Definition: libphy.cpp:580
void fft(vector< complex< float >> time_domain_signal, vector< vector< complex< float >>> &output_signal, int fft_size, int *cp_lengths, int *cum_sum_symb, int num_symbols, int num_sc_output, int first_symb_index, int offset)
Definition: libphy.cpp:543
void parse_dci_1_0_si_rnti(int *dci_bits, int freq_domain_ra_size, free5GRAN::dci_1_0_si_rnti &dci)
Definition: phy.cpp:861
void get_pdsch_dmrs_symbols(const string &type, int duration, int additionnal_position, int l0, int **output, int &size)
Definition: libphy.cpp:438
void search_pdcch(bool &validated)
Definition: phy.cpp:515
int TS_38_214_TABLE_5_1_2_1_1_2[16][2][4]
free5GRAN::pdcch_t0ss_monitoring_occasions compute_pdcch_t0_ss_monitoring_occasions(int pdcch_config, int pbch_scs, int common_scs, int i)
Definition: libphy.cpp:369
void search_pss(int &n_id_2, int &synchronisation_index, float &peak_value, int cp_length, vector< complex< float >> &buff, int fft_size)
void print_cell_info()
Definition: phy.cpp:476
void extract_pdsch()
Definition: phy.cpp:894
int SIZE_SSB_DMRS_SYMBOLS
void transpose_signal(vector< complex< float >> *input_signal, float freq_offset, int sample_rate, int input_length)
Definition: libphy.cpp:282
void decode_pbch(vector< complex< float >> pbch_symbols, int i_ssb, int pci, int *bch_bits)
void decode_pdsch(vector< complex< float >> pdsch_samples, double *unscrambled_soft_bits, int pci)
void compute_rb_start_lrb_dci(int RIV, int n_size_bwp, int &lrb, int &rb_start)
Definition: libphy.cpp:419
int extract_pbch()
Definition: phy.cpp:188
int TS_38_214_TABLE_5_1_3_1_1[29][2]
void generate_pbch_dmrs_sequence(int pci, int i_bar_ssb, complex< float > *output_sequence)
void channelEstimation(complex< float > *pilots, complex< float > *reference_pilot, vector< vector< int >> &pilot_indexes, vector< vector< complex< float >>> &coefficients, float &snr, int num_sc, int num_symbols, int pilot_size)
Definition: libphy.cpp:27
void generate_pdsch_dmrs_sequence(int n_symb_slot, int slot_number, int symbol_number, int n_scid, int n_id_scid, complex< float > *output_sequence, int size)
void compute_pdcch_indexes(vector< vector< vector< int >>> &ref, free5GRAN::pdcch_t0ss_monitoring_occasions pdcch_ss_mon_occ, int agg_level, int *reg_bundles, int height_reg_rb)
int SIZE_SSB_PBCH_SYMBOLS
void print_dci_info()
Definition: phy.cpp:841
BCCH_DL_SCH_Message_t * getSib()
Definition: phy.cpp:1095
void get_sss(int &n_id_1, float &peak_value, vector< complex< float >> &buff, int fft_size, int n_id_2)
int compute_nre(int num_symb_pdsch, int num_dmrs_symb)
Definition: libphy.cpp:532
void decode_pdcch(vector< complex< float >> pdcch_symbols, int *dci_bits, int agg_level, int *reg_index, int *reg_index_sorted, int pci)
int getSIB1RV()
Definition: phy.cpp:1103
void channel_demapper(vector< vector< complex< float >>> &input_signal, vector< vector< vector< int >>> &ref, complex< float > **output_channels, vector< vector< vector< int >>> &output_indexes, int num_channels, int num_symbols, int num_sc)
Definition: libphy.cpp:298
vector< int > decode_dl_sch(double *dl_sch_bits, int n_re, float R, int nrb, int E, bool &validated, free5GRAN::dci_1_0_si_rnti dci_1_0_si_rnti)
void compute_pdsch_indexes(vector< vector< vector< int >>> &ref, bool dmrs_symbol_array[], int L, int lrb)
void compute_cp_lengths(int scs, int nfft, int is_extended_cp, int num_symb_per_subframes, int *cp_lengths, int *cum_sum_cp_lengths)
Definition: libphy.cpp:483
void compute_fine_frequency_offset(vector< complex< float >> input_signal, int symbol_duration, int fft_size, int cp_length, int scs, float &output, int num_symbols)
Definition: libphy.cpp:247
void generate_pdcch_dmrs_sequence(int nid, int slot_number, int symbol_number, complex< float > *output_sequence, int size)
void compute_pbch_indexes(vector< vector< vector< int >>> &ref, int pci)
void decode_dci(int *dci_bits, int E, int K, int *rnti, bool &validated, int *decoded_dci_bits)
void parse_mib(int *mib_bits, free5GRAN::mib &mib_object)
int cell_synchronization(float &received_power)
Definition: phy.cpp:60
void print_sib1()
Definition: phy.cpp:1099
phy()
Definition: phy.cpp:472
void reconfigure(int fft_size)
Definition: phy.cpp:511
void decode_bch(int *bch_bits, bool &crc_validated, int *mib_bits, int pci)
struct free5GRAN::dci_1_0_si_rnti_ dci_1_0_si_rnti
Definition: rf.h:29