Goertzel self test

Hi Chip

I've been running some Goertzel tests today and i'm getting erratic results.
I am looping the Goertzel output back into itself (via 270R resistor) and taking samples while sweeping from10kHz to 2MHz.
What i'm seeing is quite large phase and power changes as well as a lot of noise.
System clock speed also affects results.
Not sure if I'm doing something wrong (more than likely) .

Here's some snippets from the data collected
60 MHz sys clock
    100000Hz X=$000BE714 Y=$00012E3A rho=$000BF608 theta=$04072BF2 
   2090000Hz X=$FFFFC828 Y=$00007776 rho=$000083DE theta=$51D104A1 

80 Mhz sys clock
    100000Hz X=$000FE366 Y=$000148E2 rho=$000FF0AC theta=$03498D31 
   2090000Hz X=$FFFFF807 Y=$0000AE56 rho=$0000AE85 theta=$41DCAA5C 

100 MHz sys clock
    100000Hz X=$0013DF51 Y=$00016316 rho=$0013EBB2 theta=$02D6D7F9 
   2090000Hz X=$00002738 Y=$0000D666 rho=$0000D9F5 theta=$38A0E418 
As Goertzel frequency increases power values reduce and phase shifts.
Any ideas?

Melbourne, Australia
«1

Comments

  • 40 Comments sorted by Date Added Votes
  • Was that one feature impacted by the signed math problem?

    Do not taunt Happy Fun Ball! @opengeekorg ---> Be Excellent To One Another SKYPE = acuity_doug
    Parallax colors simplified: https://forums.parallax.com/discussion/123709/commented-graphics-demo-spin<br>
  • IIRC Chip said somewhere here that Goertzel was not affected.
    Melbourne, Australia
  • The colorspace IQ modulator doesn't work because of the sign extension problem.

    About these Goertzel measurements, if you are looking at a frequency of 100KHz, using a system clock of 80MHz for, say 10ms, and then you do the same measurement of 100KHz for 10 ms from a 160MHz clock, you are going to get twice the accumulated sine and cosine samples. This is going to affect power, but not necessarily the phase angle.

    I will run these kinds of tests tonight to see what I get.
  • I tried a different loop structure using an interrupt to feed the streamer commands.
    Doesn't seem to have made any differenct to results.
    main
    		getxacc	gtz_x		'dummy read/zero accumulators
    		mov	gtz_y,0-0
    
    		getct	st
    		addct2	st,##10 * ms	'10mS sample
    .loop		pollct2	wc
    	if_nc	jmp	#.loop
    		getxacc	gtz_x
    		mov	gtz_y,0-0	'get goertzel accumulation
    
    		qvector	gtz_x,gtz_y	'convert to rh0,theta
    		getqx	rho		'get rho,theta results
    		getqy	theta
    

    I will keep digging.....
    Melbourne, Australia
  • Oz,
    You've got %TT = %01 in your ADC mode setting that isn't a smart mode. I vaguely remember an exchange between you and Chip on this, but I can't find it.

    "Are we alone in the universe?"
    "Yes," said the Oracle.
    "So there's no other life out there?"
    "There is. They're alone too."
  • evanh wrote: »
    Oz,
    You've got %TT = %01 in your ADC mode setting that isn't a smart mode. I vaguely remember an exchange between you and Chip on this, but I can't find it.
    Nope.
    I have the same TT setting as Chip's Goertzel demo.
    Tried all 4 combinations, no difference. :(

    Melbourne, Australia
  • evanhevanh Posts: 5,647
    edited November 4 Vote Up0Vote Down
    Heh, I was thinking I should document it. I think it's a workaround to enable the ADC when not in a smart mode. One of the revision fixes.

    "Are we alone in the universe?"
    "Yes," said the Oracle.
    "So there's no other life out there?"
    "There is. They're alone too."
  • Found the original posts. It was for DAC mode, not ADC mode: https://forums.parallax.com/discussion/169163/need-help-with-dac-streamer-configuration/p1

    And I might have imagined the %TT part too. I'm not sure what bit7 Chip is talking about now.

    "Are we alone in the universe?"
    "Yes," said the Oracle.
    "So there's no other life out there?"
    "There is. They're alone too."
  • cgraceycgracey Posts: 10,131
    edited November 4 Vote Up0Vote Down
    I'm running the Goertzel thing now and I'm using a single pin as both a Goertzel DAC output and as the ADC input to the Goertzel. In all DAC modes, DIR must be high to enable DAC output. If OUT is also high, it turns on the ADC and the delta-sigma stream comes out the IN signal.

    I'm seeing things being really stable, but, crazy enough, the same kind of ADC noise we've been battling is showing up here, causing low frequency wandering.

    HEY!!! I just made my signal frequency a multiple of 60Hz and the dang wandering went away. It looked like a beat frequency and it was! WOW!! If I tweak my frequency to really sync to the ambient 60Hz, IT TOTALLY GOES AWAY!!!!

    Here is the code I'm playing with:
    con		adcpin = 0
    		xpin = 8
    		ypin = 9
    		shift = 14-2
    		clock_freq = 200_000_000.0
    		signal_freq = 6_001_000.0
    		samples = 10000
    
    ' set up clock
    
    dat		org
    
    		hubset	##%1_000000_0000001001_1111_10_00	'enable crystal+PLL, stay in 20MHz+ mode
    		waitx	##20_000_000/100			'wait ~10ms for crystal+PLL to stabilize
    		hubset	##%1_000000_0000001001_1111_10_11	'now switch to PLL running at 200MHz
    
    ' make a sin/cos table in LUT
    
    		mov	z,#$1FF			'make 512-sample sin/cos table in lut
    sincos		mov	x,z			'get angle into top 9 bits of x
    		shl	x,#32-9
    		qrotate	#$7F,x			'get sin/cos of (ro,theta)
    		getqx	x			'get cos
    		getqy	y			'get sin
    		setbyte	x,y,#1			'get sin into byte1, cos in byte0
    		setword	x,x,#1			'copy bytes 1,0 to 3,2
    		xor	x,##$8080		'make bytes 1,0 positive (not used, but could be)
    		wrlut	x,z			'write sin:cos:psin:pcos into lut bottom bytes
    		djnf	z,#sincos		'make 512 samples
    
    ' set up I/O
    
    doit		wrpin	dacmode,#adcpin		'enable DAC output and ADC input on same pin
    		drvh	#adcpin
    
    		dirh	#xpin			'enable X,Y pins for future DAC output
    		dirh	#ypin
    
    ' Do Goertzel loop, show accumulations on X,Y pins for scope in X,Y mode
    
    loop		setq	f1			'ready frequency
    		xcont	m1,#0			'issue Goertzel command
    		getxacc	x			'get last Goertzel accumulations, x first
    		mov	y,0			'y comes through s
    
    		sar	x,#shift		'shift down results and make unsigned for x,y scope input
    		sar	y,#shift
    		xor	x,#$80			'(change these xor's to mov's to find center x,y)
    		xor	y,#$80
    
    		setbyte	xymode,x,#1		'x pin update
    		wrpin	xymode,#xpin
    
    		setbyte	xymode,y,#1		'y pin update
    		wrpin	xymode,#ypin
    
    		jmp	#loop			'loop
    
    
    xymode		long	%0000_0000_000_1011100000000_00_00000_0		'DAC for x,y scope output (0-2V)
    
    dacmode		long	%0000_0000_000_1011000000000_01_00000_0		'Goertzel DAC, also used as ADC
    
    f1		long	round(signal_freq/clock_freq*float($80000000))	'Goertzel frequency
    
    m1		long	%0000_0001<<24 + adcpin<<17 + samples		'Goertzel mode, DAC0 output
    
    x		res	1
    y		res	1
    z		res	1
    

    For this program, pin 8 = X and pin 9 = Y for X,Y mode on a scope. It makes sense to just look at the accumulations as coordinates, instead of the rho,theta approach.
  • Good find too.

    "Are we alone in the universe?"
    "Yes," said the Oracle.
    "So there's no other life out there?"
    "There is. They're alone too."
  • cgracey wrote: »
    ...

    HEY!!! I just made my signal frequency a multiple of 60Hz and the dang wandering went away. It looked like a beat frequency and it was! WOW!! If I tweak my frequency to really sync to the ambient 60Hz, IT TOTALLY GOES AWAY!!!!

    Are you still on Bench supplies ? - what is their 60Hz ripple ? What about ambient 60Hz fields ?
    With a DAC driving a ADC, there are no board-level HiZ nodes ?
    What about unused pins ? - they should not be left to float.


  • jmg wrote: »
    cgracey wrote: »
    ...

    HEY!!! I just made my signal frequency a multiple of 60Hz and the dang wandering went away. It looked like a beat frequency and it was! WOW!! If I tweak my frequency to really sync to the ambient 60Hz, IT TOTALLY GOES AWAY!!!!

    Are you still on Bench supplies ? - what is their 60Hz ripple ? What about ambient 60Hz fields ?
    With a DAC driving a ADC, there are no board-level HiZ nodes ?
    What about unused pins ? - they should not be left to float.


    I'm still on bench supplies. Not sure what their ripple is. Certainly ambient 60Hz field in here.

    I need to see what 60Hz-multiple sampling does for the ADC now.
  • cgracey wrote: »
    jmg wrote: »
    cgracey wrote: »
    ...

    HEY!!! I just made my signal frequency a multiple of 60Hz and the dang wandering went away. It looked like a beat frequency and it was! WOW!! If I tweak my frequency to really sync to the ambient 60Hz, IT TOTALLY GOES AWAY!!!!

    Are you still on Bench supplies ? - what is their 60Hz ripple ? What about ambient 60Hz fields ?
    With a DAC driving a ADC, there are no board-level HiZ nodes ?
    What about unused pins ? - they should not be left to float.


    I'm still on bench supplies. Not sure what their ripple is. Certainly ambient 60Hz field in here.

    I need to see what 60Hz-multiple sampling does for the ADC now.

    So, are the testers here in the Antipodes seeing 50Hz noise?
  • cgraceycgracey Posts: 10,131
    edited November 4 Vote Up0Vote Down
    Here I'm looking at some LSBs of the X,Y Goertzel reading on my scope. My Goertzel signal was set to 6,000,000Hz. My crystal is off, though, by some amount, because its error is guaranteed within 50ppm. By increasing my frequency to 6,000,100Hz (+16ppm), I better sync to my 60Hz environment and a lot of noise goes away. Look!

  • cgraceycgracey Posts: 10,131
    edited November 4 Vote Up1Vote Down
    So, this is certainly an argument for using a clipped-sine oscillator on the EVAL board, like Jmg's been talking about. When it comes to something like measuring small signals in an AC-noisy environment, it's critical to be able to cancel out those AC effects.
  • I've got to do some tests on the ADC to make sure this wasn't all due to some numerical effect of certain NCO values, but, indeed, has to do with the AC environment.
  • Ooh yes, when you sync the frequency its much more stable :)
    My Prop boards: P8XBlade2, RamBlade, CpuBlade, TriBlade
    Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
  • I'm wondering about adding dither to the NCO. Maybe that could help reduce birdies.
  • cgraceycgracey Posts: 10,131
    edited November 4 Vote Up0Vote Down
    This Goertzel thing is working really well now. It's doing exactly what I hoped it would do.

    Here I have P0 outputting the Goertzel reference signal, a sine wave of 1.2MHz (multiple of the 60Hz power all around me, so it cancels noise) for 1200 cycles, so each measurement takes 1ms.

    I'm using P12 as a 100x magnification ADC input to the Goertzel multiply-and-accumulate. This means about +/-18mV full-span, so it's sensitive.

    The P0 DAC output is touching my body, so I'm like a broadcast antenna, and a piece of wire connected to P12 is a receiving antenna. My proximity to the P12 wire has huge and precise effect on the Goertzel output, which is coming out of P8 and P9 in the form of X,Y signals to go into my scope for viewing in X,Y mode.

    I am really pleased with how good the signal-to-noise ratio is. This is working just like I hoped it would.

    Check this video out:

    (must download the attachment)


    Here's the code that does it:
    con		gtzpin = 0
    		adcpin = 12
    		xpin = 8
    		ypin = 9
    		shift = 13
    		clock_freq = 200_000_000.0
    		signal_freq = 1_200_000.0
    		samples = 1200
    
    ' set up clock
    
    dat		org
    
    		hubset	##%1_000000_0000001001_1111_10_00	'enable crystal+PLL, stay in 20MHz+ mode
    		waitx	##20_000_000/100			'wait ~10ms for crystal+PLL to stabilize
    		hubset	##%1_000000_0000001001_1111_10_11	'now switch to PLL running at 200MHz
    
    ' make a sin/cos table in LUT
    
    		mov	z,#$1FF			'make 512-sample sin/cos table in lut
    sincos		mov	x,z			'get angle into top 9 bits of x
    		shl	x,#32-9
    		qrotate	#$7F,x			'get sin/cos of (ro,theta)
    		getqx	x			'get cos
    		getqy	y			'get sin
    		setbyte	x,y,#1			'get sin into byte1, cos in byte0
    		setword	x,x,#1			'copy bytes 1,0 to 3,2
    		xor	x,##$8080		'make bytes 1,0 positive (not used, but could be)
    		wrlut	x,z			'write sin:cos:psin:pcos into lut bottom bytes
    		djnf	z,#sincos		'make 512 samples
    
    ' set up I/O
    
    		wrpin	dacmode,#gtzpin		'enable DAC output and ADC input on same pin
    		drvh	#gtzpin
    
    		wrpin	adcmode,#adcpin		'enable ADC pin (Goertzel may use gtzpin directly)
    
    		dirh	#xpin			'enable X,Y pins for future DAC output
    		dirh	#ypin
    
    ' Do Goertzel loop, show accumulations on X,Y pins for scope in X,Y mode
    
    loop		setq	f1			'ready frequency
    		xcont	m1,#0			'issue Goertzel command
    		getxacc	x			'get last Goertzel accumulations, x first
    		mov	y,0			'y comes through s
    
    		sar	x,#shift		'shift down results and make unsigned for x,y scope input
    		sar	y,#shift
    		xor	x,#$80			'(change these xor's to mov's to find center x,y)
    		xor	y,#$80
    
    		setbyte	xymode,x,#1		'x pin update
    		wrpin	xymode,#xpin
    
    		setbyte	xymode,y,#1		'y pin update
    		wrpin	xymode,#ypin
    
    		jmp	#loop			'loop
    
    
    xymode		long	%0000_0000_000_1011100000000_00_00000_0		'DAC for x,y scope output (0-2V)
    
    adcmode		long	%0000_0000_000_1001110000000_00_00000_0		'ADC input, 100x mode
    
    dacmode		long	%0000_0000_000_1011000000000_01_00000_0		'Goertzel DAC, also used as ADC
    
    f1		long	round(signal_freq/clock_freq*float($80000000))	'Goertzel frequency
    
    m1		long	%0000_0001<<24 + adcpin<<17 + samples		'Goertzel mode, DAC0 output
    
    x		res	1
    y		res	1
    z		res	1
    
  • Congratulations Chip, that's really impressive.

    @ozpropdev, this looks really handy for your project
  • Is my reasoning off for using 1.2MHz? It DID make a difference, but it really shouldn't matter in relation to 60Hz AC ambient, right? We have no constant relationship with the 60Hz phase.
  • I could understand it needing an integer number of cycles of the frequencies of interest, I guess this includes 60/50 Hz as well as a carrier

    Going to spend some quality time with Goertzel tomorrow.
  • Tubular wrote: »
    I could understand it needing an integer number of cycles of the frequencies of interest, I guess this includes 60/50 Hz as well as a carrier

    Going to spend some quality time with Goertzel tomorrow.

    One nice thing about this Goertzel setup is that the ADC's low-frequency thermal wandering is out-of-band and gets filtered away. The ADC seems to work ideally in this mode.
  • cgraceycgracey Posts: 10,131
    edited November 4 Vote Up0Vote Down
    I'm thinking about that thing I posted above where it takes a measurement every 1ms.

    Each subsequent measurement is started with a new XCONT instruction which specifies the ADC pin to look at. It would be interesting to switch among several ADC pins and track them in sequence, repeatedly. What kind of data could be gleaned by doing that, I wonder. I think, by placing their antennae in different directions, you could resolve direction from where signal is coming from. So many things are possible.
  • cgraceycgracey Posts: 10,131
    edited November 4 Vote Up0Vote Down
    I tried it out. Pretty neat, I think. You'll have to download the .mp4 file.

    Here's the code. I just increment the ADC pin each time through, to cycle through all four:
    con		gtzpin = 0
    		adcpin = 12
    		xpin = 8
    		ypin = 9
    		shift = 13
    		clock_freq = 200_000_000.0
    		signal_freq = 1_200_000.0
    		samples = 1200
    
    ' set up clock
    
    dat		org
    
    		hubset	##%1_000000_0000001001_1111_10_00	'enable crystal+PLL, stay in 20MHz+ mode
    		waitx	##20_000_000/100			'wait ~10ms for crystal+PLL to stabilize
    		hubset	##%1_000000_0000001001_1111_10_11	'now switch to PLL running at 200MHz
    
    ' make a sin/cos table in LUT
    
    		mov	z,#$1FF			'make 512-sample sin/cos table in lut
    sincos		mov	x,z			'get angle into top 9 bits of x
    		shl	x,#32-9
    		qrotate	#$7F,x			'get sin/cos of (ro,theta)
    		getqx	x			'get cos
    		getqy	y			'get sin
    		setbyte	x,y,#1			'get sin into byte1, cos in byte0
    		setword	x,x,#1			'copy bytes 1,0 to 3,2
    		xor	x,##$8080		'make bytes 1,0 positive (not used, but could be)
    		wrlut	x,z			'write sin:cos:psin:pcos into lut bottom bytes
    		djnf	z,#sincos		'make 512 samples
    
    ' set up I/O
    
    		wrpin	dacmode,#gtzpin		'enable DAC output and ADC input on same pin
    		drvh	#gtzpin
    
    		wrpin	adcmode,#adcpin		'enable ADC pin (Goertzel may use gtzpin directly)
    		wrpin	adcmode,#adcpin+1
    		wrpin	adcmode,#adcpin+2
    		wrpin	adcmode,#adcpin+3
    
    		dirh	#xpin			'enable X,Y pins for future DAC output
    		dirh	#ypin
    
    ' Do Goertzel loop, show accumulations on X,Y pins for scope in X,Y mode
    
    loop		setq	f1			'ready frequency
    		xcont	m1,#0			'issue Goertzel command
    		getxacc	x			'get last Goertzel accumulations, x first
    		mov	y,0			'y comes through s
    
    		sar	x,#shift		'shift down results and make unsigned for x,y scope input
    		sar	y,#shift
    		xor	x,#$80			'(change these xor's to mov's to find center x,y)
    		xor	y,#$80
    
    		setbyte	xymode,x,#1		'x pin update
    		wrpin	xymode,#xpin
    
    		setbyte	xymode,y,#1		'y pin update
    		wrpin	xymode,#ypin
    
    		bitnot	m1,#17		wcz	'increment ADC pin number
    	if_c	bitnot	m1,#18
    
    		jmp	#loop			'loop
    
    
    xymode		long	%0000_0000_000_1011100000000_00_00000_0		'DAC for x,y scope output (0-2V)
    
    adcmode		long	%0000_0000_000_1001110000000_00_00000_0		'ADC input, 100x mode
    
    dacmode		long	%0000_0000_000_1011000000000_01_00000_0		'Goertzel DAC, also used as ADC
    
    f1		long	round(signal_freq/clock_freq*float($80000000))	'Goertzel frequency
    
    m1		long	%0000_0001<<24 + adcpin<<17 + samples		'Goertzel mode, DAC0 output
    
    x		res	1
    y		res	1
    z		res	1
    
  • YanomaniYanomani Posts: 664
    edited November 4 Vote Up0Vote Down
    Perhaps there is a suitable multiple of both 50 Hz and 60Hz, +- ppm tolerance that could ensure the same good effects to your tests and the ones being carried worldwide.

    Wikipedia's Mains Electricity by Country shows a comprehensive listing.

    https://en.wikipedia.org/wiki/Mains_electricity_by_country

    As always, providence comes in help again, and Australia is listed among the 50 Hz ones.

    Maybe using a 12.288 MHz, clipped sine, VCTCXO could even enable calibration under sofware control, both numerically and also thru a filtered pin DAC.

    The above frequency was selected because it can be divided by 50, 60, generating a lot of binary and decimal submultiples (including 32768).

    It has to be tested how HDMI sinks would react to 245.7600 MHz. I believe it won't give a dime for the difference and will work solid and stable like a Rock(lin)!
  • Congrats Chip, you just built a Theremin!
  • cgracey wrote: »
    Is my reasoning off for using 1.2MHz? It DID make a difference, but it really shouldn't matter in relation to 60Hz AC ambient, right? We have no constant relationship with the 60Hz phase.

    Do you mean as a multiple of 60Hz ?
    It does make sense to sync things up to 60Hz, as there will be harmonic chirps at various parts of 60Hz, from things like Dimmers and SMPS Power factor correctors.
    You want all those artifacts fixed in time, not walking thru your data.

    The way to fully null 50/60Hz effects, for DC measurements, is to measure for a whole cycle.
  • Yanomani wrote: »
    Maybe using a 12.288 MHz, clipped sine, VCTCXO could even enable calibration under sofware control, both numerically and also thru a filtered pin DAC.

    12.288MHz is a rare value, more common are GPS related valued, like 19.2MHz and 26MHz
    The PLL means either of those can be used, ans still have whole-number relations with 50Hz/60Hz
    19.2M/60 = 320000
    19.2M/50 = 384000
    26M/50 = 520000
    26M/60 = 433333.3333' - so you need a x3 in the PLL, if you want whole-numbers.

    Currently cheapest VCTCXO at digikey is
    NT1612AA-48MHZ-END5173A NDK America, Inc. XTAL OSC VCTCXO 48.0000MHZ 990 - Immediate $0.92400/500 (1.60mm x 1.20mm) 0.018" (0.45mm)

    Next is
    ASVTX-11-121-19.200MHZ-T Abracon LLC XTAL OSC VCTCXO 19.2000MHZ SNWV 3,225 - Immediate $1.13576/500 (3.20mm x 2.50mm) 0.035" (0.90mm)

    and if you check at lcsc these appear (notice the prices here... )
    TCXO lcsc
    KDS Daishinku 1XTW26000CGA SMD-3225_4P In stock: 2196 Ship Immediately 26MHz 1.5ppm relow 0.2ppm temp 1ppm/yr aging
    1+ $0.3298 100+ $0.2807 1000 $0.2695

    KDS Daishinku 1XXA26000MAA SMD-2520_4P In stock: 3980 Ship Immediately
    1+ $0.3061 100+ $0.2604 1000+ $0.2500

    I'm not sure how 48MHz clipped sine drive would go on a P2, certainly worth testing. At some point, the Xtal amplifier will run out of gain.
    19.2 & 26MHz I'd expect to have no problems.

    This also illustrates the importance of a wide-choice-footprint design on the PCB
  • jmg wrote: »
    The way to fully null 50/60Hz effects, for DC measurements, is to measure for a whole cycle.

    That's the point Chip is making I think. There is no measuring in his examples. He's getting success just by approximating a mains frequency multiple.

    Then this is posted:
    cgracey wrote: »
    One nice thing about this Goertzel setup is that the ADC's low-frequency thermal wandering is out-of-band and gets filtered away. The ADC seems to work ideally in this mode.

    "Are we alone in the universe?"
    "Yes," said the Oracle.
    "So there's no other life out there?"
    "There is. They're alone too."
Sign In or Register to comment.