From 13e4dea446442a05d89b7ea130dbc78f9078ffb9 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 19 Feb 2017 11:10:30 -0700 Subject: [PATCH 1/5] hackrf_sweep: avoid starting RX too early --- host/hackrf-tools/src/hackrf_sweep.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_sweep.c b/host/hackrf-tools/src/hackrf_sweep.c index 3d400942..61a4272b 100644 --- a/host/hackrf-tools/src/hackrf_sweep.c +++ b/host/hackrf-tools/src/hackrf_sweep.c @@ -581,12 +581,6 @@ int main(int argc, char** argv) { result = hackrf_set_vga_gain(device, vga_gain); result |= hackrf_set_lna_gain(device, lna_gain); - result |= hackrf_start_rx(device, rx_callback, NULL); - if (result != HACKRF_SUCCESS) { - fprintf(stderr, "hackrf_start_rx() failed: %s (%d)\n", hackrf_error_name(result), result); - usage(); - return EXIT_FAILURE; - } /* * For each range, plan a whole number of tuning steps of a certain @@ -601,6 +595,13 @@ int main(int argc, char** argv) { frequencies[2*i], frequencies[2*i+1]); } + result |= hackrf_start_rx(device, rx_callback, NULL); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_start_rx() failed: %s (%d)\n", hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + result = hackrf_init_sweep(device, frequencies, num_ranges, num_samples * 2, TUNE_STEP * FREQ_ONE_MHZ, OFFSET, INTERLEAVED); if( result != HACKRF_SUCCESS ) { From f34cc960ffa338c49f196599569f80dbf35f60f2 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 20 Feb 2017 21:07:00 -0700 Subject: [PATCH 2/5] hackrf_sweep: Added experimental Inverse FFT binary output mode. In this mode, FFT output bins from multiple hops are stitched together into a single set of bins per sweep. Each sweep is then processed with an inverse FFT to simulate a time domain signal at a sample rate equal to the sweep bandwidth. This wideband time domain signal is sent to the output as complex floats and can be piped to or viewed with tools such as fosphor or inspectrum. The output signal is discontinuous, so the time axis (e.g. in inspectrum) will be incorrect. --- host/hackrf-tools/src/hackrf_sweep.c | 68 ++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_sweep.c b/host/hackrf-tools/src/hackrf_sweep.c index 61a4272b..ba43bfad 100644 --- a/host/hackrf-tools/src/hackrf_sweep.c +++ b/host/hackrf-tools/src/hackrf_sweep.c @@ -108,6 +108,7 @@ int gettimeofday(struct timeval *tv, void* ignored) { uint32_t num_samples = SAMPLES_PER_BLOCK; int num_ranges = 0; uint16_t frequencies[MAX_SWEEP_RANGES*2]; +int step_count; static float TimevalDiff(const struct timeval *a, const struct timeval *b) { return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec); @@ -175,6 +176,7 @@ bool antenna = false; uint32_t antenna_enable; bool binary_output = false; +bool ifft_output = false; bool one_shot = false; volatile bool sweep_started = false; @@ -183,6 +185,10 @@ double fft_bin_width; fftwf_complex *fftwIn = NULL; fftwf_complex *fftwOut = NULL; fftwf_plan fftwPlan = NULL; +fftwf_complex *ifftwIn = NULL; +fftwf_complex *ifftwOut = NULL; +fftwf_plan ifftwPlan = NULL; +uint32_t ifft_idx = 0; float* pwr; float* window; @@ -200,7 +206,7 @@ int rx_callback(hackrf_transfer* transfer) { uint64_t frequency; /* in Hz */ uint64_t band_edge; uint32_t record_length; - int i, j; + int i, j, ifft_bins; struct tm *fft_time; char time_str[50]; struct timeval usb_transfer_time; @@ -212,6 +218,7 @@ int rx_callback(hackrf_transfer* transfer) { gettimeofday(&usb_transfer_time, NULL); byte_count += transfer->valid_length; buf = (int8_t*) transfer->buffer; + ifft_bins = fftSize * step_count; for(j=0; j i; i++) { + ifftwIn[ifft_idx + i][0] = fftwOut[i + 1 + (fftSize*5)/8][0]; + ifftwIn[ifft_idx + i][1] = fftwOut[i + 1 + (fftSize*5)/8][1]; + } + ifft_idx += fftSize / 2; + ifft_idx %= ifft_bins; + for(i = 0; (fftSize / 4) > i; i++) { + ifftwIn[ifft_idx + i][0] = fftwOut[i + 1 + (fftSize/8)][0]; + ifftwIn[ifft_idx + i][1] = fftwOut[i + 1 + (fftSize/8)][1]; + } } else { fft_time = localtime(&time_stamp.tv_sec); strftime(time_str, 50, "%Y-%m-%d, %H:%M:%S", fft_time); @@ -285,8 +315,8 @@ int rx_callback(hackrf_transfer* transfer) { (uint64_t)(frequency+DEFAULT_SAMPLE_RATE_HZ/4), fft_bin_width, fftSize); - for(i=1+(fftSize*5)/8; (1+(fftSize*7)/8) > i; i++) { - fprintf(fd, ", %.2f", pwr[i]); + for(i = 0; (fftSize / 4) > i; i++) { + fprintf(fd, ", %.2f", pwr[i + 1 + (fftSize*5)/8]); } fprintf(fd, "\n"); fprintf(fd, "%s.%06ld, %" PRIu64 ", %" PRIu64 ", %.2f, %u", @@ -296,8 +326,8 @@ int rx_callback(hackrf_transfer* transfer) { (uint64_t)(frequency+((DEFAULT_SAMPLE_RATE_HZ*3)/4)), fft_bin_width, fftSize); - for(i=1+fftSize/8; (1+(fftSize*3)/8) > i; i++) { - fprintf(fd, ", %.2f", pwr[i]); + for(i = 0; (fftSize / 4) > i; i++) { + fprintf(fd, ", %.2f", pwr[i + 1 + (fftSize/8)]); } fprintf(fd, "\n"); } @@ -318,6 +348,7 @@ static void usage() { fprintf(stderr, "\t[-w bin_width] # FFT bin width (frequency resolution) in Hz\n"); fprintf(stderr, "\t[-1] # one shot mode\n"); fprintf(stderr, "\t[-B] # binary output\n"); + fprintf(stderr, "\t[-I] # binary inverse FFT output\n"); fprintf(stderr, "\t-r filename # output file"); fprintf(stderr, "\n"); fprintf(stderr, "Output fields:\n"); @@ -351,13 +382,12 @@ int main(int argc, char** argv) { struct timeval t_end; float time_diff; unsigned int lna_gain=16, vga_gain=20; - int step_count; uint32_t freq_min = 0; uint32_t freq_max = 6000; uint32_t requested_fft_bin_width; - while( (opt = getopt(argc, argv, "a:f:p:l:g:d:n:w:1Br:h?")) != EOF ) { + while( (opt = getopt(argc, argv, "a:f:p:l:g:d:n:w:1BIr:h?")) != EOF ) { result = HACKRF_SUCCESS; switch( opt ) { @@ -427,6 +457,10 @@ int main(int argc, char** argv) { binary_output = true; break; + case 'I': + ifft_output = true; + break; + case 'r': path = optarg; break; @@ -487,6 +521,16 @@ int main(int argc, char** argv) { num_ranges++; } + if(binary_output && ifft_output) { + fprintf(stderr, "argument error: binary output (-B) and IFFT output (-I) are mutually exclusive.\n"); + return EXIT_FAILURE; + } + + if(ifft_output && (1 < num_ranges)) { + fprintf(stderr, "argument error: only one frequency range is supported in IFFT output (-I) mode.\n"); + return EXIT_FAILURE; + } + if(4 > fftSize) { fprintf(stderr, "argument error: FFT bin width (-w) must be no more than one quarter the sample rate\n"); @@ -595,6 +639,10 @@ int main(int argc, char** argv) { frequencies[2*i], frequencies[2*i+1]); } + ifftwIn = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize * step_count); + ifftwOut = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize * step_count); + ifftwPlan = fftwf_plan_dft_1d(fftSize * step_count, ifftwIn, ifftwOut, FFTW_BACKWARD, FFTW_MEASURE); + result |= hackrf_start_rx(device, rx_callback, NULL); if (result != HACKRF_SUCCESS) { fprintf(stderr, "hackrf_start_rx() failed: %s (%d)\n", hackrf_error_name(result), result); @@ -703,6 +751,8 @@ int main(int argc, char** argv) { fftwf_free(fftwOut); fftwf_free(pwr); fftwf_free(window); + fftwf_free(ifftwIn); + fftwf_free(ifftwOut); fprintf(stderr, "exit\n"); return exit_code; } From 886ba6acfb7961fa331050567f49619dbd78799d Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 20 Feb 2017 21:42:02 -0700 Subject: [PATCH 3/5] hackrf_sweep: corrected output file descriptors in binary and ifft modes for compatibility with output file option --- host/hackrf-tools/src/hackrf_sweep.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_sweep.c b/host/hackrf-tools/src/hackrf_sweep.c index ba43bfad..6eec1ea8 100644 --- a/host/hackrf-tools/src/hackrf_sweep.c +++ b/host/hackrf-tools/src/hackrf_sweep.c @@ -235,8 +235,8 @@ int rx_callback(hackrf_transfer* transfer) { for(i=0; i < ifft_bins; i++) { ifftwOut[i][0] *= 1.0f / ifft_bins; ifftwOut[i][1] *= 1.0f / ifft_bins; - fwrite(&ifftwOut[i][0], sizeof(float), 1, stdout); - fwrite(&ifftwOut[i][1], sizeof(float), 1, stdout); + fwrite(&ifftwOut[i][0], sizeof(float), 1, fd); + fwrite(&ifftwOut[i][1], sizeof(float), 1, fd); } if(one_shot) { do_exit = true; @@ -281,19 +281,19 @@ int rx_callback(hackrf_transfer* transfer) { record_length = 2 * sizeof(band_edge) + (fftSize/4) * sizeof(float); - fwrite(&record_length, sizeof(record_length), 1, stdout); + fwrite(&record_length, sizeof(record_length), 1, fd); band_edge = frequency; - fwrite(&band_edge, sizeof(band_edge), 1, stdout); + fwrite(&band_edge, sizeof(band_edge), 1, fd); band_edge = frequency + DEFAULT_SAMPLE_RATE_HZ / 4; - fwrite(&band_edge, sizeof(band_edge), 1, stdout); - fwrite(&pwr[1+(fftSize*5)/8], sizeof(float), fftSize/4, stdout); + fwrite(&band_edge, sizeof(band_edge), 1, fd); + fwrite(&pwr[1+(fftSize*5)/8], sizeof(float), fftSize/4, fd); - fwrite(&record_length, sizeof(record_length), 1, stdout); + fwrite(&record_length, sizeof(record_length), 1, fd); band_edge = frequency + DEFAULT_SAMPLE_RATE_HZ / 2; - fwrite(&band_edge, sizeof(band_edge), 1, stdout); + fwrite(&band_edge, sizeof(band_edge), 1, fd); band_edge = frequency + (DEFAULT_SAMPLE_RATE_HZ * 3) / 4; - fwrite(&band_edge, sizeof(band_edge), 1, stdout); - fwrite(&pwr[1+fftSize/8], sizeof(float), fftSize/4, stdout); + fwrite(&band_edge, sizeof(band_edge), 1, fd); + fwrite(&pwr[1+fftSize/8], sizeof(float), fftSize/4, fd); } else if(ifft_output) { for(i = 0; (fftSize / 4) > i; i++) { ifftwIn[ifft_idx + i][0] = fftwOut[i + 1 + (fftSize*5)/8][0]; From 9baac3996206a8c5347af41439e5b0f600ed3db1 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Tue, 21 Feb 2017 12:18:41 -0700 Subject: [PATCH 4/5] hackrf_sweep: suppress ifft output unless requested --- host/hackrf-tools/src/hackrf_sweep.c | 30 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_sweep.c b/host/hackrf-tools/src/hackrf_sweep.c index 6eec1ea8..925fd329 100644 --- a/host/hackrf-tools/src/hackrf_sweep.c +++ b/host/hackrf-tools/src/hackrf_sweep.c @@ -231,12 +231,14 @@ int rx_callback(hackrf_transfer* transfer) { } if (frequency == (uint64_t)(FREQ_ONE_MHZ*frequencies[0])) { if(sweep_started) { - fftwf_execute(ifftwPlan); - for(i=0; i < ifft_bins; i++) { - ifftwOut[i][0] *= 1.0f / ifft_bins; - ifftwOut[i][1] *= 1.0f / ifft_bins; - fwrite(&ifftwOut[i][0], sizeof(float), 1, fd); - fwrite(&ifftwOut[i][1], sizeof(float), 1, fd); + if(ifft_output) { + fftwf_execute(ifftwPlan); + for(i=0; i < ifft_bins; i++) { + ifftwOut[i][0] *= 1.0f / ifft_bins; + ifftwOut[i][1] *= 1.0f / ifft_bins; + fwrite(&ifftwOut[i][0], sizeof(float), 1, fd); + fwrite(&ifftwOut[i][1], sizeof(float), 1, fd); + } } if(one_shot) { do_exit = true; @@ -274,9 +276,6 @@ int rx_callback(hackrf_transfer* transfer) { for (i=0; i < fftSize; i++) { pwr[i] = logPower(fftwOut[i], 1.0f / fftSize); } - ifft_idx = round((frequency - (uint64_t)(FREQ_ONE_MHZ*frequencies[0])) - / fft_bin_width); - ifft_idx = (ifft_idx + ifft_bins/2) % ifft_bins; if(binary_output) { record_length = 2 * sizeof(band_edge) + (fftSize/4) * sizeof(float); @@ -295,6 +294,9 @@ int rx_callback(hackrf_transfer* transfer) { fwrite(&band_edge, sizeof(band_edge), 1, fd); fwrite(&pwr[1+fftSize/8], sizeof(float), fftSize/4, fd); } else if(ifft_output) { + ifft_idx = round((frequency - (uint64_t)(FREQ_ONE_MHZ*frequencies[0])) + / fft_bin_width); + ifft_idx = (ifft_idx + ifft_bins/2) % ifft_bins; for(i = 0; (fftSize / 4) > i; i++) { ifftwIn[ifft_idx + i][0] = fftwOut[i + 1 + (fftSize*5)/8][0]; ifftwIn[ifft_idx + i][1] = fftwOut[i + 1 + (fftSize*5)/8][1]; @@ -349,7 +351,7 @@ static void usage() { fprintf(stderr, "\t[-1] # one shot mode\n"); fprintf(stderr, "\t[-B] # binary output\n"); fprintf(stderr, "\t[-I] # binary inverse FFT output\n"); - fprintf(stderr, "\t-r filename # output file"); + fprintf(stderr, "\t-r filename # output file\n"); fprintf(stderr, "\n"); fprintf(stderr, "Output fields:\n"); fprintf(stderr, "\tdate, time, hz_low, hz_high, hz_bin_width, num_samples, dB, dB, . . .\n"); @@ -639,9 +641,11 @@ int main(int argc, char** argv) { frequencies[2*i], frequencies[2*i+1]); } - ifftwIn = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize * step_count); - ifftwOut = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize * step_count); - ifftwPlan = fftwf_plan_dft_1d(fftSize * step_count, ifftwIn, ifftwOut, FFTW_BACKWARD, FFTW_MEASURE); + if(ifft_output) { + ifftwIn = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize * step_count); + ifftwOut = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize * step_count); + ifftwPlan = fftwf_plan_dft_1d(fftSize * step_count, ifftwIn, ifftwOut, FFTW_BACKWARD, FFTW_MEASURE); + } result |= hackrf_start_rx(device, rx_callback, NULL); if (result != HACKRF_SUCCESS) { From c7956b49b173b766a64aa7a7be540c5f923c3662 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Tue, 21 Feb 2017 12:43:46 -0700 Subject: [PATCH 5/5] hackrf_sweep: report sweep rate instead of data rate --- host/hackrf-tools/src/hackrf_sweep.c | 35 +++++++++++++--------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_sweep.c b/host/hackrf-tools/src/hackrf_sweep.c index 925fd329..c0c81b0a 100644 --- a/host/hackrf-tools/src/hackrf_sweep.c +++ b/host/hackrf-tools/src/hackrf_sweep.c @@ -164,6 +164,7 @@ volatile bool do_exit = false; FILE* fd = NULL; volatile uint32_t byte_count = 0; +volatile uint64_t sweep_count = 0; struct timeval time_start; struct timeval t_start; @@ -240,6 +241,7 @@ int rx_callback(hackrf_transfer* transfer) { fwrite(&ifftwOut[i][1], sizeof(float), 1, fd); } } + sweep_count++; if(one_shot) { do_exit = true; } @@ -381,8 +383,9 @@ int main(int argc, char** argv) { const char* path = NULL; const char* serial_number = NULL; int exit_code = EXIT_SUCCESS; - struct timeval t_end; + struct timeval time_now; float time_diff; + float sweep_rate; unsigned int lna_gain=16, vga_gain=20; uint32_t freq_min = 0; uint32_t freq_max = 6000; @@ -685,32 +688,25 @@ int main(int argc, char** argv) { } gettimeofday(&t_start, NULL); - gettimeofday(&time_start, NULL); fprintf(stderr, "Stop with Ctrl-C\n"); while((hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false)) { - uint32_t byte_count_now; - struct timeval time_now; - float time_difference, rate; + float time_difference; sleep(1); gettimeofday(&time_now, NULL); - byte_count_now = byte_count; - byte_count = 0; - - time_difference = TimevalDiff(&time_now, &time_start); - rate = (float)byte_count_now / time_difference; - fprintf(stderr, "%4.1f MiB / %5.3f sec = %4.1f MiB/second\n", - (byte_count_now / 1e6f), time_difference, (rate / 1e6f) ); + time_difference = TimevalDiff(&time_now, &t_start); + sweep_rate = (float)sweep_count / time_difference; + fprintf(stderr, "%" PRIu64 " total sweeps completed, %.2f sweeps/second\n", + sweep_count, sweep_rate); - time_start = time_now; - - if (byte_count_now == 0) { + if (byte_count == 0) { exit_code = EXIT_FAILURE; - fprintf(stderr, "\nCouldn't transfer any bytes for one second.\n"); + fprintf(stderr, "\nCouldn't transfer any data for one second.\n"); break; } + byte_count = 0; } result = hackrf_is_streaming(device); @@ -721,9 +717,10 @@ int main(int argc, char** argv) { hackrf_error_name(result), result); } - gettimeofday(&t_end, NULL); - time_diff = TimevalDiff(&t_end, &t_start); - fprintf(stderr, "Total time: %5.5f s\n", time_diff); + gettimeofday(&time_now, NULL); + time_diff = TimevalDiff(&time_now, &t_start); + fprintf(stderr, "Total sweeps: %" PRIu64 " in %.5f seconds (%.2f sweeps/second)\n", + sweep_count, time_diff, sweep_rate); if(device != NULL) { result = hackrf_stop_rx(device);