#include #include #include #include #include #include #include #include #include "lte.h" #define DISABLE_UHD #ifndef DISABLE_UHD #include "uhd.h" #include "uhd_utils.h" #endif #define MHZ 1000000 #define SAMP_FREQ 1920000 #define RSSI_FS 1000000 #define FLEN 9600 #define FLEN_PERIOD 0.005 #define RSSI_DECIM 20 #define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold) int band, earfcn=-1; float find_threshold = 40.0, track_threshold = 8.0; int earfcn_start=-1, earfcn_end = -1; float rssi_threshold = -30.0; int max_track_lost=9; int nof_frames_find=8, nof_frames_track=100, nof_samples_rssi=50000; int track_len=500; int nof_ports; cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; pbch_t pbch; lte_fft_t fft; chest_t chest; sync_t sfind, strack; float *cfo_v; int *idx_v, *idx_valid, *t; float *p2a_v; void *uhd; int nof_bands; float gain = 20.0; #define MAX_EARFCN 1000 lte_earfcn_t channels[MAX_EARFCN]; float rssi[MAX_EARFCN]; float rssi_d[MAX_EARFCN/RSSI_DECIM]; float freqs[MAX_EARFCN]; float cfo[MAX_EARFCN]; float p2a[MAX_EARFCN]; enum sync_state {INIT, FIND, TRACK, MIB, DONE}; void print_to_matlab(); void usage(char *prog) { printf("Usage: %s [seRrFfTtgv] -b band\n", prog); printf("\t-s earfcn_start [Default All]\n"); printf("\t-e earfcn_end [Default All]\n"); printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi); printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold); printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find); printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold); printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track); printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold); printf("\t-l pss_track_len [Default %d]\n", track_len); printf("\t-g gain [Default %.2f dB]\n", gain); printf("\t-v [set verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) { switch(opt) { case 'b': band = atoi(argv[optind]); break; case 's': earfcn_start = atoi(argv[optind]); break; case 'e': earfcn_end = atoi(argv[optind]); break; case 'R': nof_samples_rssi = atoi(argv[optind]); break; case 'r': rssi_threshold = -atof(argv[optind]); break; case 'F': nof_frames_find = atoi(argv[optind]); break; case 'f': find_threshold = atof(argv[optind]); break; case 'T': nof_frames_track = atoi(argv[optind]); break; case 't': track_threshold = atof(argv[optind]); break; case 'g': gain = atof(argv[optind]); break; case 'v': verbose++; break; default: usage(argv[0]); exit(-1); } } } int base_init(int frame_length) { int i; input_buffer = malloc(2 * frame_length * sizeof(cf_t)); if (!input_buffer) { perror("malloc"); return -1; } fft_buffer = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); if (!fft_buffer) { perror("malloc"); return -1; } for (i=0;i 0) { return mean/n; } else { return 0.0; } } int preprocess_idx(int *in, int *out, int *period, int len) { int i, n; n=0; for (i=0;i 100) { /* scan every Mhz, that is 10 freqs */ for (i=0;i= nof_frames_find) { state = INIT; freq++; } } break; case TRACK: INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx + track_len); track_idx = sync_run(&strack, input_buffer, FLEN + find_idx - track_len); p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); /* save cell id for the best peak-to-avg */ if (p2a_v[frame_cnt] > max_peak_to_avg) { max_peak_to_avg = p2a_v[frame_cnt]; cell_id = sync_get_cell_id(&strack); } if (track_idx != -1) { cfo_v[frame_cnt] = sync_get_cfo(&strack); last_found = frame_cnt; find_idx += track_idx - track_len; idx_v[frame_cnt] = find_idx; nslot = sync_get_slot_id(&strack); } else { idx_v[frame_cnt] = -1; cfo_v[frame_cnt] = 0.0; } /* if we missed to many PSS it is not a cell, next freq */ if (frame_cnt - last_found > max_track_lost) { INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands, channels[freq].id, channels[freq].fd, frame_cnt - last_found); state = INIT; freq++; } else if (frame_cnt >= nof_frames_track) { state = MIB; nslot=(nslot+10)%20; } break; case MIB: INFO("Finding MIB at freq %.2f Mhz\n", channels[freq].fd); cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt); p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt); valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt); sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD); // TODO: Correct SFO // Correct CFO INFO("Correcting CFO=%.4f\n", cfo[freq]); nco_cexp_f_direct(&input_buffer[FLEN], -cfo[freq]/128, FLEN); if (nslot == 10) { if (mib_decoder_run(&input_buffer[FLEN+find_idx+FLEN/10], &mib)) { INFO("MIB detected attempt=%d\n", mib_attempts); state = DONE; } else { INFO("MIB not detected attempt=%d\n", mib_attempts); if (mib_attempts >= 20) { freq++; state = INIT; } } mib_attempts++; } else { nslot = (nslot+10)%20; } break; case DONE: printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. " "PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands, channels[freq].id, channels[freq].fd, 10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id); pbch_mib_fprint(stdout, &mib); state = INIT; freq++; break; } /** FIXME: This is not necessary at all */ if (state == TRACK || (state == FIND && frame_cnt)) { memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t)); } frame_cnt++; } } print_to_matlab(); base_free(); printf("\n\nDone\n"); exit(0); } void print_to_matlab() { int i; FILE *f = fopen("output.m", "w"); if (!f) { perror("fopen"); exit(-1); } fprintf(f, "fd=["); for (i=0;i