plutotx

plutotx è una semplice applicazione a linea di comando che pilota ADALM-PLUTO per generare un tono CW alla frequenza e intensità specificati dall’utente.

Spero che questo articolo e il codice sorgente in C di plutotx possano essere un piccolo aiuto per chi desidera iniziare un nuovo progetto SDR.

Il file compresso che troverai qui sotto contiene anche i binari x86 per Windows e Linux, per cui potrebbero essere utili anche per chi non è programmatore, ma è solo interessato a sperimentare con Pluto:

Latest Release:

plutotx v.1.1 (04 august 2022)
File size: 705,962  Bytes
MD5 bb0d3b1e42ff892f377fcf5e2cdbb7f3
SHA1 30ade07ad365b23c211f85632c6e9edcb1efdaa0
SHA256 607ae42da31bddaf1528a4dadac7b8ce711a4e2e9ee9210726c3fb2e1d6f673c

- F: 2,147GHz limit
- I: Output bursts issue
- I: Switching off any DDS second tone active
- A: Include, library and instruction to compile under Windows and Linux

Older versions:

plutotx (4 august 2022)
File size: 685,626 Bytes
MD5 e241666bd41a84e5eff1ec44dab2283f
SHA1 e775f8fce1af59c833a850635b6df135cda9ef1b
SHA256 bf1e782b704b5671c901bfb53280a7f754475eba3d0204dd5bf25f99326e393b

Il file ZIP contiene le librerie necessarie per l’esecuzione in ambiente Windows mentre per compilare ed eseguire Pluto sotto Linux occorre scaricare e installare la libreria libiio di ADI per il tuo specifico OS da qui: libiio.

plutotx richiede tre parametri: frequenza espressa in kHz, livello di uscita in dBm e opzionale, indirizzo URI del device da connettere.

Per esempio: plutotx 432410 -10

plutotx effettuerà la connessione all’indirizzo di default URI ip:192.168.2.1 se il terzo parametro non viene specificato.

Come funziona

Per migliorare la comprensione dei passaggi necessari per la generazione del tono CW, descriverò il codice in porzioni semplificate:

  • Connessione al device Pluto ed acquisizione della struttura context
  • Verifica se il modello del transceiver corrisponde a un AD9364 (richiesto per il completo range di frequenze)
  • Ricerca dei device physical transceiver e del DAC/TX output driver (FPGA)
  • Ricerca dei canali I, Q, catena TX e oscillatore locale TX
  • Applicazione di una configurazione di default del dispositivo
  • Impostazione dell’attenuatore TX
  • Impostazione della larghezza di banda TX
  • Impostazione dei parametri di scala, frequenza e phase dei canali I e Q
  • Impostazione della frequenza dell’oscillatore locale TX
  • Attivazione dei canali I e Q in modo raw per ottenere il segnale in uscita

Prima di tutto occorre effettuare la connessione al dispositivo ed acquisire la struttura context:

struct iio_context *ctx;
ctx = iio_create_context_from_uri("ip:192.168.2.1");

Verifica se il modello del transceiver corrisponde a un AD9364:

if((value=iio_context_get_attr_value(ctx, "ad9361-phy,model"))!=NULL)
  {
  if(strcmp(value,"ad9364"))
    stderrandexit("Pluto not expanded",0,__LINE__);
  }else
   stderrandexit("Error retrieving phy model",0,__LINE__);

Ricerca dei device physical transceiver e del DAC/TX output driver (FPGA):

phy = iio_context_find_device(ctx, "ad9361-phy");
dds_core_lpc = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc");

Ricerca dei canali I, Q, catena TX e oscillatore locale TX:

tx0_i = iio_device_find_channel(dds_core_lpc, "altvoltage0", true);
tx0_q = iio_device_find_channel(dds_core_lpc, "altvoltage2", true);
tx_chain=iio_device_find_channel(phy, "voltage0", true);
tx_lo=iio_device_find_channel(phy, "altvoltage1", true);

