Merge pull request #1153 from greatscottgadgets/measure-power
Measure digital signal power, not amplitude in hackrf_transfer
This commit is contained in:
@ -343,17 +343,8 @@ uint32_t stream_tail = 0;
|
|||||||
uint32_t stream_drop = 0;
|
uint32_t stream_drop = 0;
|
||||||
uint8_t* stream_buf = NULL;
|
uint8_t* stream_buf = NULL;
|
||||||
|
|
||||||
/*
|
/* sum of power of all samples, reset on the periodic report */
|
||||||
* To report amplitude, best would be dB(fullscale) and the variance,
|
volatile uint64_t stream_power = 0;
|
||||||
* but that would require more math per sample (dB(amplitude) = log(sqrt(i^2 + q^2) and sum of squares).
|
|
||||||
* For now, just sum iabs(i)+iabs(q) and divide by the number of samples*2.
|
|
||||||
* That allows us to give a measure of dB(fullscale).
|
|
||||||
* I don't know whether overload causes wrapping or clamping the 8-bit values.
|
|
||||||
* Clamping would produce a sigmoid curve, so with a signal of variable intensity you're
|
|
||||||
* probably getting substantial overload anytime this reports more than about -6dBfs.
|
|
||||||
*/
|
|
||||||
uint64_t stream_amplitude =
|
|
||||||
0; /* sum of magnitudes of all I&Q samples, reset on the periodic report */
|
|
||||||
|
|
||||||
bool transmit = false;
|
bool transmit = false;
|
||||||
struct timeval time_start;
|
struct timeval time_start;
|
||||||
@ -419,8 +410,18 @@ int rx_callback(hackrf_transfer* transfer)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte_count += transfer->valid_length;
|
/* Accumulate power (magnitude squared). */
|
||||||
bytes_to_write = transfer->valid_length;
|
bytes_to_write = transfer->valid_length;
|
||||||
|
uint64_t sum = 0;
|
||||||
|
for (i = 0; i < bytes_to_write; i++) {
|
||||||
|
int8_t value = transfer->buffer[i];
|
||||||
|
sum += value * value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update both running totals at approximately the same time. */
|
||||||
|
byte_count += transfer->valid_length;
|
||||||
|
stream_power += sum;
|
||||||
|
|
||||||
if (limit_num_samples) {
|
if (limit_num_samples) {
|
||||||
if (bytes_to_write >= bytes_to_xfer) {
|
if (bytes_to_write >= bytes_to_xfer) {
|
||||||
bytes_to_write = bytes_to_xfer;
|
bytes_to_write = bytes_to_xfer;
|
||||||
@ -428,11 +429,6 @@ int rx_callback(hackrf_transfer* transfer)
|
|||||||
bytes_to_xfer -= bytes_to_write;
|
bytes_to_xfer -= bytes_to_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
// accumulate stream_amplitude:
|
|
||||||
for (i = 0; i < bytes_to_write; i++) {
|
|
||||||
stream_amplitude += abs((signed char) transfer->buffer[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (receive_wav) {
|
if (receive_wav) {
|
||||||
/* convert .wav contents from signed to unsigned */
|
/* convert .wav contents from signed to unsigned */
|
||||||
for (i = 0; i < bytes_to_write; i++) {
|
for (i = 0; i < bytes_to_write; i++) {
|
||||||
@ -487,12 +483,19 @@ int tx_callback(hackrf_transfer* transfer)
|
|||||||
stop_main_loop();
|
stop_main_loop();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
byte_count += transfer->valid_length;
|
|
||||||
|
/* Accumulate power (magnitude squared). */
|
||||||
bytes_to_read = transfer->valid_length;
|
bytes_to_read = transfer->valid_length;
|
||||||
|
uint64_t sum = 0;
|
||||||
for (i = 0; i < bytes_to_read; i++) {
|
for (i = 0; i < bytes_to_read; i++) {
|
||||||
stream_amplitude += abs((signed char) transfer->buffer[i]);
|
int8_t value = transfer->buffer[i];
|
||||||
|
sum += value * value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update both running totals at approximately the same time. */
|
||||||
|
byte_count += transfer->valid_length;
|
||||||
|
stream_power += sum;
|
||||||
|
|
||||||
if (file == NULL) { // transceiver_mode == TRANSCEIVER_MODE_SS
|
if (file == NULL) { // transceiver_mode == TRANSCEIVER_MODE_SS
|
||||||
/* Transmit continuous wave with specific amplitude */
|
/* Transmit continuous wave with specific amplitude */
|
||||||
if (limit_num_samples) {
|
if (limit_num_samples) {
|
||||||
@ -503,7 +506,7 @@ int tx_callback(hackrf_transfer* transfer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < bytes_to_read; i++)
|
for (i = 0; i < bytes_to_read; i++)
|
||||||
transfer->buffer[i] = amplitude;
|
transfer->buffer[i] = -(uint8_t) amplitude;
|
||||||
|
|
||||||
if (limit_num_samples && (bytes_to_xfer == 0)) {
|
if (limit_num_samples && (bytes_to_xfer == 0)) {
|
||||||
stop_main_loop();
|
stop_main_loop();
|
||||||
@ -625,7 +628,7 @@ static void usage()
|
|||||||
printf("\t[-S buf_size] # Enable receive streaming with buffer size buf_size.\n");
|
printf("\t[-S buf_size] # Enable receive streaming with buffer size buf_size.\n");
|
||||||
#endif
|
#endif
|
||||||
printf("\t[-B] # Print buffer statistics during transfer\n");
|
printf("\t[-B] # Print buffer statistics during transfer\n");
|
||||||
printf("\t[-c amplitude] # CW signal source mode, amplitude 0-127 (DC value to DAC).\n");
|
printf("\t[-c amplitude] # CW signal source mode, amplitude 0-128 (DC value to DAC).\n");
|
||||||
printf("\t[-R] # Repeat TX mode (default is off) \n");
|
printf("\t[-R] # Repeat TX mode (default is off) \n");
|
||||||
printf("\t[-b baseband_filter_bw_hz] # Set baseband filter bandwidth in Hz.\n");
|
printf("\t[-b baseband_filter_bw_hz] # Set baseband filter bandwidth in Hz.\n");
|
||||||
printf("\tPossible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz, default <= 0.75 * sample_rate_hz.\n");
|
printf("\tPossible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz, default <= 0.75 * sample_rate_hz.\n");
|
||||||
@ -680,6 +683,7 @@ int main(int argc, char** argv)
|
|||||||
unsigned int lna_gain = 8, vga_gain = 20, txvga_gain = 0;
|
unsigned int lna_gain = 8, vga_gain = 20, txvga_gain = 0;
|
||||||
hackrf_m0_state state;
|
hackrf_m0_state state;
|
||||||
stats_t stats = {0, 0};
|
stats_t stats = {0, 0};
|
||||||
|
static int32_t preload_bytes = 0;
|
||||||
|
|
||||||
while ((opt =
|
while ((opt =
|
||||||
getopt(argc,
|
getopt(argc,
|
||||||
@ -1012,9 +1016,9 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
if (signalsource) {
|
if (signalsource) {
|
||||||
transceiver_mode = TRANSCEIVER_MODE_SS;
|
transceiver_mode = TRANSCEIVER_MODE_SS;
|
||||||
if (amplitude > 127) {
|
if (amplitude > 128) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"argument error: amplitude shall be in between 0 and 127.\n");
|
"argument error: amplitude must be between 0 and 128.\n");
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -1269,9 +1273,11 @@ int main(int argc, char** argv)
|
|||||||
.it_value = {.tv_sec = 1, .tv_usec = 0}};
|
.it_value = {.tv_sec = 1, .tv_usec = 0}};
|
||||||
setitimer(ITIMER_REAL, &interval_timer, NULL);
|
setitimer(ITIMER_REAL, &interval_timer, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
preload_bytes = hackrf_get_transfer_queue_depth(device) *
|
||||||
|
hackrf_get_transfer_buffer_size(device);
|
||||||
|
|
||||||
while ((hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false)) {
|
while ((hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false)) {
|
||||||
uint32_t byte_count_now;
|
uint64_t byte_count_now;
|
||||||
struct timeval time_now;
|
struct timeval time_now;
|
||||||
float time_difference, rate;
|
float time_difference, rate;
|
||||||
if (stream_size > 0) {
|
if (stream_size > 0) {
|
||||||
@ -1304,7 +1310,7 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
uint64_t stream_amplitude_now;
|
uint64_t stream_power_now;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Wait for interval timer event, or interrupt event.
|
// Wait for interval timer event, or interrupt event.
|
||||||
HANDLE handles[] = {timer_handle, interrupt_handle};
|
HANDLE handles[] = {timer_handle, interrupt_handle};
|
||||||
@ -1315,13 +1321,28 @@ int main(int argc, char** argv)
|
|||||||
#endif
|
#endif
|
||||||
gettimeofday(&time_now, NULL);
|
gettimeofday(&time_now, NULL);
|
||||||
|
|
||||||
|
/* Read and reset both totals at approximately the same time. */
|
||||||
byte_count_now = byte_count;
|
byte_count_now = byte_count;
|
||||||
|
stream_power_now = stream_power;
|
||||||
byte_count = 0;
|
byte_count = 0;
|
||||||
stream_amplitude_now = stream_amplitude;
|
stream_power = 0;
|
||||||
stream_amplitude = 0;
|
|
||||||
if (byte_count_now <
|
/*
|
||||||
sample_rate_hz / 20) // Don't report on very short frames
|
* The TX callback is called to preload the USB
|
||||||
stream_amplitude_now = 0;
|
* transfer buffers at the start of TX. This results in
|
||||||
|
* invalid statistics collected about the empty buffers
|
||||||
|
* before any USB transfer is completed. We skip these
|
||||||
|
* statistics and do not report them to the user.
|
||||||
|
*/
|
||||||
|
if (preload_bytes > 0) {
|
||||||
|
if (preload_bytes > byte_count_now) {
|
||||||
|
preload_bytes -= byte_count_now;
|
||||||
|
byte_count_now = 0;
|
||||||
|
} else {
|
||||||
|
byte_count_now -= preload_bytes;
|
||||||
|
preload_bytes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
time_difference = TimevalDiff(&time_now, &time_start);
|
time_difference = TimevalDiff(&time_now, &time_start);
|
||||||
rate = (float) byte_count_now / time_difference;
|
rate = (float) byte_count_now / time_difference;
|
||||||
@ -1329,21 +1350,15 @@ int main(int argc, char** argv)
|
|||||||
hw_sync_enable != 0) {
|
hw_sync_enable != 0) {
|
||||||
fprintf(stderr, "Waiting for sync...\n");
|
fprintf(stderr, "Waiting for sync...\n");
|
||||||
} else {
|
} else {
|
||||||
// This is only an approximate measure, to assist getting receive levels right:
|
double full_scale_ratio = (double) stream_power_now /
|
||||||
double full_scale_ratio =
|
(byte_count_now * 128 * 128);
|
||||||
((double) stream_amplitude_now /
|
double dB_full_scale = 10 * log10(full_scale_ratio);
|
||||||
(byte_count_now ? byte_count_now : 1)) /
|
|
||||||
128;
|
|
||||||
double dB_full_scale_ratio = 10 * log10(full_scale_ratio);
|
|
||||||
// Guard against ridiculous reports
|
|
||||||
if (dB_full_scale_ratio > 1)
|
|
||||||
dB_full_scale_ratio = -0.0;
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%4.1f MiB / %5.3f sec = %4.1f MiB/second, amplitude %3.1f dBfs",
|
"%4.1f MiB / %5.3f sec = %4.1f MiB/second, average power %3.1f dBfs",
|
||||||
(byte_count_now / 1e6f),
|
(byte_count_now / 1e6f),
|
||||||
time_difference,
|
time_difference,
|
||||||
(rate / 1e6f),
|
(rate / 1e6f),
|
||||||
dB_full_scale_ratio);
|
dB_full_scale);
|
||||||
if (display_stats) {
|
if (display_stats) {
|
||||||
bool tx = transmit || signalsource;
|
bool tx = transmit || signalsource;
|
||||||
result = update_stats(device, &state, &stats);
|
result = update_stats(device, &state, &stats);
|
||||||
|
@ -2685,6 +2685,26 @@ int ADDCALL hackrf_start_rx_sweep(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get USB transfer buffer size.
|
||||||
|
* @return size in bytes
|
||||||
|
*/
|
||||||
|
size_t ADDCALL hackrf_get_transfer_buffer_size(hackrf_device* device)
|
||||||
|
{
|
||||||
|
(void) device;
|
||||||
|
return TRANSFER_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the total number of USB transfer buffers.
|
||||||
|
* @return number of buffers
|
||||||
|
*/
|
||||||
|
uint32_t ADDCALL hackrf_get_transfer_queue_depth(hackrf_device* device)
|
||||||
|
{
|
||||||
|
(void) device;
|
||||||
|
return TRANSFER_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // __cplusplus defined.
|
} // __cplusplus defined.
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,6 +25,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI
|
|||||||
#define __HACKRF_H__
|
#define __HACKRF_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define ADD_EXPORTS
|
#define ADD_EXPORTS
|
||||||
@ -458,6 +459,10 @@ extern ADDAPI int ADDCALL hackrf_start_rx_sweep(
|
|||||||
hackrf_sample_block_cb_fn callback,
|
hackrf_sample_block_cb_fn callback,
|
||||||
void* rx_ctx);
|
void* rx_ctx);
|
||||||
|
|
||||||
|
extern ADDAPI size_t ADDCALL hackrf_get_transfer_buffer_size(hackrf_device* device);
|
||||||
|
|
||||||
|
extern ADDAPI uint32_t ADDCALL hackrf_get_transfer_queue_depth(hackrf_device* device);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // __cplusplus defined.
|
} // __cplusplus defined.
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user