Hi, I am attempting to measure the gain phase and magnitude spectrum through various filters (hardware) using the RFSoC 2x2. Currently, I have the code for the gain magnitude working and reliable. However, I am unable determine phase data reliably.
What I would like to do is use the ADC mixer to convert the phase and gain data into DC signals. Then, I apply a digital low pass filter (spicy butter) to measure only the DC component of the signal. From here I should be able to recover the gain and phase data easily. I will attach a PDF of this math below to show the calculations I am describing.
Mar2022.pdf (191.8 KB)
Unfortunately, the ADC mixing does not appear to be consistent. For example, when I test the response at 1 GHz I get a phase of say -2. If I keep making to measurements at 1 GHz, my phase moves around -2 with a normal amount of noise. However, if I tune the ADC to 100 MHz and then tune it back to 1 GHz, my answer for the phase changes radically, for example to 0.6. This would explain why my phase spectrum is nonsense. My understanding is that there is likely some QMC correction which I need to do after switching frequencies. However, it is not clear what this correction would be and how I would determine it.
The code and output are attached below (measuring a high pass filter).
from pynq.overlays.base import BaseOverlay
import xrfdc
import plotly.graph_objs as go
import numpy as np
import ipywidgets as ipw
from scipy import signal
import time
from tqdm.notebook import tqdm
base = BaseOverlay('base.bit')
base.init_rf_clks()
frequency_list = np.logspace(2,3,25) #Use log space
transmitter_amplitude = 0.5
number_samples = 2048
sample_frequency = 2048e6
def update_adc_mixers(channel, freq, phase):
channel.adc_block.MixerSettings['Freq'] = freq
channel.adc_block.MixerSettings['PhaseOffset'] = phase
channel.adc_block.UpdateEvent(xrfdc.EVENT_MIXER)
def update_dac_mixers(channel, enable, gain, frequency, phase):
channel.control.enable = enable
channel.control.gain = gain
channel.dac_block.MixerSettings['Freq'] = frequency
channel.dac_block.MixerSettings['PhaseOffset'] = phase
channel.dac_block.UpdateEvent(xrfdc.EVENT_MIXER)
def calculate_gain_magnitude_phase(ia, qa, ib, qb, phi_a, phi_b):
return [np.mean(np.sqrt(ib**2+qb**2)/np.sqrt(ia**2+qa**2)), np.mean(phi_a-phi_b)]
def run_spectrum_sweep(frequencies = frequency_list,
amplitude = transmitter_amplitude):
magnitude = []
phase = []
results = []
for freq in tqdm(frequencies):
update_dac_mixers(base.radio.transmitter.channel[1], True, transmitter_amplitude, freq, 0)
update_adc_mixers(base.radio.receiver.channel[0], freq , 0)
update_adc_mixers(base.radio.receiver.channel[1], freq, 0)
time.sleep(1)
cdata = []
for i in range(0, len(base.radio.receiver.channel)):
cdata.append(base.radio.receiver.channel[i].transfer(number_samples))
sos = signal.butter(8, freq/2.0*1e6, 'lp', fs=2048e6, output='sos')
cdata[0] = signal.sosfilt(sos, cdata[0])
cdata[1] = signal.sosfilt(sos, cdata[1])
samples=int(number_samples/100*np.log(freq)**2) #This is just to average DC component over many cycles after the digital filter is applied. Somewhat arbitrary quantity, but definitely not the issue.
ia=np.real(cdata[0][-samples:])
qa=np.imag(cdata[0][-samples:])
ib=np.real(cdata[1][-samples:])
qb=np.imag(cdata[1][-samples:])
phi_a=np.arctan2(qa, ia)
phi_b=np.arctan2(qb, ib)
computed_data=calculate_gain_magnitude_phase(ia,qa,ib,qb, phi_a, phi_b)
magnitude.append(computed_data[0])
phase.append(computed_data[1])
return [magnitude, phase]
results=run_spectrum_sweep()
The gain magnitude and phase are shown below. Frequency (MHz) is on the x-axis. The first plot shows gain magnitude, the second shows phase (not really) in radians.
Are there any remedies for the phase data? Am I misunderstanding the ADC mixing process and the errors it introduces? Any help to get more accurate phase data would be appreciated. Thank you.