Applicazione di una configurazione di default del dispositivo. Forse questo passaggio non è necessario, ma è raccomandato nel caso di un utilizzo precedente di un altro programma SDR che potrebbe aver variato la configurazione di default del dispositivo.

//enable internal TX local oscillator
if((rc=iio_channel_attr_write_bool(tx_lo,"external",false))<0)
  stderrandexit(NULL,rc,__LINE__);

//disable fastlock feature of TX local oscillator
if((rc=iio_channel_attr_write_bool(tx_lo,"fastlock_store",false))<0)
  stderrandexit(NULL,rc,__LINE__);

//power on TX local oscillator
if((rc=iio_channel_attr_write_bool(tx_lo,"powerdown",false))<0)
  stderrandexit(NULL,rc,__LINE__);

//full duplex mode
if((rc=iio_device_attr_write(phy,"ensm_mode","fdd"))<0)
  stderrandexit(NULL,rc,__LINE__);

//calibration mode to manual
if((rc=iio_device_attr_write(phy,"calib_mode","manual"))<0)
  stderrandexit(NULL,rc,__LINE__);

La linea 18 imposta la calibrazione del TX in modo manuale, questo per evitare che l’automatismo di calibrazione generi dei picchi in uscita che potrebbero superare il livello di potenza specificato dall’utente.

Impostazione dell’attenuatore TX. Il valore dell’attenuatore si ottiene sottraendo al valore di intensità specificato dall’utente, il valore di potenza in uscita di Pluto (circa 10 dBm definito da REFTXPWR):

if((rc=iio_channel_attr_write_double(tx_chain,"hardwaregain",dBm-REFTXPWR))<0)
  stderrandexit(NULL,rc,__LINE__);

Impostazione della larghezza di banda TX:

if((rc=iio_channel_attr_write_longlong(tx_chain,"rf_bandwidth",FBANDWIDTH))<0)
  stderrandexit(NULL,rc,__LINE__);

Impostazione dei parametri di scala, frequenza e phase dei canali I e Q:

if((rc=iio_channel_attr_write_double(tx0_i,"scale",1))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_double(tx0_q,"scale",1))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx0_i,"frequency",FCW))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx0_q,"frequency",FCW))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx0_i,"phase",90000))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx0_q,"phase",0))<0)
  stderrandexit(NULL,rc,__LINE__);

Impostazione della frequenza dell’oscillatore locale TX. La frequenza dell’oscillatore locale TX è ottenuta sottraendo al valore richiesto dall’utente, la frequenza del tono CW definita da FCW:

if((rc=iio_channel_attr_write_longlong(tx_lo,"frequency",freq-FCW))<0)
  stderrandexit(NULL,rc,__LINE__);

Attivazione dei canali I e Q in modo raw per ottenere il segnale in uscita:

int rc;

if((rc=iio_channel_attr_write_bool(
        tx0_i,
        "raw",
        1))<0)
 stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_bool(
        tx0_q,
        "raw",
        1))<0)
 stderrandexit(NULL,rc,__LINE__);

Intero codice sorgente di plutotx:

