SDR: Add option to set local oscillator (LO) offset

By default it is set to -1 MHz.
This commit is contained in:
Andreas Eversberg 2017-12-04 14:12:11 +01:00
parent c49ee3b2a8
commit 9f901384de
10 changed files with 58 additions and 30 deletions

View File

@ -77,9 +77,7 @@ In case of B-Netz, I use the following parameters:
# bnetz --sdr-soapy \ # bnetz --sdr-soapy \
--sdr-tx-gain 50 \ --sdr-tx-gain 50 \
--sdr-rx-gain 30 \ --sdr-rx-gain 30 \
--sdr-bandwidth 5000000 \
--sdr-samplerate 5000000 \ --sdr-samplerate 5000000 \
--sdr-tune-args "OFFSET=1000000" \
-s 100000 \ -s 100000 \
-k 17 -k 17
@ -89,10 +87,10 @@ In case of B-Netz, I use the following parameters:
In order to change from analog sound card to SDR, you need <b>--sdr-soapy</b> option. In order to change from analog sound card to SDR, you need <b>--sdr-soapy</b> option.
In my setup I use antennas directly connected to the SDR. In my setup I use antennas directly connected to the SDR.
Being about 1-10 meters away, I use the <b>gain</b> as defined above. Being about 1-10 meters away, I use the <b>gain</b> as defined above.
The IF filter requires a minimum <b>bandwidth</b> of 5 MHz.
The <b>sample rate</b> must be 5 MHz minimum. The <b>sample rate</b> must be 5 MHz minimum.
The default <b>bandwidth</b> follows the sample rate, if not specified using <b>--sdr-bandwidth</b>.
Higher sample rate causes more CPU, RAM and USB load. Higher sample rate causes more CPU, RAM and USB load.
The local oscillator frequency causes the transmitted signal to be noisy, so I shift it 1 MHz away, using an <b>offset</b>. The local oscillator frequency causes the transmitted signal to be noisy, so I shift it 1 MHz away, using the default <b>--sdr-lo-offset</b>.
The audio processing rate of 100 KHz (<b>-s 100000</b>) is used to generate two channels: <b>17</b> and 19. The audio processing rate of 100 KHz (<b>-s 100000</b>) is used to generate two channels: <b>17</b> and 19.
Note that channel 19 is not given here, but will be used automatically. Note that channel 19 is not given here, but will be used automatically.
With B-Netz, the transmitter switches from any voice channel to the paging channel (19) whenever the phone gets paged. With B-Netz, the transmitter switches from any voice channel to the paging channel (19) whenever the phone gets paged.
@ -174,9 +172,7 @@ Because C-Netz uses only odd channel numbers for 10 KHz spacing, we use channel
# cnetz --sdr-soapy \ # cnetz --sdr-soapy \
--sdr-rx-gain 50 \ --sdr-rx-gain 50 \
--sdr-tx-gain 30 \ --sdr-tx-gain 30 \
--sdr-bandwidth 5000000 \
--sdr-samplerate 5000000 \ --sdr-samplerate 5000000 \
--sdr-tune-args "OFFSET=1000000" \
-s 100000 \ -s 100000 \
-k 131 -k 135 \ -k 131 -k 135 \
-C 0,0 -C 0,0
@ -192,7 +188,7 @@ Give PAL 'FUBK' test image on TV channel 21.
# osmotv --sdr-soapy \ # osmotv --sdr-soapy \
--sdr-tx-gain 60 \ --sdr-tx-gain 60 \
--sdr-tune-args "OFFSET=-3000000" \ --sdr-bandwidth 60000000 \
-r 13750000 \ -r 13750000 \
-c 21 \ -c 21 \
tx-fubk tx-fubk

View File

@ -43,6 +43,8 @@
#include "../libsdr/sdr_config.h" #include "../libsdr/sdr_config.h"
#endif #endif
#define DEFAULT_LO_OFFSET -1000000.0
static int got_init = 0; static int got_init = 0;
/* common mobile settings */ /* common mobile settings */
@ -77,7 +79,7 @@ void main_mobile_init(void)
{ {
got_init = 1; got_init = 1;
#ifdef HAVE_SDR #ifdef HAVE_SDR
sdr_config_init(); sdr_config_init(DEFAULT_LO_OFFSET);
#endif #endif
} }

