analogdevicesinc / pyadi-iio

Python interfaces for ADI hardware with IIO drivers (aka peyote)
https://analogdevicesinc.github.io/pyadi-iio
Other
139 stars 101 forks source link

Inconsistent Tx Port with dds_dual_tone on ad9361 #569

Closed maso27 closed 1 month ago

maso27 commented 4 months ago

On ADALM-PLUTO, with 2r2t mod, the dds_dual_tone() function sometimes generates a tone on the wrong channel.

With this code, it can be demonstrated on a dual-channel PLUTO with cables looping back Tx1-Rx1 and Tx2-Rx2. Code:

    import adi
    import numpy as np
    import matplotlib.pyplot as plt

    for a in range(10):
        sdr = adi.ad9361("ip:192.168.2.1")

        sdr.rx_enabled_channels = [0, 1]
        sdr.tx_enabled_channels = [0, 1]

        sample_rate = int(30.72e6)
        lo_freq     = int(1e9)
        cw_freq     = int(1e6)

        sdr.sample_rate     = sample_rate
        sdr.rx_rf_bandwidth = sample_rate
        sdr.tx_rf_bandwidth = sample_rate

        # set up Tx
        sdr.tx_lo = lo_freq

        sdr.tx_hardwaregain_chan0 = -10
        sdr.tx_hardwaregain_chan1 = -10

        ## Dual Tone port output is inconsistent ##
        ######################################################
        sdr.dds_dual_tone(cw_freq, 0.5, cw_freq + 1e6, 0.3, channel=0)
        ######################################################

        # set up Rx
        sdr.rx_lo = lo_freq
        sdr.gain_control_mode_chan0 = 'manual'
        sdr.gain_control_mode_chan1 = 'manual'
        sdr.rx_hardwaregain_chan0 = 0
        sdr.rx_hardwaregain_chan1 = 0

        # Clear Buffer
        for i in range (0, 10):
            sdr.rx()

        # Receive samples
        rx_samples = sdr.rx()

        # Disable Outputs
        sdr.disable_dds()

        # Calculate Power Spectral Density (Frequency Domain)
        psd_1 = np.abs(np.fft.fftshift(np.fft.fft(rx_samples[0])))**2
        psd_dB_1 = 10*np.log10(psd_1)
        psd_2 = np.abs(np.fft.fftshift(np.fft.fft(rx_samples[1])))**2
        psd_dB_2 = 10*np.log10(psd_2)

        # generate frequency span
        f = np.linspace(sample_rate/-2, sample_rate/2, sdr.rx_buffer_size)
        f += sdr.rx_lo

        # Plot
        full_fig = plt.figure()
        time_plot = full_fig.add_subplot(211)
        freq_plot = full_fig.add_subplot(212)

        # Time Plot
        time_plot.plot(np.real(rx_samples[0][:100]), label='Rx 1 Real')
        time_plot.plot(np.imag(rx_samples[0][:100]), label='Rx 1 Imag')
        time_plot.plot(np.real(rx_samples[1][:100]), label='Rx 2 Real')
        time_plot.plot(np.imag(rx_samples[1][:100]), label='Rx 2 Imag')

        time_plot.set_xlabel("Samples")
        time_plot.legend()
        time_plot.grid()

        # Freq Plot
        freq_plot.plot(f/1e6, psd_dB_1, alpha=0.7, label='Rx 1')
        freq_plot.plot(f/1e6, psd_dB_2, alpha=0.7, label='Rx 2')
        freq_plot.legend()

        freq_plot.set_xlabel("Frequency [MHz]")
        freq_plot.set_ylabel("PSD")
        freq_plot.grid()

    plt.show()
tfcollins commented 4 months ago

I don't think this is an issue with pyadi-iio. If you comment out updating the sample rate the problem goes away. Alternatively you can put the sample_rate write after the dds_dual_tone call.

There was bug branch related here https://github.com/analogdevicesinc/pyadi-iio/tree/tfcollins/pluto-bug-samplerate There seems to be some interplay with the interface core (axi_ad9361) and I think the driver interface retuning. There is an internal bug report but it hasn't been looked at.

tfcollins commented 1 month ago

Closing since its not a pyadi-iio issue