/*
 Author: Alberto Ferraris IU1KVL - https://www.albfer.com

 This program is free software: you can redistribute it and/or modify
 it under the terms of the version 3 GNU General Public License as
 published by the Free Software Foundation.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "iio.h"

#define URIPLUTO "ip:192.168.2.1"
#define MINFREQ 50000000
#define MAXFREQ 6000000000
#define MINDBM -89
#define MAXDBM 10
#define REFTXPWR 10
#define FBANDWIDTH 4000000
#define FSAMPLING 4000000
#define FCW 1000000

struct iio_channel *tx0_i, *tx0_q;

void stderrandexit(const char *msg, int errcode, int line)
{
if(errcode<0)
  fprintf(stderr, "Error:%d, program terminated (line:%d)\n", errcode, line);
  else
  fprintf(stderr, "%s, program terminated (line:%d)\n",msg, line);
exit(-1);
}

void CWOnOff(int onoff)
{
int rc;

if((rc=iio_channel_attr_write_bool(
		tx0_i,
		"raw",
		onoff))<0)
 stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_bool(
		tx0_q,
		"raw",
		onoff))<0)
 stderrandexit(NULL,rc,__LINE__);
}

int main(int argc, char* argv[])
{
struct iio_context *ctx;
struct iio_device *phy;
struct iio_device *dds_core_lpc;
struct iio_channel *tx_chain;
struct iio_channel *tx_lo;
const char *value;
long long freq;
double dBm;
int rc;
int ch;

if(argc<3)
  {
  printf("Usage: plutotx kHz dBm [uri]\n");
  return  0;
  }

freq=atol(argv[1])*1000;

if(freq<MINFREQ || freq>MAXFREQ)
  stderrandexit("Frequency is not in range",0,__LINE__);

dBm=atof(argv[2]);

if(dBm<MINDBM || dBm>MAXDBM)
  stderrandexit("dBm is not in range",0,__LINE__);

if(argc>3)
  ctx = iio_create_context_from_uri(argv[3]);
  else
  ctx = iio_create_context_from_uri(URIPLUTO);

if(ctx==NULL)
  stderrandexit("Connection failed",0,__LINE__);

if((value=iio_context_get_attr_value(ctx, "ad9361-phy,model"))!=NULL)
  {
  if(strcmp(value,"ad9364"))
    stderrandexit("Pluto is not expanded",0,__LINE__);
  }else
   stderrandexit("Error retrieving phy model",0,__LINE__);

phy = iio_context_find_device(ctx, "ad9361-phy");
dds_core_lpc = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc");  
tx0_i = iio_device_find_channel(dds_core_lpc, "altvoltage0", true);
tx0_q = iio_device_find_channel(dds_core_lpc, "altvoltage2", true);
tx_chain=iio_device_find_channel(phy, "voltage0", true);
tx_lo=iio_device_find_channel(phy, "altvoltage1", true);

if(!phy || !dds_core_lpc || !tx0_i || !tx0_q || !tx_chain || !tx_lo)
  stderrandexit("Error finding device or channel",0,__LINE__);

//enable internal TX local oscillator
if((rc=iio_channel_attr_write_bool(tx_lo,"external",false))<0)
  stderrandexit(NULL,rc,__LINE__);

//disable fastlock feature of TX local oscillator
if((rc=iio_channel_attr_write_bool(tx_lo,"fastlock_store",false))<0)
  stderrandexit(NULL,rc,__LINE__);

//power on TX local oscillator
if((rc=iio_channel_attr_write_bool(tx_lo,"powerdown",false))<0)
  stderrandexit(NULL,rc,__LINE__);

//full duplex mode
if((rc=iio_device_attr_write(phy,"ensm_mode","fdd"))<0)
  stderrandexit(NULL,rc,__LINE__);

//calibration mode to manual
if((rc=iio_device_attr_write(phy,"calib_mode","manual"))<0)
  stderrandexit(NULL,rc,__LINE__);

CWOnOff(0);  

if((rc=iio_channel_attr_write_double(tx_chain,"hardwaregain",dBm-REFTXPWR))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx_chain,"rf_bandwidth",FBANDWIDTH))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx_chain,"sampling_frequency",FSAMPLING))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_double(tx0_i,"scale",1))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_double(tx0_q,"scale",1))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx0_i,"frequency",FCW))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx0_q,"frequency",FCW))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx0_i,"phase",90000))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx0_q,"phase",0))<0)
  stderrandexit(NULL,rc,__LINE__);

if((rc=iio_channel_attr_write_longlong(tx_lo,"frequency",freq-FCW))<0)
  stderrandexit(NULL,rc,__LINE__);

CWOnOff(1);

printf("TX ON! Q to exit or E to keep TX ON and exit\n");

while(1)
     {
     ch=getchar();
     if(ch=='q' || ch=='Q')
       {
       CWOnOff(0);
       break;
       }
     if(ch=='e' || ch=='E')
       break;
     };

iio_context_destroy(ctx);

return 0;
}

SATSAGEN

SATSAGEN è un’applicazione Windows che permette di utilizzare un dispositivo SDR come Spectrum Analyzer. Al momento SATSAGEN supporta solo il device ADALM-PLUTO. e con le ultime versioni di SATSAGEN molti altri dispositivi, come RTL-SDR, HackRF e RSP1!

E’ mio desiderio rendere disponibile in forma gratuita alla comunità dei Radioamatori questa mia realizzazione, con la speranza che SATSAGEN possa essere apprezzato come uno strumento utile per la nostra attività di sperimentazione Radio.

Le ultime novità su SATSAGEN le puoi trovare nella seguente pagina:

 https://www.albfer.com/en/satsagen-news/ 

Da qui potete scaricare l’ultima versione:

 SATSAGEN Download Page 

I prerequisiti per il garantito funzionamento dell’applicazione sono:

  • OS: Da Windows 7 in poi…
  • Driver per ADALM-PLUTO installati: PlutoSDR-M2k-USB-Drivers
  • Dispositivo ADALM-PLUTO con firmware >=0.31 (non mandatorio)
  • o un altro dispositivo SDR con le ultime versioni di SATSAGEN!

ATTENZIONE: Al primo avvio, l’applicazione effettuerà sul dispositivo l’estensione in frequenza e bandwidth prevista per l’utilizzo del range 70MHZ-6000MHZ, facendo “vedere” al firmware il transceiver AD9363 come un AD9364. L’estensione è necessaria per il funzionamento dell’applicazione, ma se non desiderate che avvenga, non avviate SATSAGEN.

Desidero ringraziare gli amici Gianni IW1EPY, Domenico I1BOC e Mauro IZ1OTT per avermi fornito l’idea, il sostegno in ogni senso, i componenti e le attrezzature necessarie per la realizzazione del progetto!

Un particolare ringraziamento va a Boian Mitov per le preziose librerie www.mitov.com utilizzate in SATSAGEN!

Di seguito trovate un altro prezioso contributo di Gianni IW1EPY scritto per l’occasione, mentre al termine dell’articolo troverete un breve video che illustra le nozioni base dell’applicazione.

Alberto IU1KVL

Posseggo un Adalm Pluto da un po’ di tempo e ho familiarizzato con l’utilizzo di diverse applicazioni (SDR console, SDRAngel) usandolo sia in RX che TX.
Con il tempo e l’uso la mia indole misuristica ha prevalso, dopo aver provato un po’ di oggetti, analizzatori scalari fino a 4,4 GHz, i vettoriali fino a 900 MHz, ho pensato che anche Pluto avrebbe potuto avere un adeguato utilizzo specialmente nella sua gamma estesa 70 MHz – 6 GHz.
Dopo alcune prove incoraggianti per i risultati a RF ottenuti, ma deludenti dal punto di vista tempi di esecuzione delle misure utilizzando Matlab, ho letteralmente preso per i capelli il mio amico Alberto che non ha saputo dirmi di no e siamo partiti in questa avventura.
Oltre allo splendido lavoro software fatto da Alberto voglio solo aggiungere alcune note hardware.
Pluto non è ovviamente uno strumento e come tale soffre di alcuni problemi.
Data l’estensione di banda, per altro forzata in quanto Pluto nasce con una gamma di utilizzo da 325 MHz a 3,8 GHz, l’impedenza di ingresso e di uscita di certo non è 50 Ohm.
Una coppia di attenuatori mitigano il problema, riducono il range dinamico di utilizzo ma per usi radioamatoriali lo ritengo accettabile.
Con una coppia di attenuatori da 10 dB che possono essere ridotti o annullati accettando il relativo disadattamento rimangono ancora 40 dB verso il basso dal livello di calibrazione e una 20 verso l’ alto per l’ inserzione di un dispositivo attivo sotto test.
Di sicuro Adalm Pluto soffre nella gamma alta di frequenze la mancanza di un contenitore metallico e del accoppiamento fra TX e RX, ma qualcosa si potrebbe fare…
La struttura attuale permette un esame diretto di funzioni di trasferimento di filtri, amplificatori, mentre per l’analisi di impedenze di ingresso è necessario un accoppiatore direzionale o un ponte riflettometrico.
In futuro pensiamo di aggiungere alcune funzionalità per quest’ultima modalità.
Tutto questo è possibile nella modalità Spectrum analyzer con Tracking, ma è possibile usare il solo Generatore o l’analizzatore di spettro.
E’ possibile inserire una curva di correzione per linearizzare l’uscita del generatore, purtroppo ogni Pluto è un po differente e andrebbe personalizzata, per ora ne ho analizzati 4 e le curve di correzione sono disponibili.
In tutti i Pluto analizzati con una adeguata curva di correzione, l’errore di potenza del generatore sta entro un dB contro i 10 dB di un Pluto non corretto, particolarmente variabili la zona da 70 a 300 MHz e da 4 a 6 GHz per altro c’era da aspettarselo essendo le zone di fuori range rispetto al prodotto originario.
E’ possibile inserire una curva di calibrazione del ricevitore, fattibile senza strumenti, una volta calibrato il generatore e accettandone gli inevitabili errori .
Il guadagno del ricevitore e l’attenuazione del generatore non introducono significativi errori per cui una sola curva di correzione permette un buon utilizzo a patto di non portare o il generatore o il ricevitore in saturazione ma la cosa diventa evidente.
Per migliorare le prestazioni dell’analizzatore di reti è possibile effettuare una calibrazione con un attenuatore da 40 dB, purtroppo questa linearizzazione corregge gli errori del livello -40 e -30 ma deteriora il responso per altro già molto compromesso per segnali inferiori es -50 in quanto a questi livelli le tipologie di errore non sono congruenti con i modelli adottati.
Tutti i livelli di ricezione e generazione nonchè le attenuazioni inserite sono programmabili permettendo di variare l’ uso del sistema.
Ogni idea di miglioramento è bene accetta e metto già in lista alcune cose che stiamo esaminando:
Calibrazione con accoppiatore direzionale o ponte riflettometrico con open corto e carico.
Possibilità di analisi con offset fra ricezione e trasmissione per verifica o taratura Transverter o qualsivogli sistema di conversione di frequenza.
Credo che Pluto coprendo 6 gamme radioamatoriali possa essere di aiuto a molti Radioamatori con un prezzo di acquisto contenuto.
IW1EPY

SA TSA GEN per ADALM-PLUTO

Il progetto consiste nella realizzazione di un’applicazione Windows per l’utilizzo di ADALM-PLUTO (recentemente ricevuto in dono da un carissimo amico) come analizzatore di spettro.

Spero a breve di creare un post con più dettagli a proposito, per il momento elenco i punti salienti dell’oggetto:

  • Analizzatore di spettro con span intero range di esercizio, 70MHz-6GHz e rappresentazione ampiezza segnali in dBm.
  • Analizzatore di spettro con tracking generator. Risoluzione fino a 1024 punti.
  • Generatore con possibilità d’impostare la frequenza a passi di 1 KHz

I requisiti per l’applicazione sono:

  • CPU: un vecchio Pentium M da 1,7GHz è più che sufficiente!
  • OS: >= Windows 7 (su necessità dei driver per ADALM-PLUTO)
  • ADALM-PLUTO esteso per far “vedere” al FW il AD9363 come un AD9364
  • Driver Analog Devices installati ( PlutoSDR-M2k-USB-Drivers )

A presto!