As I have been continuing to experiment with the DDS module board based on the AD9850 125MHz direct digital synthesizer chip I came across a couple of months ago, I have been slowly increasing the complexity of the measurements and applications with it. At each step in this process, I have been using my Eclypse Z7 as a USB scope running the WaveForms instrument suite software to validate everything.
After adequately covering the basics of creating/validating the digital serial interface, measuring basic RF output parameters of fundamental frequency offset/output power, and measuring spurs due to DDS quantization error, it was time to make a real SDR type project with it like I've been mentioning in each of these project posts. So I decided to create a super basic baseband modulator with it.
Baseband modulation is the process of encoding a stream of digital data to the amplitude, width, or position of a respective analog pulse for transmission in a communication system. The baseband aspect specifically refers to those analog frequencies in a lower range that have not yet been up-converted to the higher target frequencies for transmission across a network.
I decided to start with a simple frequency shift keying format my digital modulation as it is one of the easiest modulation schemes to measure on a spectrum analyzer or oscilloscope.
Frequency Shift KeyingFrequency shift keying (FSK) is where the digital binary signal is encoded onto the analog carrier signal by periodically shifting that carrier signal between various discrete frequencies. Each symbol is defined to be a certain number of binary bits, then each symbol is tied or "mapped" to a specific discrete frequency. So when that frequency is transmitted for a certain amount of time, the receiver can correlate it back to that specific symbol of binary bits.
One of the simplest forms of FSK is 2FSK which has 1 binary bit per symbol, so there are only 2 types of symbols. This means only 2 discrete frequencies are used by the carrier to represent either a binary 0 or 1.
Symbol Mapper Python CodeThe process of taking a digital message and mapping each binary bit to some discrete frequency to drive the AD9850 with, I wrote a Python script for the Raspberry Pi Zero W that I'm using to drive the serial interface of the DDS module.
The first step is to take a message string and convert it to binary format, then parse it into an array of single symbols of 0 or 1:
msg = 'deadbeef'
print("msg : " + str(msg))
tx_msg = ''.join(format(ord(i), '08b') for i in msg)
print("tx_msg after binary conversion : " + str(tx_msg))
for symbol in tx_msg:
sendCtrlWord(symbol)
Next, set the discrete frequency value for the respective 0 or 1 bit value and send the control word for that frequency to the AD9850. I chose to set the frequency for a binary bit 0 to 10MHz and the frequency for a binary bit 1 to 20MHz.
symbol_freq0 = 10000000
symbol_freq1 = 20000000
def sendCtrlWord(symbol):
if symbol == '0':
frequency = symbol_freq0
print("frequency = 10MHz")
else:
frequency = symbol_freq1
print("frequency = 20MHz")
pulsePin(RESET)
pulsePin(W_CLK)
pulsePin(W_CLK)
pulsePin(W_CLK)
pulsePin(FQ_UD)
freq = int((frequency*(2**32))/CLKIN)
phase = 0
phas = int ((phase*(2**5))/360)
for i in range (0,34):
GPIO.output(DATA, freq & 0x01)
pulsePin(W_CLK)
freq = freq >> 1
GPIO.output(DATA, 0x00 & 0x01)
pulsePin(W_CLK)
for j in range (0,4):
GPIO.output(DATA, phas & 0x01)
pulsePin(W_CLK)
phas = phas >> 1
GPIO.output(DATA, 0x00 & 0x01)
pulsePin(W_CLK)
pulsePin(FQ_UD)
for k in range (0,18):
GPIO.output(DATA, 0x00 & 0x01)
pulsePin(W_CLK)
return
Validating with Spectrum AnalyzerReturning to the spectrum analyzer window as I've outlined in my previous project posts, I set the span to 20MHz with the center frequency at 15 MHz so that I could see both 10MHz and 20MHz on the spectrum at once when running the symbol mapper Python script.
I added markers to both the 10MHz and 20MHz points as well before hitting run on the spectrum analyzer in WaveForms. I was able to measure both of the respective frequencies for the two binary symbols clearly as the output frequency within the proper fundamental frequency offset and output power tolerances I previously verified for the AD9850.
Binary symbol 0 at 10MHz:
Binary symbol 1 at 20MHz:
I also validated the measurement in the time domain using the oscilloscope in WaveForms to view the different carrier frequencies. Since my lowest target signal is 10MHz, I set the time base of the x-axis of the scope to 100ns per division since 100ns equals one period of a 10MHz signal (period = 1/frequency).
Binary symbol 0 at 10MHz:
Binary symbol 1 at 20MHz:
However, I had trouble setting the appropriate trigger to capture a transition between the two carrier frequencies.
ConclusionsI did notice a couple of issues with the AD9850 again throwing up random spur values the long I left it running. I also noticed there was an issue with trying to switch between output frequencies too quickly, which capped the overall data rate of my little symbol mapper (ie - how fast it can transmit the whole message) to be fairly low.
This tells me that this little DDS module is probably better used as a local oscillator where the frequency value isn't needing to change as often. But for a good demonstration of some basic concepts in digital modulation, it's still a great exercise.
Comments
Please log in or sign up to comment.