S3Board

The CloudS3 board is a specific ultra wideband device designed and manufactured by SDR-Technologies. It features a 6400 MSPS ADC from Teledyne and a USB3 link. It works by taking 1 M samples snapshots in the time domain and transferring them back to the host PC.

CloudS3 Module

You cannot directly allocate one S3Board. This module handles the required USB bus scan and device configuration.
Listing existing devices :

var devices = CloudS3.list()

In return, variable devices (type : JavaScript Array) contains objects (one per avaiblable board), having the following properties :

  • data_type : 's3_device'
  • serial : serial_number (string)
  • device_name : string
  • usb_bus : number
  • usb_addr : number

To open the first found board :

    var s3 = CloudS3.makeDevice();
This returns the first S3 board available, as S3Board object, described below :

object S3Board {
  IQData takeSnapshot();  
  bool storeSnapshot( filename, String attributes ) ;

  number addSubBand( number centerFrequencyMHZ, number bandwidthMHz [,String fifoName]) ;
  IQData getBandIQ( number bandID ) ;
  bool streamTo( String fifoname );
  captureBands() ;

  bool startBands();
  bool stopBands();
} 

.takeSnapshot

Captures one snapshot over the full bandwidth. This returns an IQData object with the raw IQ data. Samples are captured as real (no imaginary part) int16, at 6400 Mega samples per second. They are then converted to complex and shifted at a center frequency of 1600 MHz by the SDRVM (using a Hilbert Transform).

.takeSnapshot();

Example :

    var s3 = CloudS3.makeDevice();
    var IQ = s3.takeSnapshot();
    IQ.dump();

.storeSnapshot

Capture one snapshot over the full bandwidth and directly stores the result into a flat file containing the int16 samples. Samples are stored as real (no imaginary part) int16, at 6400 Mega samples per second. No Hilbert transform is applied.

bool storeSnapshot( filename, String attributes ) ;

File format:

  • Samples are wrote as int16 (2 bytes) ;
  • Then, if the attributes string is provided, it is added just after.
  • Total file length is then : (number of samples)x(2 bytes) + length( attributes)

A typical Matlab function to read these files is provided here as an example :

function [samples, attr ] = readS3FlatFile(filename)
    s=dir(filename);
    N = s.bytes - 16384*128 ; % estimate attributes string length
    fid = fopen(filename, 'r');  
    % read samples
    samples = fread(fid, 16384*128/2, 'int16');     
    samples = (samples -mean(samples))* 3.0/2048 ;

    % apply a simple Hilbert Transform
    Np = 1024*1024 ;
    X = fft( samples, Np);
    fft_in = [X(1); 2*X(2:Np/2); X(Np/2+1); zeros(Np/2-1,1)];
    z = ifft(fft_in,Np);
    samples = z ;

    % if we have remaining data, read this as a JSON document
    if( N > 0 ) 
        attr = jsondecode( fgetl( fid ) );
    end
    fclose(fid);
end

Example :

var s3 = CloudS3.makeDevice();
var infos = {
    'tag' : 12,
    'comment': 'wide capture'
} ; 
var json = JSON.stringify( infos );
if( s3.storeSnapshot( '/tmp/data.s3', json ) === false ) {
       print('record error');        
}

.addSubBand

The S3Board object has an internal DDC bank to decompose each snapshot in sub-bands. Depending on the SDRVM version used, this number varies. Typically for the Jetson family, this number is limited to 16. Once DDC have been declared, each capture is automatically processed and resulting sub-band IQ data pushed in a queue for later processing.
Two options are provided here :

  • Sub-band data extraction by function call ( see getBandIQ() )
  • Automatic data push to a specific Queue.

Manual data extraction

Add a new DDC to the S3 board object and retrieve the channel ID. You need to specify :

  • Center frequency , in MHz;
  • Bandwidth, in MHZ.

Before allocation, internal code checks that parameters are constistant and that the added band does not fall outside of the [0..3200 MHz] range. If so, an exception is thrown.

int channel_id = S3Board.addSubBand( number centerFrequencyMHZ, number bandwidthMHz);

