How to shift IQ stream using numpy?

183 Views Asked by At

I have a python code that reads an IQ stream from a RTL-SDR dongle and process it to a ndarray, the IQ from the ndarray is then demodulated to extract an USB signal and written to a file, the code is something like:

def MainLoop():
  ...
  # A loop that reads samples from the RTL-SDR device
  data = client.read_samples()
  ...
  # Convert RTL-SDR IQ from 0/255 to -1/+1
  iq_samples = PackedBytesToIQ(data)
  LowPassFilter(iq_samples)
...
def LowPassFilter(iq_signal, minFreq, maxFreq):
  # Low pass filtering
  samplingRate = common.getRtlSdrSampleRate()  # Sampling rate in Hz
  carrierFreq = (samplingRate/4) - (common.getRtlSdrTuningFreq() - common.getFt8Freq()) 
  minFreq = int(carrierFreq)  # Minimum frequency in Hz
  maxFreq = int(carrierFreq + 3000)  # Maximum frequency in Hz
  filteredSignal = IQLowpassFilter(inputIq, minFreq, maxFreq, samplingRate)
  DecodeUsbSignal(filteredSignal, fileName, minFreq)
...
def DecodeUsbSignal(inputIq, output_file: str, carrierFreq: int):
    logging.debug("DEC -> Starting USB decode")
    # Create the carrier signal for demodulation
    sampling_rate = common.getRtlSdrSampleRate()  # Adjust this to your actual sampling rate
    t = np.arange(0, len(inputIq)) / sampling_rate
    #carrier_freq = 0  # Adjust this to your USB carrier frequency
    carrier_signal = np.exp(1j * 2 * np.pi * carrierFreq * t)
    # Demodulate the USB signal
    demodulated_signal = inputIq * carrier_signal
    # Shift the spectrum down
    # demodulated_signal = ShiftIQ(demodulated_signal, -1 * carrierFreq) <- This does not work
    # Ensure that the demodulated signal is real-valued
    demodulated_signal = demodulated_signal.real
    # Normalize the signal before scaling
    max_value = np.max(np.abs(demodulated_signal))
    if max_value != 0:
        normalized_signal = demodulated_signal / max_value
    else:
        normalized_signal = demodulated_signal
    # Scale the signal for 16-bit audio
    scaled_signal = np.int16(normalized_signal * 32767)
    # Write to file
    logging.debug(f"DEC -> Writing to {output_file}")
    scipy.io.wavfile.write(output_file, sampling_rate, scaled_signal)
    logging.debug(f"DEC -> Writing completed")

My center frequency is 144.5MHz and the USB signal is at 144.174MHz, with a samplerate of 2.048Ms/s means that my signal is 186Khz above the minimum received frequency. The code mostly works fine except for the fact that is stored as a 2048000Hz file and my USB signal is at 186KHz in the audio spectrum, how do i "shift" the IQ down by 186KHz to have the USB signal at an usable audio range?

Audio spectrum from audacity:

Audio spectrum from audacity

I tried to shift the IQ with something like:

import numpy as np
def shift_iq_frequency(iq_signal, shift_freq, sampling_rate):
    t = np.arange(0, len(iq_signal)) / sampling_rate
    shift = np.exp(-1j * 2 * np.pi * shift_freq * t)  # Use negative sign for frequency shift
    shifted_iq_signal = iq_signal * shift
    return shifted_iq_signal

But i only managed to shift the signal up, not down, even by using a negative interval.

A negative value gave me this (the audio wave looks weird too):

negative value

While a positive value shifted my spectrum up correctly: positive valuehere

0

There are 0 best solutions below