Proof of concept for fft beacon finder
This commit is contained in:
parent
1201e2fdf3
commit
22fcda3276
|
@ -5,61 +5,114 @@
|
|||
#include <stdio.h>
|
||||
|
||||
const float SAMPLINGRATE = 1000000.0;
|
||||
const float FFT_LEN = 256;
|
||||
const float FFT_LEN = 512;
|
||||
|
||||
int spectral_bin_to_fft_idx(int bin) {
|
||||
if(bin == 0) {
|
||||
return FFT_LEN/2;
|
||||
} else if(bin > 0) {
|
||||
return bin - 1;
|
||||
} else {
|
||||
return bin + FFT_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
FILE* output = fopen("output.csv", "w");
|
||||
FILE* output_csv = fopen("output.csv", "w");
|
||||
FILE* output = fopen("output.raw", "w");
|
||||
FILE* input = fopen("input.raw", "r");
|
||||
|
||||
nco_crcf correction = nco_crcf_create(LIQUID_NCO);
|
||||
nco_crcf_set_phase(correction, 0.0f);
|
||||
|
||||
float complex * fft_in = (float complex*) malloc(FFT_LEN * sizeof(float complex));
|
||||
float complex * fft_out = (float complex*) malloc(FFT_LEN * sizeof(float complex));
|
||||
|
||||
// create FFT plan
|
||||
fftplan fft = fft_create_plan(FFT_LEN, fft_in, fft_out, LIQUID_FFT_FORWARD, 0);
|
||||
|
||||
int next_fft_in = 0;
|
||||
int pos = 0;
|
||||
float in[2];
|
||||
|
||||
while(fread(in, sizeof(float), 2, input) == 2) {
|
||||
fft_in[pos] = (in[1] + I * in[0]);
|
||||
complex float cplx_in = (in[1] + I * in[0]);
|
||||
|
||||
if(next_fft_in <= 0) {
|
||||
fft_in[pos] = cplx_in;
|
||||
pos += 1;
|
||||
if(pos == FFT_LEN) {
|
||||
pos = 0;
|
||||
fft_execute(fft);
|
||||
|
||||
float fft_min = cabsf(fft_out[0]);
|
||||
float fft_max = cabsf(fft_out[0]);
|
||||
for(int i = 0; i < FFT_LEN; i++) {
|
||||
float mag = cabsf(fft_out[i]);
|
||||
if(mag < fft_min) {
|
||||
fft_min = mag;
|
||||
}
|
||||
if(mag > fft_max) {
|
||||
fft_max = mag;
|
||||
}
|
||||
}
|
||||
//printf("Min: %f Max: %f\n", fft_min, fft_max);
|
||||
|
||||
for(int i = FFT_LEN / 2; i < FFT_LEN; i++) {
|
||||
float mag = cabsf(fft_out[i]);
|
||||
mag = (mag - fft_min) / (fft_max - fft_min);
|
||||
fprintf(output, "%f;", mag);
|
||||
for(int bin = -FFT_LEN/2; bin < FFT_LEN/2; bin++) {
|
||||
int idx = spectral_bin_to_fft_idx(bin);
|
||||
float mag = cabsf(fft_out[idx]);
|
||||
mag = mag / fft_max;
|
||||
fprintf(output_csv, "%f;", mag);
|
||||
}
|
||||
|
||||
for(int i = 0; i < FFT_LEN / 2; i++) {
|
||||
float mag = cabsf(fft_out[i]);
|
||||
mag = (mag - fft_min) / (fft_max - fft_min);
|
||||
fprintf(output, "%f;", mag);
|
||||
printf("===========\n");
|
||||
float max_levels = 0;
|
||||
int max_center = 0;
|
||||
for(int bin = -50; bin <= 50; bin++) {
|
||||
int center_idx = spectral_bin_to_fft_idx(bin);
|
||||
float center_val = cabsf(fft_out[center_idx]) / fft_max;
|
||||
if(center_val > 0.25) {
|
||||
printf("Found peak candidate at %d\n", bin);
|
||||
int left_idx = spectral_bin_to_fft_idx(bin - 127);
|
||||
int right_idx = spectral_bin_to_fft_idx(bin + 127);
|
||||
float left_val = cabsf(fft_out[left_idx]) / fft_max;
|
||||
float right_val = cabsf(fft_out[right_idx]) / fft_max;
|
||||
|
||||
if(center_val + left_val + right_val > max_levels) {
|
||||
max_levels = center_val + left_val + right_val;
|
||||
max_center = bin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(output, "\n");
|
||||
if(max_levels > 0.0) {
|
||||
float center_freq = max_center * SAMPLINGRATE / FFT_LEN;
|
||||
printf("Found center at %f\n", center_freq);
|
||||
nco_crcf_set_frequency(correction, -(2 * M_PI * center_freq) / SAMPLINGRATE);
|
||||
}
|
||||
|
||||
fprintf(output_csv, "\n");
|
||||
|
||||
next_fft_in = SAMPLINGRATE / 10;
|
||||
}
|
||||
} else {
|
||||
next_fft_in--;
|
||||
}
|
||||
|
||||
float complex x;
|
||||
// increment internal phase
|
||||
nco_crcf_step(correction);
|
||||
// compute complex exponential
|
||||
nco_crcf_cexpf(correction, &x);
|
||||
|
||||
float complex cplx_out = cplx_in * x;
|
||||
|
||||
float buffer[] = {creal(cplx_out), cimag(cplx_out)};
|
||||
fwrite(buffer, sizeof(float), 2, output);
|
||||
}
|
||||
|
||||
fft_destroy_plan(fft);
|
||||
free(fft_in);
|
||||
free(fft_out);
|
||||
|
||||
fclose(output_csv);
|
||||
fclose(output);
|
||||
fclose(input);
|
||||
|
||||
|
|
|
@ -32,6 +32,27 @@ options:
|
|||
state: enabled
|
||||
|
||||
blocks:
|
||||
- name: offset
|
||||
id: variable_qtgui_range
|
||||
parameters:
|
||||
comment: ''
|
||||
gui_hint: ''
|
||||
label: ''
|
||||
min_len: '200'
|
||||
orient: QtCore.Qt.Horizontal
|
||||
rangeType: float
|
||||
start: '-35000'
|
||||
step: '1000'
|
||||
stop: '35000'
|
||||
value: '0'
|
||||
widget: counter_slider
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [448, 12.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: samp_rate
|
||||
id: variable
|
||||
parameters:
|
||||
|
@ -60,7 +81,7 @@ blocks:
|
|||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [984, 148.0]
|
||||
coordinate: [1152, 148.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: analog_sig_source_x_0
|
||||
|
@ -151,6 +172,28 @@ blocks:
|
|||
coordinate: [208, 404.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: analog_sig_source_x_1_0_0_0
|
||||
id: analog_sig_source_x
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
amp: '1'
|
||||
comment: ''
|
||||
freq: offset
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
offset: '0'
|
||||
phase: '0'
|
||||
samp_rate: samp_rate
|
||||
type: complex
|
||||
waveform: analog.GR_COS_WAVE
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [952, 476.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_add_xx_0
|
||||
id: blocks_add_xx
|
||||
parameters:
|
||||
|
@ -166,7 +209,7 @@ blocks:
|
|||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [1192, 240.0]
|
||||
coordinate: [1360, 240.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_add_xx_1
|
||||
|
@ -202,7 +245,7 @@ blocks:
|
|||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [1320, 236.0]
|
||||
coordinate: [1488, 236.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_multiply_xx_0
|
||||
|
@ -223,6 +266,24 @@ blocks:
|
|||
coordinate: [1048, 256.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_multiply_xx_0_0
|
||||
id: blocks_multiply_xx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
num_inputs: '2'
|
||||
type: complex
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [1192, 272.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_multiply_xx_1
|
||||
id: blocks_multiply_xx
|
||||
parameters:
|
||||
|
@ -251,7 +312,7 @@ blocks:
|
|||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samp_rate: samp_rate
|
||||
sensitivity: '10000'
|
||||
sensitivity: '40000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
|
@ -337,7 +398,7 @@ blocks:
|
|||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [1320, 124.0]
|
||||
coordinate: [1488, 124.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: rational_resampler_xxx_0
|
||||
|
@ -367,10 +428,12 @@ connections:
|
|||
- [analog_sig_source_x_1, '0', blocks_add_xx_1, '0']
|
||||
- [analog_sig_source_x_1_0, '0', blocks_add_xx_1, '1']
|
||||
- [analog_sig_source_x_1_0_0, '0', blocks_multiply_xx_1, '0']
|
||||
- [analog_sig_source_x_1_0_0_0, '0', blocks_multiply_xx_0_0, '1']
|
||||
- [blocks_add_xx_0, '0', blocks_file_sink_0, '0']
|
||||
- [blocks_add_xx_0, '0', qtgui_waterfall_sink_x_0, '0']
|
||||
- [blocks_add_xx_1, '0', blocks_multiply_xx_0, '0']
|
||||
- [blocks_multiply_xx_0, '0', blocks_add_xx_0, '1']
|
||||
- [blocks_multiply_xx_0, '0', blocks_multiply_xx_0_0, '0']
|
||||
- [blocks_multiply_xx_0_0, '0', blocks_add_xx_0, '1']
|
||||
- [blocks_multiply_xx_1, '0', blocks_add_xx_1, '2']
|
||||
- [blocks_vco_c_0, '0', blocks_multiply_xx_0, '1']
|
||||
- [blocks_vector_source_x_0, '0', rational_resampler_xxx_0, '0']
|
||||
|
|
|
@ -0,0 +1,341 @@
|
|||
options:
|
||||
parameters:
|
||||
author: ''
|
||||
catch_exceptions: 'True'
|
||||
category: '[GRC Hier Blocks]'
|
||||
cmake_opt: ''
|
||||
comment: ''
|
||||
copyright: ''
|
||||
description: ''
|
||||
gen_cmake: 'On'
|
||||
gen_linking: dynamic
|
||||
generate_options: qt_gui
|
||||
hier_block_src_path: '.:'
|
||||
id: view_waterfall
|
||||
max_nouts: '0'
|
||||
output_language: python
|
||||
placement: (0,0)
|
||||
qt_qss_theme: ''
|
||||
realtime_scheduling: ''
|
||||
run: 'True'
|
||||
run_command: '{python} -u {filename}'
|
||||
run_options: prompt
|
||||
sizing_mode: fixed
|
||||
thread_safe_setters: ''
|
||||
title: Not titled yet
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [8, 8]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
blocks:
|
||||
- name: samp_rate
|
||||
id: variable
|
||||
parameters:
|
||||
comment: ''
|
||||
value: '1000000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [184, 12]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_file_source_0
|
||||
id: blocks_file_source
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
begin_tag: pmt.PMT_NIL
|
||||
comment: ''
|
||||
file: /home/sebastian/projects/QO100-trx/prototypes/fft-beacon-finder/output.raw
|
||||
length: '0'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
offset: '0'
|
||||
repeat: 'False'
|
||||
type: complex
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [184, 212.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_file_source_0_0
|
||||
id: blocks_file_source
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
begin_tag: pmt.PMT_NIL
|
||||
comment: ''
|
||||
file: /home/sebastian/projects/QO100-trx/prototypes/fft-beacon-finder/input.raw
|
||||
length: '0'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
offset: '0'
|
||||
repeat: 'False'
|
||||
type: complex
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [176, 92.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_throttle_0
|
||||
id: blocks_throttle
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
ignoretag: 'True'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samples_per_second: samp_rate
|
||||
type: complex
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [496, 244.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_throttle_1
|
||||
id: blocks_throttle
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
ignoretag: 'True'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samples_per_second: samp_rate
|
||||
type: complex
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [400, 124.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: qtgui_freq_sink_x_0
|
||||
id: qtgui_freq_sink_x
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
alpha1: '1.0'
|
||||
alpha10: '1.0'
|
||||
alpha2: '1.0'
|
||||
alpha3: '1.0'
|
||||
alpha4: '1.0'
|
||||
alpha5: '1.0'
|
||||
alpha6: '1.0'
|
||||
alpha7: '1.0'
|
||||
alpha8: '1.0'
|
||||
alpha9: '1.0'
|
||||
autoscale: 'False'
|
||||
average: '1.0'
|
||||
axislabels: 'True'
|
||||
bw: samp_rate
|
||||
color1: '"blue"'
|
||||
color10: '"dark blue"'
|
||||
color2: '"red"'
|
||||
color3: '"green"'
|
||||
color4: '"black"'
|
||||
color5: '"cyan"'
|
||||
color6: '"magenta"'
|
||||
color7: '"yellow"'
|
||||
color8: '"dark red"'
|
||||
color9: '"dark green"'
|
||||
comment: ''
|
||||
ctrlpanel: 'False'
|
||||
fc: '0'
|
||||
fftsize: '4096'
|
||||
freqhalf: 'True'
|
||||
grid: 'True'
|
||||
gui_hint: ''
|
||||
label: Relative Gain
|
||||
label1: ''
|
||||
label10: ''''''
|
||||
label2: ''''''
|
||||
label3: ''''''
|
||||
label4: ''''''
|
||||
label5: ''''''
|
||||
label6: ''''''
|
||||
label7: ''''''
|
||||
label8: ''''''
|
||||
label9: ''''''
|
||||
legend: 'True'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
name: '""'
|
||||
nconnections: '1'
|
||||
norm_window: 'False'
|
||||
showports: 'False'
|
||||
tr_chan: '0'
|
||||
tr_level: '0.0'
|
||||
tr_mode: qtgui.TRIG_MODE_FREE
|
||||
tr_tag: '""'
|
||||
type: complex
|
||||
units: dB
|
||||
update_time: '0.10'
|
||||
width1: '1'
|
||||
width10: '1'
|
||||
width2: '1'
|
||||
width3: '1'
|
||||
width4: '1'
|
||||
width5: '1'
|
||||
width6: '1'
|
||||
width7: '1'
|
||||
width8: '1'
|
||||
width9: '1'
|
||||
wintype: window.WIN_BLACKMAN_hARRIS
|
||||
ymax: '10'
|
||||
ymin: '-140'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [712, 156.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: qtgui_waterfall_sink_x_0
|
||||
id: qtgui_waterfall_sink_x
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
alpha1: '1.0'
|
||||
alpha10: '1.0'
|
||||
alpha2: '1.0'
|
||||
alpha3: '1.0'
|
||||
alpha4: '1.0'
|
||||
alpha5: '1.0'
|
||||
alpha6: '1.0'
|
||||
alpha7: '1.0'
|
||||
alpha8: '1.0'
|
||||
alpha9: '1.0'
|
||||
axislabels: 'True'
|
||||
bw: samp_rate
|
||||
color1: '0'
|
||||
color10: '0'
|
||||
color2: '0'
|
||||
color3: '0'
|
||||
color4: '0'
|
||||
color5: '0'
|
||||
color6: '0'
|
||||
color7: '0'
|
||||
color8: '0'
|
||||
color9: '0'
|
||||
comment: ''
|
||||
fc: '0'
|
||||
fftsize: '4096'
|
||||
freqhalf: 'True'
|
||||
grid: 'True'
|
||||
gui_hint: ''
|
||||
int_max: '10'
|
||||
int_min: '-140'
|
||||
label1: ''
|
||||
label10: ''
|
||||
label2: ''
|
||||
label3: ''
|
||||
label4: ''
|
||||
label5: ''
|
||||
label6: ''
|
||||
label7: ''
|
||||
label8: ''
|
||||
label9: ''
|
||||
legend: 'True'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
name: '""'
|
||||
nconnections: '1'
|
||||
showports: 'False'
|
||||
type: complex
|
||||
update_time: '0.10'
|
||||
wintype: window.WIN_BLACKMAN_hARRIS
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [704, 348.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: qtgui_waterfall_sink_x_0_0
|
||||
id: qtgui_waterfall_sink_x
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
alpha1: '1.0'
|
||||
alpha10: '1.0'
|
||||
alpha2: '1.0'
|
||||
alpha3: '1.0'
|
||||
alpha4: '1.0'
|
||||
alpha5: '1.0'
|
||||
alpha6: '1.0'
|
||||
alpha7: '1.0'
|
||||
alpha8: '1.0'
|
||||
alpha9: '1.0'
|
||||
axislabels: 'True'
|
||||
bw: samp_rate
|
||||
color1: '0'
|
||||
color10: '0'
|
||||
color2: '0'
|
||||
color3: '0'
|
||||
color4: '0'
|
||||
color5: '0'
|
||||
color6: '0'
|
||||
color7: '0'
|
||||
color8: '0'
|
||||
color9: '0'
|
||||
comment: ''
|
||||
fc: '0'
|
||||
fftsize: '4096'
|
||||
freqhalf: 'True'
|
||||
grid: 'True'
|
||||
gui_hint: ''
|
||||
int_max: '10'
|
||||
int_min: '-140'
|
||||
label1: ''
|
||||
label10: ''
|
||||
label2: ''
|
||||
label3: ''
|
||||
label4: ''
|
||||
label5: ''
|
||||
label6: ''
|
||||
label7: ''
|
||||
label8: ''
|
||||
label9: ''
|
||||
legend: 'True'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
name: '""'
|
||||
nconnections: '1'
|
||||
showports: 'False'
|
||||
type: complex
|
||||
update_time: '0.10'
|
||||
wintype: window.WIN_BLACKMAN_hARRIS
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [696, 60.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
|
||||
connections:
|
||||
- [blocks_file_source_0, '0', blocks_throttle_0, '0']
|
||||
- [blocks_file_source_0_0, '0', blocks_throttle_1, '0']
|
||||
- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
|
||||
- [blocks_throttle_0, '0', qtgui_waterfall_sink_x_0, '0']
|
||||
- [blocks_throttle_1, '0', qtgui_waterfall_sink_x_0_0, '0']
|
||||
|
||||
metadata:
|
||||
file_format: 1
|
Loading…
Reference in New Issue