If the system could not allocate the channel, a negative number is returned.

Example :

We allocate one DDC to cover the 460-700 MHz TV Band.

    var s3 = CloudS3.makeDevice();
    var start = 460.0 ;
    var stop  = 700.0 ;
    var bw = stop-start ;
    var middle = start + bw/2 ;

    var channel_id = s3.addSubBand( middle, bw );
    s3.captureBands();
    var IQTV = s3.getBandIQ( channel_id );

Automatic data extraction

Add a new DDC to the S3 board object and plug the output to the given IQQueue. Expected parameters are :

  • Center frequency , in MHz;
  • Bandwidth, in MHZ.
  • Queue name, existing or not (automatically created if not existing yet).

Before allocation, internal code checks that parameters are constistant and that the added band does not fall outside of the [0..3200 MHz] range. If so, an exception is thrown.

int channel_id = S3Board.addSubBand( number centerFrequencyMHZ, number bandwidthMHz, String channelName );

Example :

We allocate one DDC to cover the 460-700 MHz TV Band. Another task will handle data extraction from the given queue.

var s3 = CloudS3.makeDevice();
var start = 460.0 ;
var stop  = 700.0 ;
var bw = stop-start ;
var middle = start + bw/2 ;

var channel_id = s3.addSubBand( middle, bw , 'TVQUEUE' );
if( channel_id < 0) {
  print('could not alloc band.');
  exit();
}
var task = createTask( 'processBand.js', 'TVQUEUE' );
for( ;; ) {
  s3.captureBands();
}

.captureBands

If DDC sub-bands have been allocated, this automatically :

  • Take a full-band snapshot,
  • Feed the DDC Bank,
  • Spread the data to the different queues.

.startBands

Engage automatic capture mode. This starts a background VM thread that will continuously take snapshot and push data to the DDC bank.
Fails if no DDC sub-band has been allocated.

.stopBands

Disables automatic mode.

.streamTo

Turn the acquisition engine on and push the IQ Blocks to the given queue.

Example:

var s3 = CloudS3.makeDevice();
if (typeof s3 != 'object') {
    print('no radio ?');
    exit();
}

var IQ = new IQData('');
var queue = Queues.create('S3');
s3.streamTo(queue);
for (; ;) {
    IQ.readFromQueue(queue);
    // do something with IQ 
}

Using Activity detection with the S3 board

The following example shows how to configure the board to run activity detection from 500 to 1000 MHz with the S3 board. This example also introduces two 'blacklisted' segments where we are not interested in getting infos on what is happening there.

var s3 = CloudS3.makeDevice();
if (typeof s3 != 'object') {
    print('no radio ?');
    exit();
}


var center_frequency = 750 ;
var bandwidth = 500 ;

// Configure the detector
var detect = new PowerChangeDetector(center_frequency, 4096);
var first_send = true ;

var IQ = new IQData('');
var queue = Queues.create('S3');
// Configure board to stream the 500 MHz chunk into the 'S3' Queue 
s3.addSubBand( center_frequency, bandwidth, 'S3') ;
s3.startBands();

for (; ;) {
    // Fetch a S3 complex bloc from the DDC 
    IQ.readFromQueue(queue);
    if (IQ.getLength() == 0) {
        continue;
    } 
    // push data to the Activity detector
    detect.pushIQ(IQ); 

    // configure the blacklist
    // we cannot do this before the first IQ block has been sents
    if( first_send ) {
        first_send = false ;
        detect.setPowerThreshold(10.0);      // 10 dB threshold 
        detect.ignore( 750.0, 830.0 );       // We do not want detections in the [750..830 MHz] band
        detect.ignore( 920.0, 970.0 );       // We do not want detections in the [920..970 MHz] band
    }
    var changes = detect.runDetections(true);
    if (changes > 0) {
        var detection = detect.popDetection();
        while (typeof detection === 'object' && detection !== null) {
            // Do something with the detection we have received
            print( JSON.stringify(detection));

            // extract the next detection
            detection = detect.popDetection();
        }
    }
}
Last update: September 13, 2023