The Receiver
I've now built most of the building blocks of my receiver design. The only thing I don't have is the anti-aliasing filters, and I guess I can live without those for now. So I decided to assemble the entire receiver for an end to end test.
Here's what it looks like:
Set-up
I configured the LO for 101.1 MHz to tune the receiver to Classic FM, since I know its signal is strong here. I set the IF amplifiers to their max gain since I know the overall system only just has enough gain, even for strong signals.
Each IF amplifier has a DC offset adjustment which needs to be manually tuned. I'm currently doing this by looking at the output of the IF stage on the scope. I initially had trouble here, because I didn't have enough adjustment to trim out the DC offset I saw in practice. I based the initial adjustment range on the DC offset I saw when testing the mixer standalone, but in practice the offset is much larger. My current guess is that energy is radiating directly from the LO to the antenna, causing a lot more self mixing than I saw when testing without an antenna. I temporarily worked around this by reducing the value of the resistors between the pots and the op-amp inputs, which increases the range of available adjustment.
Sampling, a little DSP, and some success?
With the DC offset adjusted as best I could, I captured three short chunks of IQ data from the ADC. This is just a case of piping data from a serial device to a file on my laptop. I then wrote a little bit of Python code to demodulate the captured IQ data and extract the mono audio channel.
Here's the result: receiver-test.mp3
Clearly the quality is terrible, but at least it does something. In truth, I only managed to get recognisable audio out of one of the captures I made, and I don't yet know why.
Next Steps
Now that I have something working I can think about how to improve it. I've not decided how to go about that, but some initial ideas are:
- Switch from batch processing of captured data to streaming data and doing DSP in real-time.
- Look into the larger than expected DC offsets. It's possible this leads to the first IF amp clipping, as this was designed with smaller offsets in mind.
- Avoid having to manually trim out the DC offset. Maybe switch to using near-zero IF?
- Use better ADCs and a higher sampling rate.
- Add anti-aliasing filters. (Over-sampling would make this easier.)
- Add more gain in order to receive weaker signals.
- Figure out how to improve the audio quality. Some of the above might help, but I might also need to look at the power supply, filtering reference voltages, etc.
- Easier gain adjustment. Automatic gain control perhaps.
Code
For posterity, here's the gist of the Python code I mentioned above:
import sys import numpy as np from scipy.io import wavfile def pk(arr): return np.max(np.abs(arr)) def norm(chan): chan0 = chan - np.mean(chan) out = chan0 / pk(chan0) return out def demod(xt): return np.diff(np.unwrap(np.angle(xt))) def main(infile, outfile): channel = np.load(infile) sample_rate = 250e3 D = 6 # decimate by this iq = norm(channel[0]) + 1j*norm(channel[1]) x = demod(iq) x = x[::D] # decimate x /= pk(x) # normalize x *= 32767 x = x.astype(np.int16) wavfile.write(outfile, int(sample_rate / D), x) if __name__ == '__main__': if len(sys.argv) < 3: print(f'usage: {sys.argv[0]} <infile> <outfile>') else: main(sys.argv[1], sys.argv[2])
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.