void lpf_peak_pick(float *foff, float *max, COMP pilot_baseband[], COMP pilot_lpf[], fft_cfg fft_pilot_cfg, COMP S[], int nin) { int i,j,k; int mpilot; COMP s[MPILOTFFT]; float mag, imax; int ix; float r; /* LPF cutoff 200Hz, so we can handle max +/- 200 Hz freq offset */ for(i=0; i<NPILOTLPF-nin; i++) pilot_lpf[i] = pilot_lpf[nin+i]; for(i=NPILOTLPF-nin, j=0; i<NPILOTLPF; i++,j++) { pilot_lpf[i].real = 0.0; pilot_lpf[i].imag = 0.0; for(k=0; k<NPILOTCOEFF; k++) pilot_lpf[i] = cadd(pilot_lpf[i], fcmult(pilot_coeff[k], pilot_baseband[j+k])); } /* decimate to improve DFT resolution, window and DFT */ mpilot = FS/(2*200); /* calc decimation rate given new sample rate is twice LPF freq */ init_comp_array(s, MPILOTFFT); for(i=0,j=0; i<NPILOTLPF; i+=mpilot,j++) { s[j] = fcmult(hanning[i], pilot_lpf[i]); } fft_do(fft_pilot_cfg, s, S); /* peak pick and convert to Hz */ imax = 0.0; ix = 0; for(i=0; i<MPILOTFFT; i++) { mag = S[i].real*S[i].real + S[i].imag*S[i].imag; if (mag > imax) { imax = mag; ix = i; } } r = 2.0*200.0/MPILOTFFT; /* maps FFT bin to frequency in Hz */ if (ix >= MPILOTFFT/2) *foff = (ix - MPILOTFFT)*r; else *foff = (ix)*r; *max = imax; }
void CODEC2_WIN32SUPPORT fdmdv_get_rx_spectrum(struct FDMDV *f, float mag_spec_dB[], COMP rx_fdm[], int nin) { int i,j; COMP fft_in[2*FDMDV_NSPEC]; COMP fft_out[2*FDMDV_NSPEC]; float full_scale_dB; /* update buffer of input samples */ for(i=0; i<2*FDMDV_NSPEC-nin; i++) f->fft_buf[i] = f->fft_buf[i+nin]; for(j=0; j<nin; j++,i++) f->fft_buf[i] = rx_fdm[j].real; assert(i == 2*FDMDV_NSPEC); /* window and FFT */ for(i=0; i<2*FDMDV_NSPEC; i++) { fft_in[i].real = f->fft_buf[i] * (0.5 - 0.5*cosf((float)i*2.0*PI/(2*FDMDV_NSPEC))); fft_in[i].imag = 0.0; } fft_do(f->fft_cfg, fft_in, fft_out); /* FFT scales up a signal of level 1 FDMDV_NSPEC */ full_scale_dB = 20*log10f(FDMDV_NSPEC); /* scale and convert to dB */ for(i=0; i<FDMDV_NSPEC; i++) { mag_spec_dB[i] = 10.0*log10f(fft_out[i].real*fft_out[i].real + fft_out[i].imag*fft_out[i].imag); mag_spec_dB[i] -= full_scale_dB; } }
void draw_fft(void) { double mx_mag = 0.0; int index = 0, highest = 0; int cx = 0, cy = 0; /* double max_freq = hz / 2.0; */ double highest_freq = 0, avg_freq_index = 0.0, total_val = 0.0, avg_freq = 0.0; int dummy = 0; getyx(w_slow, cy, cx); for(index=0; index<max_x; index++) { double val = 0.0; if (history_set[index]) val = history[index]; else val = index > 0 ? history[index - 1] : 0; if (val > graph_limit) val = graph_limit; history_temp[index] = val; } fft_do(history_temp, history_fft_magn, history_fft_phase); for(index=1; index<max_x/2; index++) { avg_freq_index += (double)index * history_fft_magn[index]; total_val += history_fft_magn[index]; if (history_fft_magn[index] > mx_mag) { mx_mag = history_fft_magn[index]; highest = index; } } highest_freq = (hz / (double)max_x) * (double)highest; avg_freq_index /= total_val; avg_freq = (hz / (double)max_x) * avg_freq_index; wattron(w_line1, A_REVERSE); myprintloc(w_line1, 0, 38, gettext("highest: %6.2fHz, avg: %6.2fHz"), highest_freq, avg_freq); wattroff(w_line1, A_REVERSE); wnoutrefresh(w_line1); dummy = max_x / 2 + 1; if (draw_phase) { int y = 0; for(y=0; y<slow_n; y++) mvwchgat(w_slow, y, dummy, 1, A_REVERSE, C_WHITE, NULL); for(index=0; index<slow_n; index++) mvwchgat(w_slow, index, 0, max_x, A_NORMAL, C_WHITE, NULL); for(index=1; index<dummy - 1; index++) draw_rad_column(w_slow, index - 1, history_fft_phase[index]); } else { for(index=0; index<slow_n; index++) mvwchgat(w_slow, index, max_x / 2, max_x / 2, A_NORMAL, C_WHITE, NULL); } for(index=1; index<dummy; index++) { int height_magn = (int)((double)slow_n * (history_fft_magn[index] / mx_mag)); draw_column(w_slow, max_x / 2 + index - 1, height_magn, 0, 0); } wmove(w_slow, cy, cx); wnoutrefresh(w_slow); }