View File

@ -368,9 +368,11 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq
display_iq_init(samplerate); display_iq_init(samplerate);
display_spectrum_init(samplerate, rx_center_frequency); display_spectrum_init(samplerate, rx_center_frequency);
PDEBUG(DSDR, DEBUG_INFO, "Using local oscillator offseet: %.0f Hz\n", sdr_config->lo_offset);
#ifdef HAVE_UHD #ifdef HAVE_UHD
if (sdr_config->uhd) { if (sdr_config->uhd) {
rc = uhd_open(sdr_config->channel, sdr_config->device_args, sdr_config->stream_args, sdr_config->tune_args, sdr_config->tx_antenna, sdr_config->rx_antenna, tx_center_frequency, rx_center_frequency, sdr_config->samplerate, sdr_config->tx_gain, sdr_config->rx_gain, sdr_config->bandwidth, sdr_config->uhd_tx_timestamps); rc = uhd_open(sdr_config->channel, sdr_config->device_args, sdr_config->stream_args, sdr_config->tune_args, sdr_config->tx_antenna, sdr_config->rx_antenna, tx_center_frequency, rx_center_frequency, sdr_config->lo_offset, sdr_config->samplerate, sdr_config->tx_gain, sdr_config->rx_gain, sdr_config->bandwidth, sdr_config->uhd_tx_timestamps);
if (rc) if (rc)
goto error; goto error;
} }
@ -378,7 +380,7 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq
#ifdef HAVE_SOAPY #ifdef HAVE_SOAPY
if (sdr_config->soapy) { if (sdr_config->soapy) {
rc = soapy_open(sdr_config->channel, sdr_config->device_args, sdr_config->stream_args, sdr_config->tune_args, sdr_config->tx_antenna, sdr_config->rx_antenna, tx_center_frequency, rx_center_frequency, sdr_config->samplerate, sdr_config->tx_gain, sdr_config->rx_gain, sdr_config->bandwidth); rc = soapy_open(sdr_config->channel, sdr_config->device_args, sdr_config->stream_args, sdr_config->tune_args, sdr_config->tx_antenna, sdr_config->rx_antenna, tx_center_frequency, rx_center_frequency, sdr_config->lo_offset, sdr_config->samplerate, sdr_config->tx_gain, sdr_config->rx_gain, sdr_config->bandwidth);
if (rc) if (rc)
goto error; goto error;
} }

View File

