[back]
Digital Signal Processing
modified: 2015-04-21 02:36:57

1. Simulating An Inductor And Capacitor Of Sorts
2. Shifting A Signal In The Frequency Domain
3. FM Demoulation
4. Link Dump
1. Simulating An Inductor And Capacitor Of Sorts

Today, after struggling with trying to understand a few IIR/FIR filters I decided to try to implement something simple that I could understand. So I decided to try to model the action of an inductor or capacitor. This should model an inductor or a capacitor:

    struct SIFilter {
        last:       f64,
        scale:      f64,
    }

    impl SIFilter {
        fn new(scale: f64) -> SIFilter { SIFilter { last: 0.0, scale: scale } }
        fn low(&mut self, mut sample: f64) -> f64 {
            let delta = sample - self.last;
            sample -= delta * self.scale;
            self.last = sample;
            sample
        }
        fn high(&mut self, mut sample: f64) -> f64 {
            let delta = sample - self.last;
            self.last = sample;
            delta * self.scale
        }
    }

    struct SIFilterC {
        i:      SIFilter,
        q:      SIFilter,
    }

    impl SIFilterC {
        fn new(scale: f64) -> SIFilterC { SIFilterC { i: SIFilter::new(scale), q: SIFilter::new(scale) } }
        fn high(&mut self, mut sample: &Complex<f64>) -> Complex<f64> {
            Complex::new(self.i.high(sample.re), self.q.high(sample.im))
        }
        fn low(&mut self, mut sample: &Complex<f64>) -> Complex<f64> {
            Complex::new(self.i.low(sample.re), self.q.low(sample.im))
        }
    }

To make sharper filter edges I have found that reapplying the filter a number of times, and if needed including full signal amplification in between will create a very sharp response, however at the expense of greatly increased number of CPU cycles per sample.

The inductor resists changes while the capacitor encourages changes in input. The capacitor (high) will also shift the output by 90 degrees, but the inductor (low) does not.

    let mut filter = SIFilterC::new(0.4);
    for sample in signal.iter_mut() {
        *sample = filter.high(sample);
    }

The above shows a signal being filtered by the capacitor (high pass). The lower the factor the higher the frequency threshold, and by increasing the degree we can achieve a sharper edge.

2. Shifting A Signal In The Frequency Domain

I have been searching for some time about shifting a signal in the frequency domain. The actual practical mechanism has been eluding me, although I have made great gains in getting closer. Also through my tinkering with trying to implement a DFT I have come across some of the very same mechanics that make shifting a signal possible. One of the most important pieces of the puzzel is the elusive exp(i*pi*t*m). The problem is I have no idea how to actually use it. So I am going to take another stab and try again!

I can understand the -j will cause rotation, and the w being angular frequency, and finally the t being the time. I also know from reading that if you multiply the signal by exp(i*pi*t*m) that you will shift it. The interesting part here however is that this simply sounds like an IF mixer circuit, and I am starting to think it might work exactly like that. However, it still does not explain exactly how the equation works, also considering how the natural logarithm fits in. The e or/and exp(..) are the most confusing parts.

Now, that I have the idea of doing a IF mixer in software I am going to see if I can shift the frequency. I will produce a signal and multiply that my target signal, and then use FFTW (my DFT library) to examine the output and see if it actually shifted, hopefully..

After seeing that exp(..) = cos(x) + i*sin(x) I decided to create a signal as a complex stream and multiply that with my target signal, and see if I can shift it. The following code snipplet shows:

    let rpt = 1.0 / sps as f64;

    for x in 0..dsignal.len() {
        let rad = (rpt * x as f64 * PI * 2.0 * 100000.0);
        let p = Complex::new(rad.cos(), rad.sin());
        dsignal[x] = p * dsignal[x];
    }

Where sps is the sampling frequency (samples per second), rpt is the time per sample, x is the sample index, and 100000.0 is the frequency of my intermediate signal. The IF signal (intermediate signal) is multipled with the signal using complex number math. I do not fully understand the indepth workings, but I am getting closer, and this concludes the problem of shifting a signal in the frequency domain! _The dsignal is an array of complex samples. The samples have both a real and imaginary component, or in other words each sample has is a 2D vector (XY) with a magnitude. The IF signal I create is also a series of 2D vectors, with a magnitude of one. The resultant signal when viewed with a DFT from FFTW showed the signal shifted! I have not verified the output fully, but from a simple visual exmaination it does indeed to appear to have worked correctly._

3. FM Demoulation

Well, I have arrived at the point in which I can attempt to demodulate an FM signal. I have the ability to filter the signal and shift the signal. I was reading and came across three different analog circuit designs that will base my digital design on: quadature detector, phase locked loop, and coincidence detector.

I originaly had thought that the phase locked loop detector would be the best, but after finding out about the other two I have decided to give the quadature detector a try. It seems like it might lend itself to the simplest digital design.

[a day later..]

I spent most of the day building a really nicely structured DSP library of my routines, but after I got done I did a little pondering and came up with a really simple way to decode an FM signal. Firstly, I centered the frequency domain on the FM signal, with left sideband as negative frequencies and right sideband as positive frequency. I actually did two FM stations at the same time by shifting the signal in the frequency domain and producing two signals with two different stations. Then I filtered with a low pass until I antenuated anything outside of the signal bandwidth. Next, we go sample per sample of the complex signal (I/Q) and calculate the phase difference. This phase difference of -PI to PI can be mapped to -128 to 128 and this can be written out as a WAVE file.

    /// A crude but working FM demodulator. I hope this is easy to learn from
    ///
    pub struct CrudeC64I8;

    impl CrudeC64I8 {
        pub fn new() -> CrudeC64I8 { CrudeC64I8 }
    }

    impl Adapter<Complex<f64>, i8> for CrudeC64I8 {
        fn work(&mut self, input: Vec<Complex<f64>>) -> BlockOutput<i8> {
            let mut out: Vec<i8> = Vec::new();
            for s in input.windows(2) {
                let a = s[0].im.atan2(s[0].re);
                let b = s[1].im.atan2(s[1].re);

                // -PI to 0.0 to PI
                let c = b - a;
                // positive angle - positive deviation
                // negative angle - negative deviation

                // ratio..  -1.0 to 0.0 to 1.0
                let r = c / PI;
                // convert to full swing
                out.push((128.0 * r) as i8);
            }
            BlockOutput::Ready(out)
        }
    }

The above shows me using atan2 to get the phase angles between two samples. I use a overlapping iteration where I check 0:1, 1:2, 2:3, and so forth. The algorithm is a little assuming in that it does not expect the phase different between two samples to be over PI.

I will continue experimenting and hopefully improve the design!

4. Link Dump

    http://whiteboard.ping.se/SDR/IQ
    http://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/
    http://www.fftw.org/fftw3_doc/The-1d-Discrete-Fourier-Transform-_0028DFT_0029.html#The-1d-Discrete-Fourier-Transform-_0028DFT_0029
    http://en.wikipedia.org/wiki/Goertzel_algorithm
    http://dsp.stackexchange.com/questions/22658/whats-the-exponential-term-in-fourier-transform-mean
    http://www.fftw.org/
    http://www.radio-electronics.com/info/rf-technology-design/fm-reception/fm-pll-detector-demodulator-demodulation.php