How to utilize DDS/Goertzel LUT mode
soohan_kim
Posts: 6
I'm having trouble understanding how to implement DDS/Goertzel on the P2. I have a sine wave being output from one pin in the first spin2 file. Another pin measures the sine wave and displays it on the debug scope.
I have another snippet of code that uses the regular DAC/ADC modes to output and measure DC voltages.
What I'd like to do is measure the sine wave from the first snippet of spin2. However, rather than using the normal ADC mode, I'd like to be able to use DDS/Goertzel to measure the frequency content of the signal and extract the real/imaginary components. I'm a little lost on how to implement that in spin2.
Comments
Soohan_kim, let me write an object that does this in PASM, so that it interfaces to Spin2. This way, the timing can be independent of your Spin2 code and the interface can become a few input and output variables. Hopefully, I can have this done today.
Wow, that's more than I could've asked for. Thank you Chip!
I didn't get to it yesterday, but I will work on it this morning.
No worries, thanks for helping out on this!
Here is the program. It outputs SINE and !SINE on two adjacent pins, then does the Goertzel input over another pin.
In this example (which is easily modified) it is outputting 10KHz over a little speaker connected directly to two opposite-phase 75-ohm DAC pins, while it inputs from a dynamic microphone coupled through a capacitor using 100x magnification ADC mode. The data is shown on the SCOPE_XY display in LOGSCALE mode.
In the video, you can see the phase winding around as I pull and push the microphone away/towards the speaker on the JonnyMac board.
It occurred to me that you could measure distance by varying the frequency a little and observing a phase-multiplying effect on the input side.
Great demo, Chip. Better find those Ultrasonic transceivers
Yes, but the microphone and speaker have greater frequency response, so some interesting stuff is possible.
I modified the program to output 10KHz and take a measurement, then 11KHz and take a measurement. The two return phases change at different rates. It's kind of scrappy, but to make it better, I'll use two LUT halves to each output 10KHz + 11KHz, then toggle between the halves which will have unique bytes in the upper words, to make separate 10KHz and 11KHz input tables. This way, I can toggle, back to back, between measurement modes while outputting a continuous 10KHz + 11KHz function to the speaker. It will then be as smooth as the video, but have TWO dots which change angles at different rates. This amounts to a measurement distance of the 10KHz period multiplied by the 11KHz period. Measurement becomes the phase delta between the two, ignoring power.
That was a great demo! Thanks for putting your time into this. I want to make sure I understand the PASM, so I have a few questions:
Let me know if you have any suggestions for how I should modify the program to suit this application. Otherwise, this is a great starting point for me to work off of. Thanks again!
Also, what's the way to go to represent the raw values for power and angle from the debug?
The (X,Y) that comes out of the Goertzel via GETXACC+MOV are the Imaginary and Real terms. The QVECTOR instruction converts those into both magnitude and phase, which I termed "power" and "angle".
The "cycles" variable tells how many integral cycles to measure for. The bigger this number, the more selective the process becomes.
To know what 1x gain looks like, set "adcmag" to 0 and connect the ADC pin to one of the DAC output pins. The resultant reading will be your 1x level. Now, you can connect your ADC to other points in whatever circuit you've got and take measurements from those points, as well. We could also automate the ADC pin changing. As well, up to four pins in a set of four (%xxxxyy, where %xxxx is the group and %yy are the members) can be added/subtracted from the measurement, allowing you to make differential measurements, for example.
Gotcha, that makes sense. Really appreciate your help!
I've just found this thread and suddenly had an idea which has nothing to do with the original question but might be useful to others:
You can put sine/cosine waves with different frequencies into bytes 1/2 and 3/4 of the lookup table, for example the base frequency (one cycle) into bytes 1+2 which goes to the output pins and the third overtone into bytes 3+4 which are used for multiplication and summing. This way it's possible to detect non-linearities of the transmission line like clipping or overshot.