@ -32,13 +32,14 @@ static int got_init = 0;
extern int use_sdr; extern int use_sdr;
sdr_config_t *sdr_config = NULL; sdr_config_t *sdr_config = NULL;
void sdr_config_init(void) void sdr_config_init(double lo_offset)
{ {
sdr_config = calloc(1, sizeof(*sdr_config)); sdr_config = calloc(1, sizeof(*sdr_config));
memset(sdr_config, 0, sizeof(*sdr_config)); memset(sdr_config, 0, sizeof(*sdr_config));
sdr_config->device_args = ""; sdr_config->device_args = "";
sdr_config->stream_args = ""; sdr_config->stream_args = "";
sdr_config->tune_args = ""; sdr_config->tune_args = "";
sdr_config->lo_offset = lo_offset;
got_init = 1; got_init = 1;
} }
@ -65,6 +66,9 @@ void sdr_config_print_help(void)
printf(" --sdr-samplerate <samplerate>\n"); printf(" --sdr-samplerate <samplerate>\n");
printf(" Sample rate to use with SDR. By default it equals the regular sample\n"); printf(" Sample rate to use with SDR. By default it equals the regular sample\n");
printf(" rate.\n"); printf(" rate.\n");
printf(" --sdr-lo-offset <Hz>\n");
printf(" Give frequency offset in Hz to move the local oscillator away from the\n");
printf(" target frequency. (default = %.0f)\n", sdr_config->lo_offset);
printf(" --sdr-bandwidth <bandwidth>\n"); printf(" --sdr-bandwidth <bandwidth>\n");
printf(" Give IF filter bandwidth to use. If not, sample rate is used.\n"); printf(" Give IF filter bandwidth to use. If not, sample rate is used.\n");
printf(" --sdr-rx-antenna <name>\n"); printf(" --sdr-rx-antenna <name>\n");
@ -109,13 +113,14 @@ void sdr_config_print_hotkeys(void)
#define OPT_SDR_RX_GAIN 1508 #define OPT_SDR_RX_GAIN 1508
#define OPT_SDR_TX_GAIN 1509 #define OPT_SDR_TX_GAIN 1509
#define OPT_SDR_SAMPLERATE 1510 #define OPT_SDR_SAMPLERATE 1510
#define OPT_SDR_BANDWIDTH 1511 #define OPT_SDR_LO_OFFSET 1511
#define OPT_WRITE_IQ_RX_WAVE 1512 #define OPT_SDR_BANDWIDTH 1512
#define OPT_WRITE_IQ_TX_WAVE 1513 #define OPT_WRITE_IQ_RX_WAVE 1513
#define OPT_READ_IQ_RX_WAVE 1514 #define OPT_WRITE_IQ_TX_WAVE 1514
#define OPT_READ_IQ_TX_WAVE 1515 #define OPT_READ_IQ_RX_WAVE 1515
#define OPT_SDR_SWAP_LINKS 1516 #define OPT_READ_IQ_TX_WAVE 1516
#define OPT_SDR_UHD_TX_TS 1517 #define OPT_SDR_SWAP_LINKS 1517
#define OPT_SDR_UHD_TX_TS 1518
struct option sdr_config_long_options[] = { struct option sdr_config_long_options[] = {
{"sdr-uhd", 0, 0, OPT_SDR_UHD}, {"sdr-uhd", 0, 0, OPT_SDR_UHD},
@ -125,6 +130,7 @@ struct option sdr_config_long_options[] = {
{"sdr-stream-args", 1, 0, OPT_SDR_STREAM_ARGS}, {"sdr-stream-args", 1, 0, OPT_SDR_STREAM_ARGS},
{"sdr-tune-args", 1, 0, OPT_SDR_TUNE_ARGS}, {"sdr-tune-args", 1, 0, OPT_SDR_TUNE_ARGS},
{"sdr-samplerate", 1, 0, OPT_SDR_SAMPLERATE}, {"sdr-samplerate", 1, 0, OPT_SDR_SAMPLERATE},
{"sdr-lo-offset", 1, 0, OPT_SDR_LO_OFFSET},
{"sdr-bandwidth", 1, 0, OPT_SDR_BANDWIDTH}, {"sdr-bandwidth", 1, 0, OPT_SDR_BANDWIDTH},
{"sdr-rx-antenna", 1, 0, OPT_SDR_RX_ANTENNA}, {"sdr-rx-antenna", 1, 0, OPT_SDR_RX_ANTENNA},
{"sdr-tx-antenna", 1, 0, OPT_SDR_TX_ANTENNA}, {"sdr-tx-antenna", 1, 0, OPT_SDR_TX_ANTENNA},
@ -184,6 +190,10 @@ int sdr_config_opt_switch(int c, int *skip_args)
sdr_config->samplerate = atoi(optarg); sdr_config->samplerate = atoi(optarg);
*skip_args += 2; *skip_args += 2;
break; break;
case OPT_SDR_LO_OFFSET:
sdr_config->lo_offset = atof(optarg);
*skip_args += 2;
break;
case OPT_SDR_BANDWIDTH: case OPT_SDR_BANDWIDTH:
sdr_config->bandwidth = atof(optarg); sdr_config->bandwidth = atof(optarg);
*skip_args += 2; *skip_args += 2;

View File

@ -7,6 +7,7 @@ typedef struct sdr_config {
*stream_args, *stream_args,
*tune_args; *tune_args;
int samplerate; /* ADC/DAC sample rate */ int samplerate; /* ADC/DAC sample rate */
double lo_offset; /* LO frequency offset */
double bandwidth; /* IF bandwidth */ double bandwidth; /* IF bandwidth */
double tx_gain, /* gain */ double tx_gain, /* gain */
rx_gain; rx_gain;
@ -22,7 +23,7 @@ typedef struct sdr_config {
extern sdr_config_t *sdr_config; extern sdr_config_t *sdr_config;
void sdr_config_init(void); void sdr_config_init(double lo_offset);
void sdr_config_print_help(void); void sdr_config_print_help(void);
void sdr_config_print_hotkeys(void); void sdr_config_print_hotkeys(void);
extern struct option sdr_config_long_options[]; extern struct option sdr_config_long_options[];

View File

@ -62,7 +62,7 @@ static int parse_args(SoapySDRKwargs *args, const char *_args_string)
return 0; return 0;
} }
int soapy_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double rate, double tx_gain, double rx_gain, double bandwidth) int soapy_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double lo_offset, double rate, double tx_gain, double rx_gain, double bandwidth)
{ {
double got_frequency, got_rate, got_gain, got_bandwidth; double got_frequency, got_rate, got_gain, got_bandwidth;
const char *got_antenna; const char *got_antenna;
@ -88,6 +88,13 @@ int soapy_open(size_t channel, const char *_device_args, const char *_stream_arg
if (rc < 0) if (rc < 0)
return rc; return rc;
if (lo_offset) {
char val[32];
snprintf(val, sizeof(val), "%.0f", lo_offset);
val[sizeof(val) - 1] = '\0';
SoapySDRKwargs_set(&tune_args, "OFFSET", val);
}
/* create SoapySDR device */ /* create SoapySDR device */
sdr = SoapySDRDevice_make(&device_args); sdr = SoapySDRDevice_make(&device_args);
if (!sdr) { if (!sdr) {

View File

@ -1,5 +1,5 @@
int soapy_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double rate, double tx_gain, double rx_gain, double bandwidth); int soapy_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double lo_offset, double rate, double tx_gain, double rx_gain, double bandwidth);
int soapy_start(void); int soapy_start(void);
void soapy_close(void); void soapy_close(void);
int soapy_send(float *buff, int num); int soapy_send(float *buff, int num);

View File

@ -49,7 +49,7 @@ static time_t tx_time_secs = 0;
static double tx_time_fract_sec = 0.0; static double tx_time_fract_sec = 0.0;
static int tx_timestamps; static int tx_timestamps;
int uhd_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double rate, double tx_gain, double rx_gain, double bandwidth, int _tx_timestamps) int uhd_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double lo_offset, double rate, double tx_gain, double rx_gain, double bandwidth, int _tx_timestamps)
{ {
uhd_error error; uhd_error error;
double got_frequency, got_rate, got_gain, got_bandwidth; double got_frequency, got_rate, got_gain, got_bandwidth;
@ -153,7 +153,7 @@ int uhd_open(size_t channel, const char *_device_args, const char *_stream_args,
uhd_close(); uhd_close();
return -EIO; return -EIO;
} }
if (fabs(got_rate - rate) > 0.001) { if (fabs(got_rate - rate) > 1.0) {
PDEBUG(DUHD, DEBUG_ERROR, "Given TX rate %.0f Hz is not supported, try %.0f Hz\n", rate, got_rate); PDEBUG(DUHD, DEBUG_ERROR, "Given TX rate %.0f Hz is not supported, try %.0f Hz\n", rate, got_rate);
uhd_close(); uhd_close();
return -EINVAL; return -EINVAL;
@ -182,7 +182,11 @@ int uhd_open(size_t channel, const char *_device_args, const char *_stream_args,
/* set frequency */ /* set frequency */
memset(&tune_request, 0, sizeof(tune_request)); memset(&tune_request, 0, sizeof(tune_request));
tune_request.target_freq = tx_frequency; tune_request.target_freq = tx_frequency;
tune_request.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO; if (lo_offset) {
tune_request.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_MANUAL;
tune_request.rf_freq = tx_frequency + lo_offset;
} else
tune_request.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO;
tune_request.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO; tune_request.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO;
tune_request.args = strdup(_tune_args); tune_request.args = strdup(_tune_args);
error = uhd_usrp_set_tx_freq(usrp, &tune_request, channel, &tune_result); error = uhd_usrp_set_tx_freq(usrp, &tune_request, channel, &tune_result);
@ -219,7 +223,7 @@ int uhd_open(size_t channel, const char *_device_args, const char *_stream_args,
uhd_close(); uhd_close();
return -EIO; return -EIO;
} }
if (fabs(got_bandwidth - bandwidth) > 0.001) { if (fabs(got_bandwidth - bandwidth) > 100.0) {
PDEBUG(DUHD, DEBUG_ERROR, "Given TX bandwidth %.0f Hz is not supported, try %.0f Hz\n", bandwidth, got_bandwidth); PDEBUG(DUHD, DEBUG_ERROR, "Given TX bandwidth %.0f Hz is not supported, try %.0f Hz\n", bandwidth, got_bandwidth);
uhd_close(); uhd_close();
return -EINVAL; return -EINVAL;
@ -337,7 +341,7 @@ int uhd_open(size_t channel, const char *_device_args, const char *_stream_args,
uhd_close(); uhd_close();
return -EIO; return -EIO;
} }
if (fabs(got_rate - rate) > 0.001) { if (fabs(got_rate - rate) > 1.0) {
PDEBUG(DUHD, DEBUG_ERROR, "Given RX rate %.0f Hz is not supported, try %.0f Hz\n", rate, got_rate); PDEBUG(DUHD, DEBUG_ERROR, "Given RX rate %.0f Hz is not supported, try %.0f Hz\n", rate, got_rate);
uhd_close(); uhd_close();
return -EINVAL; return -EINVAL;
@ -366,7 +370,11 @@ int uhd_open(size_t channel, const char *_device_args, const char *_stream_args,
/* set frequency */ /* set frequency */
memset(&tune_request, 0, sizeof(tune_request)); memset(&tune_request, 0, sizeof(tune_request));
tune_request.target_freq = rx_frequency; tune_request.target_freq = rx_frequency;
tune_request.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO; if (lo_offset) {
tune_request.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_MANUAL;
tune_request.rf_freq = rx_frequency + lo_offset;
} else
tune_request.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO;
tune_request.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO; tune_request.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO;
tune_request.args = strdup(_tune_args); tune_request.args = strdup(_tune_args);
error = uhd_usrp_set_rx_freq(usrp, &tune_request, channel, &tune_result); error = uhd_usrp_set_rx_freq(usrp, &tune_request, channel, &tune_result);
@ -403,7 +411,7 @@ int uhd_open(size_t channel, const char *_device_args, const char *_stream_args,
uhd_close(); uhd_close();
return -EIO; return -EIO;
} }
if (fabs(got_bandwidth - bandwidth) > 0.001) { if (fabs(got_bandwidth - bandwidth) > 100.0) {
PDEBUG(DUHD, DEBUG_ERROR, "Given RX bandwidth %.0f Hz is not supported, try %.0f Hz\n", bandwidth, got_bandwidth); PDEBUG(DUHD, DEBUG_ERROR, "Given RX bandwidth %.0f Hz is not supported, try %.0f Hz\n", bandwidth, got_bandwidth);
uhd_close(); uhd_close();
return -EINVAL; return -EINVAL;

View File

@ -1,5 +1,5 @@
int uhd_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double rate, double tx_gain, double rx_gain, double bandwidth, int _tx_timestamps); int uhd_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double lo_offset, double rate, double tx_gain, double rx_gain, double bandwidth, int _tx_timestamps);
int uhd_start(void); int uhd_start(void);
void uhd_close(void); void uhd_close(void);
int uhd_send(float *buff, int num); int uhd_send(float *buff, int num);

View File

@ -41,6 +41,8 @@ enum paging_signal;
#include "tv_modulate.h" #include "tv_modulate.h"
#include "channels.h" #include "channels.h"
#define DEFAULT_LO_OFFSET -3000000.0
void *sender_head = NULL; void *sender_head = NULL;
int use_sdr = 0; int use_sdr = 0;
int num_kanal = 1; /* only one channel used for debugging */ int num_kanal = 1; /* only one channel used for debugging */
@ -454,7 +456,7 @@ int main(int argc, char *argv[])
debuglevel = 0; debuglevel = 0;
#ifdef HAVE_SDR #ifdef HAVE_SDR
sdr_config_init(); sdr_config_init(DEFAULT_LO_OFFSET);
#endif #endif
skip_args = handle_options(argc, argv); skip_args = handle_options(argc, argv);