Skip to content

Waveform Generator

rfsoc_rfdc.waveform_generator

Classes

WaveFormGenerator

A class that generates different types of waveforms.

Source code in rfsoc_rfdc/waveform_generator.py
class WaveFormGenerator:
    """
    A class that generates different types of waveforms.
    """
    @staticmethod
    def generate_tone(tone_freq_mhz, sample_rate, interpolation_rate, sideband="SSB", mode="iq2real"):
        pts_per_period = int(sample_rate / interpolation_rate / tone_freq_mhz)

        if pts_per_period <= 4:
            logging.warning("target CW frequency too low")

        # Ensure sample_pts * repeat_time > 8000
        repeat_time = math.ceil(8001 / pts_per_period)

        real = WaveFormGenerator.generate_sine_wave(
            repeat_time=repeat_time, sample_pts=pts_per_period)

        if mode == "real2real":
            return real

        # For iq2real / iq2iq
        if sideband == "SSB":  # Single side band
            imag = WaveFormGenerator.generate_cosine_wave(
                repeat_time=repeat_time, sample_pts=pts_per_period)
            data = real + 1j * imag
        elif sideband == "DSB":  # Double side band
            data = real + 1j * 0
        else:
            raise ValueError(f"Unknown sideband mode: {sideband}")

        return data

    @staticmethod
    def generate_sine_wave(repeat_time=1, sample_pts=1000, scaling_factor=1.0, raw_np=False):
        t = np.linspace(0, repeat_time, int(
            sample_pts * repeat_time), endpoint=False)
        wave = np.sin(2 * np.pi * t)
        if raw_np:
            return wave
        else:
            wave *= int(MyRFdcType.DAC_MAX_SCALE * scaling_factor)
        return wave.astype(MyRFdcType.DATA_PATH_DTYPE)

    @staticmethod
    def generate_square_wave(repeat_time=1, sample_pts=1000, scaling_factor=1.0):
        t = np.linspace(0, repeat_time, int(
            sample_pts * repeat_time), endpoint=False)
        wave = np.sign(np.sin(2 * np.pi * t)) * \
            int(MyRFdcType.DAC_MAX_SCALE * scaling_factor)
        return wave.astype(MyRFdcType.DATA_PATH_DTYPE)

    @staticmethod
    def generate_triangle_wave(repeat_time=1, sample_pts=1000, scaling_factor=1.0):
        t = np.linspace(0, repeat_time, int(
            sample_pts * repeat_time), endpoint=False)
        wave = 2 * np.abs(2 * (t - np.floor(t + 0.5))) - 1
        wave *= int(MyRFdcType.DAC_MAX_SCALE * scaling_factor)
        return wave.astype(MyRFdcType.DATA_PATH_DTYPE)

    @staticmethod
    def generate_sawtooth_wave(repeat_time=1, sample_pts=1000, scaling_factor=1.0):
        t = np.linspace(0, repeat_time, int(
            sample_pts * repeat_time), endpoint=False)
        wave = 2 * (t - np.floor(0.5 + t))
        wave *= int(MyRFdcType.DAC_MAX_SCALE * scaling_factor)
        return wave.astype(MyRFdcType.DATA_PATH_DTYPE)

    @staticmethod
    def generate_cosine_wave(repeat_time=1, sample_pts=1000, scaling_factor=1.0, raw_np=False):
        t = np.linspace(0, repeat_time, int(
            sample_pts * repeat_time), endpoint=False)
        wave = np.cos(2 * np.pi * t)
        if raw_np:
            return wave
        else:
            wave *= int(MyRFdcType.DAC_MAX_SCALE * scaling_factor)
        return wave.astype(MyRFdcType.DATA_PATH_DTYPE)

    @staticmethod
    def generate_binary_seq(repeat_time=1, sample_pts=1000, scaling_factor=1.0):
        num_of_samples = repeat_time * sample_pts
        wave = np.tile([0, 1], num_of_samples // 2 + 1)[:num_of_samples]
        wave *= int(MyRFdcType.DAC_MAX_SCALE * scaling_factor)
        return wave.astype(MyRFdcType.DATA_PATH_DTYPE)

    @staticmethod
    def generate_ten_sine(scaling_factor=1.0):
        ten_sine = WaveFormGenerator.generate_sine_wave(
            repeat_time=10, sample_pts=10, scaling_factor=scaling_factor)
        ten_sine = np.append(ten_sine, np.zeros(
            100, dtype=MyRFdcType.DATA_PATH_DTYPE))
        wave = np.append(ten_sine, ten_sine)
        return wave

    @staticmethod
    def generate_zadoff_chu_wave(repeat_time=1, sample_pts=1000, scaling_factor=1.0):
        u = 1  # Root index of the the ZC sequence
        seq_length = sample_pts * repeat_time
        q = 0  # Cyclic shift of the sequence

        for el in [u, seq_length, q]:
            if not float(el).is_integer():
                raise ValueError('{} is not an integer'.format(el))
        if u <= 0:
            raise ValueError('u is not stricly positive')
        if u >= seq_length:
            raise ValueError('u is not stricly smaller than seq_length')
        if np.gcd(u, seq_length) != 1:
            raise ValueError(
                'the greatest common denominator of u and seq_length is not 1')

        cf = seq_length % 2
        n = np.arange(seq_length)
        zcseq = np.exp(-1j * np.pi * u * n * (n+cf+2.*q) / seq_length)

        scale_to_max = int(MyRFdcType.DAC_MAX_SCALE * scaling_factor)

        zcseq_real = np.real(zcseq) * scale_to_max
        zcseq_real = zcseq_real.astype(MyRFdcType.DATA_PATH_DTYPE)
        zcseq_imag = np.imag(zcseq) * scale_to_max
        zcseq_imag = zcseq_imag.astype(MyRFdcType.DATA_PATH_DTYPE)

        return zcseq_real, zcseq_imag

    @staticmethod
    def generate_no_wave(repeat_time=1, sample_pts=1000, scaling_factor=1.0):
        wave = np.zeros(sample_pts * repeat_time)
        return wave.astype(MyRFdcType.DATA_PATH_DTYPE)