diff --git a/analyzer/analyzer.c b/analyzer/analyzer.c index 6d6efbc..faefb2c 100644 --- a/analyzer/analyzer.c +++ b/analyzer/analyzer.c @@ -504,6 +504,12 @@ suscan_analyzer_set_hop_range(suscan_analyzer_t *self, SUFREQ min, SUFREQ max) return (self->iface->set_hop_range) (self->impl, min, max); } +SUBOOL +suscan_analyzer_set_rel_bandwidth(suscan_analyzer_t *self, SUFLOAT rel_bw) +{ + return (self->iface->set_rel_bandwidth) (self->impl, rel_bw); +} + SUBOOL suscan_analyzer_set_buffering_size(suscan_analyzer_t *self, SUSCOUNT size) { diff --git a/analyzer/analyzer.h b/analyzer/analyzer.h index fda8fd0..b96c1cf 100644 --- a/analyzer/analyzer.h +++ b/analyzer/analyzer.h @@ -132,6 +132,7 @@ struct suscan_analyzer_sweep_params { SUFREQ min_freq; SUFREQ max_freq; + SUFLOAT rel_bw; SUSCOUNT fft_min_samples; /* Minimum number of FFT frames before updating */ }; @@ -193,6 +194,7 @@ struct suscan_analyzer_interface { SUBOOL (*set_sweep_strategy) (void *, enum suscan_analyzer_sweep_strategy); SUBOOL (*set_spectrum_partitioning) (void *, enum suscan_analyzer_spectrum_partitioning); SUBOOL (*set_hop_range) (void *, SUFREQ, SUFREQ); + SUBOOL (*set_rel_bandwidth) (void *, SUFLOAT); SUBOOL (*set_buffering_size) (void *, SUSCOUNT); /* Fast methods */ @@ -399,6 +401,18 @@ SUBOOL suscan_analyzer_set_hop_range( SUFREQ min, SUFREQ max); +/*! + * In wideband analyzers, set the the frequency step interval as a + * fraction of the sample rate. + * \param self a pointer to the analyzer object + * \param rel_bw fraction of the sample rate to advance per hop + * \return SU_TRUE for success or SU_FALSE on failure + * \author Sultan Qasim Khan + */ +SUBOOL suscan_analyzer_set_rel_bandwidth( + suscan_analyzer_t *self, + SUFLOAT rel_bw); + /*! * In wideband analyzers, set the sweep strategy. * \param self a pointer to the analyzer object diff --git a/analyzer/impl/local.c b/analyzer/impl/local.c index d2a2021..da8fd13 100644 --- a/analyzer/impl/local.c +++ b/analyzer/impl/local.c @@ -668,6 +668,7 @@ suscan_local_analyzer_ctor(suscan_analyzer_t *parent, va_list ap) SUSCAN_ANALYZER_MIN_POST_HOP_FFTS * det_params.window_size; new->current_sweep_params.max_freq = parent->params.max_freq; new->current_sweep_params.min_freq = parent->params.min_freq; + new->current_sweep_params.rel_bw = 0.5; } else { SU_TRYCATCH( suscan_local_analyzer_init_channel_worker(new), @@ -1027,6 +1028,31 @@ suscan_local_analyzer_set_hop_range(void *ptr, SUFREQ min, SUFREQ max) return ok; } +SUPRIVATE SUBOOL +suscan_local_analyzer_set_rel_bandwidth(void *ptr, SUFLOAT rel_bw) +{ + suscan_local_analyzer_t *self = (suscan_local_analyzer_t *) ptr; + SUBOOL ok = SU_FALSE; + + SU_TRYCATCH( + self->parent->params.mode == SUSCAN_ANALYZER_MODE_WIDE_SPECTRUM, + goto done); + + SU_TRYCATCH(rel_bw >= 0.001, goto done); + + self->pending_sweep_params = + self->sweep_params_requested + ? self->pending_sweep_params + : self->current_sweep_params; + self->pending_sweep_params.rel_bw = rel_bw; + self->sweep_params_requested = SU_TRUE; + + ok = SU_TRUE; + +done: + return ok; +} + SUPRIVATE SUBOOL suscan_local_analyzer_set_buffering_size( void *ptr, @@ -1178,6 +1204,7 @@ suscan_local_analyzer_get_interface(void) SET_CALLBACK(set_sweep_strategy); SET_CALLBACK(set_spectrum_partitioning); SET_CALLBACK(set_hop_range); + SET_CALLBACK(set_rel_bandwidth); SET_CALLBACK(set_buffering_size); SET_CALLBACK(set_inspector_frequency); SET_CALLBACK(set_inspector_bandwidth); diff --git a/analyzer/impl/remote.c b/analyzer/impl/remote.c index 6894bc4..f10b186 100644 --- a/analyzer/impl/remote.c +++ b/analyzer/impl/remote.c @@ -445,6 +445,10 @@ SUSCAN_SERIALIZER_PROTO(suscan_analyzer_remote_call) SUSCAN_PACK(freq, self->hop_range.max); break; + case SUSCAN_ANALYZER_REMOTE_SET_REL_BANDWIDTH: + SUSCAN_PACK(float, self->rel_bw); + break; + case SUSCAN_ANALYZER_REMOTE_SET_BUFFERING_SIZE: SUSCAN_PACK(uint, self->buffering_size); break; @@ -558,6 +562,12 @@ SUSCAN_DESERIALIZER_PROTO(suscan_analyzer_remote_call) SU_TRYCATCH(self->hop_range.min < self->hop_range.max, goto fail); break; + case SUSCAN_ANALYZER_REMOTE_SET_REL_BANDWIDTH: + SUSCAN_UNPACK(float, self->rel_bw); + + SU_TRYCATCH(self->rel_bw >= 0.001, goto fail); + break; + case SUSCAN_ANALYZER_REMOTE_SET_BUFFERING_SIZE: SUSCAN_UNPACK(uint32, self->buffering_size); break; @@ -2561,6 +2571,34 @@ suscan_remote_analyzer_set_hop_range(void *ptr, SUFREQ min, SUFREQ max) return ok; } +SUPRIVATE SUBOOL +suscan_remote_analyzer_set_rel_bandwidth(void *ptr, SUFLOAT rel_bw) +{ + suscan_remote_analyzer_t *self = (suscan_remote_analyzer_t *) ptr; + struct suscan_analyzer_remote_call *call = NULL; + SUBOOL ok = SU_FALSE; + + SU_TRYCATCH( + call = suscan_remote_analyzer_acquire_call( + self, + SUSCAN_ANALYZER_REMOTE_SET_REL_BANDWIDTH), + goto done); + + call->rel_bw = rel_bw; + + SU_TRYCATCH( + suscan_remote_analyzer_queue_call(self, call, SU_TRUE), + goto done); + + ok = SU_TRUE; + +done: + if (call != NULL) + suscan_remote_analyzer_release_call(self, call); + + return ok; +} + SUPRIVATE SUBOOL suscan_remote_analyzer_set_buffering_size(void *ptr, SUSCOUNT size) { @@ -2673,6 +2711,7 @@ suscan_remote_analyzer_get_interface(void) SET_CALLBACK(set_sweep_strategy); SET_CALLBACK(set_spectrum_partitioning); SET_CALLBACK(set_hop_range); + SET_CALLBACK(set_rel_bandwidth); SET_CALLBACK(set_buffering_size); SET_CALLBACK(write); SET_CALLBACK(req_halt); diff --git a/analyzer/impl/remote.h b/analyzer/impl/remote.h index b0f4e1a..208ee28 100644 --- a/analyzer/impl/remote.h +++ b/analyzer/impl/remote.h @@ -70,6 +70,7 @@ enum suscan_analyzer_remote_type { SUSCAN_ANALYZER_REMOTE_SET_SWEEP_STRATEGY, SUSCAN_ANALYZER_REMOTE_SET_SPECTRUM_PARTITIONING, SUSCAN_ANALYZER_REMOTE_SET_HOP_RANGE, + SUSCAN_ANALYZER_REMOTE_SET_REL_BANDWIDTH, SUSCAN_ANALYZER_REMOTE_SET_BUFFERING_SIZE, SUSCAN_ANALYZER_REMOTE_MESSAGE, SUSCAN_ANALYZER_REMOTE_REQ_HALT, @@ -199,6 +200,7 @@ SUSCAN_SERIALIZABLE(suscan_analyzer_remote_call) { char *antenna; SUFLOAT bandwidth; SUFLOAT ppm; + SUFLOAT rel_bw; SUBOOL dc_remove; SUBOOL iq_reverse; SUBOOL agc; diff --git a/analyzer/workers/wide.c b/analyzer/workers/wide.c index 4794c45..aabe4df 100644 --- a/analyzer/workers/wide.c +++ b/analyzer/workers/wide.c @@ -48,7 +48,7 @@ suscan_local_analyzer_hop(suscan_local_analyzer_t *self) SUFREQ fs = suscan_analyzer_get_samp_rate(self->parent); SUFREQ part_bw = self->current_sweep_params.partitioning == SUSCAN_ANALYZER_SPECTRUM_PARTITIONING_DISCRETE - ? fs / 2 + ? fs * self->current_sweep_params.rel_bw : 1; SUFREQ bw = self->current_sweep_params.max_freq @@ -78,15 +78,25 @@ suscan_local_analyzer_hop(suscan_local_analyzer_t *self) break; case SUSCAN_ANALYZER_SWEEP_STRATEGY_PROGRESSIVE: - /* - * Progressive strategy: traverse the spectrum monotonically, - * in fixed steps of fs / 2 - */ - next = (fs / 2) * self->part_ndx++ - + self->current_sweep_params.min_freq; - if (next > self->current_sweep_params.max_freq) { - next = self->current_sweep_params.min_freq; - self->part_ndx = 1; + /* Progressive strategy: traverse the spectrum monotonically */ + if (self->current_sweep_params.partitioning == + SUSCAN_ANALYZER_SPECTRUM_PARTITIONING_DISCRETE) { + /* Discrete: advance in fixed steps of fs * rel_bw */ + next = part_bw * self->part_ndx++ + + self->current_sweep_params.min_freq; + if (next > self->current_sweep_params.max_freq) { + next = self->current_sweep_params.min_freq; + self->part_ndx = 1; + } + } else { + /* Continuous: advance monotonically in randomized steps */ + SUFLOAT step_size = fs * self->current_sweep_params.rel_bw; + SUFLOAT freq_jiggle = SU_FLOOR(step_size * rnd * 0.2); + next = self->curr_freq + step_size - freq_jiggle; + if (next > self->current_sweep_params.max_freq) { + next = self->current_sweep_params.min_freq + step_size * 0.5 + - freq_jiggle; + } } break; } diff --git a/cli/devserv/server.c b/cli/devserv/server.c index 22ca6c6..be258fe 100644 --- a/cli/devserv/server.c +++ b/cli/devserv/server.c @@ -919,6 +919,14 @@ suscli_analyzer_server_deliver_call( goto done); break; + case SUSCAN_ANALYZER_REMOTE_SET_REL_BANDWIDTH: + SU_TRYCATCH( + suscan_analyzer_set_rel_bandwidth( + self->analyzer, + call->rel_bw), + goto done); + break; + case SUSCAN_ANALYZER_REMOTE_SET_BUFFERING_SIZE: SU_TRYCATCH( suscan_analyzer_set_buffering_size(