realtimeradio / souk-firmware

Simons Observatory UK RFSoC Firmware
GNU General Public License v3.0
3 stars 1 forks source link

Error in measured tone frequencies for N>8 #26

Closed sr-cdf closed 1 year ago

sr-cdf commented 1 year ago

Hey @jack-h,

When setting any number of tones, the first 8 are at the expected frequency, but the rest are not.

Tested on the latest 5.5.5.0, with the DPSS window and run remotely over ethernet from host desktop.

Here is a plot with 64 tones showing the spectrum analyser sweep with circles for the magnitudes at the applied frequencies and the measured frequencies, along with the difference.

sweeps_dpss

Here is the code:

import os
import time
from numpy import *; from matplotlib.pyplot import *; ion()

import souk_mkid_readout

r=souk_mkid_readout.SoukMkidReadout('rfsoc4x2',configfile='/home/sam/souk/souk-firmware/software/control_sw/config/souk-single-pipeline-4x2.yaml')

if not r.fpga.is_programmed():
    r.program()

r.initialize()
r.fpga.print_status()

dut_proj = 'RFSOC4x2_SOUK-FIRMWARE'
dut_ver  = r.fpga.get_firmware_version() +' '+ souk_mkid_readout.__version__

DAC_SAMPLE_RATE = 4915.2e6
DAC_INTERPOLATION= 2
LUT_FREQUENCY_RESOLUTION = (DAC_SAMPLE_RATE / DAC_INTERPOLATION) /  r.gen_lut.n_samples

#MIXFREQ=0 #version <= 4.1.1.2
MIXFREQ = DAC_SAMPLE_RATE/DAC_INTERPOLATION/2 #version > 5.0.0.0

N_TX_FFT=2048 #times 2 banks
bin_centers = np.fft.fftfreq(2*N_TX_FFT, 1./(2*MIXFREQ)) + MIXFREQ
bins        = np.arange(len(bin_centers))
freqs       = bin_centers

def setfreqlut(r,target_frequency):
    print('set')
    r.output.use_lut()
    actual_frequency=round((target_frequency - MIXFREQ) / LUT_FREQUENCY_RESOLUTION) * LUT_FREQUENCY_RESOLUTION
    r.gen_lut.set_output_freq(0,
                               actual_frequency,
                               sample_rate_hz=r.adc_clk_hz,
                               amplitude=1)
    return actual_frequency+MIXFREQ

def setfreqcordic(r,freq_hz,cordic_id=-1):
    print('set')
    r.output.use_cordic()
    r.gen_cordic.set_output_freq(cordic_id,
                                  (freq_hz-MIXFREQ),
                                  sample_rate_hz=r.adc_clk_hz)
    return freq_hz

def setfreqpsb(r,freq_hz,phase=0,amplitude=1.0):
    freq_hz=np.atleast_1d(freq_hz)
    phase=np.atleast_1d(phase)
    amplitude=np.atleast_1d(amplitude)
    n_tones=len(freq_hz)
    r.output.use_psb()
    r.reset_psb_outputs()
    r.set_multi_tone(freq_hz, phase, amplitude)
    shift_stages = int(np.ceil(np.log2(n_tones)))
    shift_schedule = 2**(shift_stages) - 1
    for synth in [r.psb, r.psboffset]:
        synth.set_fftshift(shift_schedule)
    r.sync.arm_sync(wait=False)
    r.sync.sw_sync() # Not necessary if there is a PPS connected
    return freq_hz

num    = 64
amps   = np.ones(num,dtype=float)
phases = np.random.uniform(0,2*pi,size=num)
freqs  = sort(random.uniform(200e6,2250e6,num))
while min(abs(diff(freqs))) <=1.2e6:
    freqs = sort(random.uniform(200e6,2250e6,num))

setfreqpsb(r,freqs,phases,amplitude=amps)

### measure with spectrum spectrum_analyser
### find peaks with scipy.signal.find_peaks(height>-60)
### plot the difference in frequencies
sr-cdf commented 1 year ago

If I use the previous fpg/dtbo with the hanning window (souk_single_pipeline_4x2_2023-08-03_1318), it works fine:

sweeps_hanning

jack-h commented 1 year ago

Investigating now

jack-h commented 1 year ago

I found a library regression issue and hastily compiled a fix in https://github.com/realtimeradio/souk-firmware/commit/0e789eddb4332c0b236e9a5c0cfdb1d573cfc911.

If it's easy to rerun your test script on this firmware that would be great. If that still doesn't work I'll set up a test rig here and/or revert the libraries to the previous version to try and figure out what changed and broke things

sr-cdf commented 1 year ago

It'll have to wait until tomorrow now but I can test it first thing.

sr-cdf commented 1 year ago

Works a treat, thanks for the quick fix!