Post Go back to editing

Help required to implement a simple AFSK transmiter via the Python API with ADALM PLUTO.

Category: Software
Software Version: rev b latest firmware

I have a PLUTO rev B with the latest firmware. I have tried a number of ways to achieve this but all have failed with the Pluto only managing transmit a very small RF burst. It appears that a block of some sort is happening in the Pluto (unlikely at the USB as the sample rate is only 1M). The following is the code sends two characters (RY) encoded as 5 bit Baudot code (45,45 baud) with one start bit and two stop bits giving 16 bits to transmit with the symbols being 22002 samples (at 1M) of the mark and space frequencies.  I'm wondering if this is a limitation of the Python API?

import numpy as np
import adi

sample_rate = 1e6 # Hz
center_freq = 132e6 # Hz
N = int(sample_rate/45.45) #22002 number of samples to transmit at once
t = np.arange(N)/sample_rate

sdr = adi.Pluto("ip:192.168.2.1")
sdr.tx_rf_bandwidth = int(sample_rate) # filter cutoff, just set it to the same as sample rate
sdr.tx_lo = int(center_freq)
sdr.tx_hardwaregain_chan0 = 0 # Increase to increase tx power, valid range is -90 to 0 dB
sdr.tx_buffer_size = 10e6

spaceI = np.int16(np.sin(2.0*np.pi*2125*t) * 2**14) 
spaceQ = np.int16(np.cos(2.0*np.pi*2125*t) * 2**14)
spaceIQ = spaceI + 1j*spaceQ

markI = np.int16(np.sin(2.0*np.pi*2295*t) * 2**14) 
markQ = np.int16(np.cos(2.0*np.pi*2295*t) * 2**14)
markIQ = markI + 1j*markQ

bit_sequence = [0,0,1,0,1,0,1,1,0,1,0,1,0,1,1,1]
waveform = np.array([], dtype=spaceIQ.dtype)
for bit in bit_sequence:
    wave = markIQ if bit else spaceIQ
    waveform = np.concatenate((waveform, wave))
sdr.tx(waveform)

  • Can you explain more of what the problem is here? This script just sends 1x 0.3 second burst...

    -Travis

  • The problem is that the transmission is not the correct length. If I increase the message length to say 10, 20 or any length, the up translated RF still remains a fraction of a second.

  • Can you provide a plot? Putting this in cycling mode with alittle gap shows the right data length.

    -Travis

  • Many thanks Travis, for the prompt reply. I'll have a look at getting a demodulated plot, but the baseband RTTY is fine. I was expecting a direct frequency translation from baseband without recourse to the cyclic buffer, or delays, as the data rate and sampling rate are so low. How would I deploy the cyclic buffer without affecting the code timings? The code at the moment uses 2 stop bits, but usual practice is 1.5 stop bits, so I have around 90ms (half a bit) for a gap? I'll give it a try.

    George 

  • I don't have a high speed trigger based scope to measure a single transmission. So I just put it in cyclic mode and put a silence gap (zeros) so I could see the rough side of the data.

    import numpy as np
    import adi

    sample_rate = 1e6 # Hz
    center_freq = 1e9 # Hz
    N = int(sample_rate/45.45) #22002 number of samples to transmit at once
    t = np.arange(N)/sample_rate

    sdr = adi.Pluto("ip:192.168.2.1")
    sdr.tx_rf_bandwidth = int(sample_rate) # filter cutoff, just set it to the same as sample rate
    sdr.tx_lo = int(center_freq)
    sdr.rx_lo = int(center_freq)
    # sdr.tx_hardwaregain_chan0 = 0 # Increase to increase tx power, valid range is -90 to 0 dB
    # sdr.tx_buffer_size = 10e6

    spaceI = np.int16(np.sin(2.0*np.pi*2125*t) * 2**14)
    spaceQ = np.int16(np.cos(2.0*np.pi*2125*t) * 2**14)
    spaceIQ = spaceI + 1j*spaceQ

    markI = np.int16(np.sin(2.0*np.pi*2295*t) * 2**14)
    markQ = np.int16(np.cos(2.0*np.pi*2295*t) * 2**14)
    markIQ = markI + 1j*markQ

    bit_sequence = [0,0,1,0,1,0,1,1,0,1,0,1,0,1,1,1]
    waveform = np.array([], dtype=spaceIQ.dtype)
    for bit in bit_sequence:
    wave = markIQ if bit else spaceIQ
    waveform = np.concatenate((waveform, wave))

    # Add zeros at the end to allow for noticeable gap
    waveform = np.concatenate((waveform, np.zeros(10000, dtype=waveform.dtype)))

    print(f"len of waveform: {len(waveform)} samples")

    sdr.tx_cyclic_buffer = True
    sdr.tx(waveform)

    import time
    time.sleep(1) # Give the SDR some time to start transmitting

    capture_size = len(waveform)*2
    sdr.rx_buffer_size = capture_size
    sdr.rx_enabled_channels = [0]

    data = sdr.rx()

    # plot time domain
    import matplotlib.pyplot as plt
    plt.figure()
    plt.plot(np.real(data), label='I')
    plt.plot(np.imag(data), label='Q')
    plt.title('Received FSK Signal - Time Domain')
    plt.xlabel('Sample Index')
    plt.ylabel('Amplitude')
    plt.legend()
    plt.grid()
    plt.show()

  • Travis, many thanks again for your efforts, however the introduction of a delay and setting the tx_cyclic_buffer does not solve the problem. Monitoring the Pluto output in real time on a spectum analyser confirms that the transmission is not correct or of the predicted length. If you lengthen the bit sequence to say 48 bits, for example, the duration of this should be (48 x 0.177s) 8.5 sec and this is not observed, with cyclic buffer off. (The requirement is to just transmit the mark - space coding without repetition). 

    best regards George