Shop OBEX P1 Docs P2 Docs Learn Events
precision sine wave generation — Parallax Forums

precision sine wave generation

TCP71TCP71 Posts: 38
edited 2012-08-27 09:32 in Propeller 1
I've been looking through some of the sine wave generation threads and OBX modules, but everyone seems to want faster generation, whereas I am looking for precision. Assuming that I can clock the propeller with perfect precision (using a GPS sync'd frequency generator), I need to be able to produce frequency stable sine waves in the range of 10-100Hz in 10Hz increments. There seem to be multiple different objects that I can use, but my concern is the circuit required at the output pin to create the actual waveform. I really need an output of 0.3Vp-p centered around a ground. Any ideas or help appreciated. I can transformer couple the output if necessary.

Comments

  • Christof Eb.Christof Eb. Posts: 1,237
    edited 2012-08-21 11:17
    Hi,
    perhaps you could specify a little bit more exactly, what precision you need.
    I have used the ROM sine table and pwm-dac, which is "quite stable".
    Good luck, Christof
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-08-21 11:25
    RC-filtered DUTY-mode output fed into an op-amp to set the gain and offset should work just fine. To get a ground-centered output, the op-amp will need both positive and negative supplies. An LTC1152 with +5V/-5V supplies would be a good choice, but any general-purpose op-amp should work.

    BTW, a transformer that would work at 10 Hz would have to be rather bulky.

    -Phil
  • pik33pik33 Posts: 2,397
    edited 2012-08-21 11:35
    .. or you can use noise shaped PWM working @ about 300 kHz/8bit. When using good filters you can get >100 dB SNR @ 100 Hz.
  • TCP71TCP71 Posts: 38
    edited 2012-08-21 12:02
    Wow, thanks for the quick replies. I guess I need to have the frequency user selectable (through a switch or user interface) and then using something like PropellerSignalGenerator and TestBench or Sinewave_V2.1 I can muddle my way through the code, but each specifies and "output" or "sync" pin. What is the circuit to take the propeller output and see the actual sine wave? The signal doesn't need to be particularly noise free, but the frequency must be stable.
    Thanks. Sorry for the simpleton questions.
  • TCP71TCP71 Posts: 38
    edited 2012-08-21 14:58
    Would the circuit in this thread would work with "propellerSignalGenerator"?

    http://forums.parallax.com/showthread.php?126254-DAC-Help

    with an 18k resistor and 0.01uf cap perhaps.
  • jmgjmg Posts: 15,183
    edited 2012-08-21 15:32
    TCP71 wrote: »
    I've been looking through some of the sine wave generation threads and OBX modules, but everyone seems to want faster generation, whereas I am looking for precision. Assuming that I can clock the propeller with perfect precision (using a GPS sync'd frequency generator), I need to be able to produce frequency stable sine waves in the range of 10-100Hz in 10Hz increments.

    Precision needs numbers ie- tolerated deviation in uHz or ppm, and tolerated jitter in ns
    You only want relatively few points, as 10Hz is quite coarse.

    For example, a /N approach, has no cycle-cycle jitter, but has small but stable errors.
    A NCO approach, will allow many more frequencies, but can have sub-frequency jitter components.
    N=0;;N=N+10;80e6/round(80e6/N)
    ans = 10
    ans = 20
    ans = 29.999996250
    ans = 40
    ans = 50
    ans = 60.000015000
    ans = 70.000008750
    ans = 80
    ans = 89.999988750
    ans = 100
    

    Errors look to be 250ppb/125ppb/0ppb in the time domain.

    In the analog domain, digital power noise will limit 'highest precision' , so you may need an external DAC.
    I2S DACs are cheap, and have very low analog noise floors, and are great for Audio-frequencies.

    There was talk of an I2S sine option, in an earlier Sine thread.
    Not sure where that ended up ?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-08-21 15:41
    I'd be more inclined to try something like this:

    attachment.php?attachmentid=95068&d=1345588881

    Using differential DUTY-mode outputs in this fashion automatically gives you an AC signal that straddles ground. It's important to use matched resistors and an op-amp with a very low input offset voltage. You might even consider using an instrumentation amplifier. I would wire it up on a good-quality perf-board with plated through holes and a ground plane. A solderless breadbaord, if my experience today with this circuit is any indication, will permit too much noise to appear on the output.

    -Phil
    426 x 246 - 11K
  • jmgjmg Posts: 15,183
    edited 2012-08-21 15:58
    #8 look good, I'd add a minor detail of a split of the 22K, to allow a cap to gnd on both arms.
    That means the opamp does NOT have to try to cope with 80Mhz digital common mode....
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-08-21 16:16
    jmg wrote:
    I'd add a minor detail of a split of the 22K, to allow a cap to gnd on both arms.
    Yeah, I was thinking the same thing but haven't tried it yet. Anything to keep as much noise off the input pins as possible.

    So the new values would be 10K, 10K, and 910R instead of 1K.

    -Phil
  • Mark_TMark_T Posts: 1,981
    edited 2012-08-21 16:28
    If you want to use DDS to generate a sine wave with more precision than the built-in sin table then using CORDIC algorithm will allow upto 29 bits or so. If the phase steps are small then coherency techniques might bepossible to speed up the calculations too.

    You really do need to explain what "precise" means to you though in terms like phase-noise, jitter, SNR,
  • frank freedmanfrank freedman Posts: 1,983
    edited 2012-08-21 22:07
    TCP71 wrote: »
    I've been looking through some of the sine wave generation threads and OBX modules, but everyone seems to want faster generation, whereas I am looking for precision. Assuming that I can clock the propeller with perfect precision (using a GPS sync'd frequency generator), I need to be able to produce frequency stable sine waves in the range of 10-100Hz in 10Hz increments. There seem to be multiple different objects that I can use, but my concern is the circuit required at the output pin to create the actual waveform. I really need an output of 0.3Vp-p centered around a ground. Any ideas or help appreciated. I can transformer couple the output if necessary.

    Maybe generate the basic sin wave using the rom table to create the samples for the period you want and feed this to the serial input of a multiplying DAC. For example using the LT8043 in 4 quadrant mode looks like it will be able with a couple of opamps give you a waveform centered about gnd. Currently I am generating a ramp into the DAC input and supplying a signal from an HP function generator (sin/square or triangle/sawtooth) into vref and that was to see if I could make the device control the output amplitude of the output stage, and it gives out a ramp from near 0 to vref. The waveform looks like a ramp made up of whatever is going into the vref input. Currently I am testing this in two quadrant mode with a single supply opamp. With a programable divider, you could probably make the device amplitude and offset fully programmable.

    FF
  • jmgjmg Posts: 15,183
    edited 2012-08-21 22:59
    This thread has a good example, that goes to low frequencies
    http://forums.parallax.com/showthread.php?140989-Using-counter-modules-to-control-frequency-of-sine-square-or-triangle-wave
    with a scan rate of 1.25MHz, it will output one of each of the Sine ROM values, at 152.5878Hz.
    The design Auto-adjusts how it handles Sine lookup - at higher Fo, it skips some values in the Sine ROM, and below ~152Hz, it will output the same value more than once, on some samples, which also gives more time for the DAC to average over.
    For best precision, an external DAC would be used, as the PWM/PDM DAC needs 2^N clocks to average over.
    (at that 152Hz example, and an update per scan loop, there are just 64 clocks per DAC change, so only 6 bits of Y axis precision.

    Compare that with a I2S DAC, which can give > 20 bits in Y axis, at an assumed 192KHz sample rates.

    So taking that example of 152Hz, you would drop X axis steps from 8192 to around 1263 per whole cycle, but gain a lot in Y axis, so a I2S system could expect to have better Zero-crossing precision.
    If you only want sub 100Hz a reasonably aggressive low pass, (ie not much above 100Hz ) would bring more sample-points into the averaged output.
  • TCP71TCP71 Posts: 38
    edited 2012-08-22 07:24
    Again, thanks for all the ideas! My design doesn't need a perfect sine. harmonics and distortion are ok to a certain point, as long as the frequency of the primary doesn't fluctuate. This will not be used as an audio signal, but as a frequency reference to QC the system clock on a Seismic survey record. The client simply needs a frequency stable signal to make sure there is no drift of the acquisition system's clock during a longer record (typically 30-60seconds). The actual signal could be distorted up to a square wave as the input channel into the acquisition system is actually filtered above 300hz or so. I just want to make sure I can create a time-stable, repeatable waveform using the propeller, if I clock the propeller from a known, stable 10MHz GPS sync'd clock device. The input channel of the acquisition system is a differential instrumentation opamp with 20k of input impedance. they generally request 50 or 100Hz signals be recorded on on input channel as a QC of the record. The recording system is most often this:

    http://www.sercel.com/Products/land/systems/428XL.php
  • Mark_TMark_T Posts: 1,981
    edited 2012-08-22 09:58
    Ah, not much precision needed in fact! Frequency stability for all schemes is going to depend directly on the clock. Basic DDS loop is:
    repeat
      phase += frequency
      output := sinetable [phase >> shift]
      waitcnt (time += delay)
    

    The phase variable repesents 0 .. 2pi, so the top bits index the sine table (hence the shift to get the right bits). The frequency variable is the phase increment to add every output-sample period. If you were generating 100Hz waveform using a sample-rate of 44.1kHz then the frequency variable needs to be 2^32 * 100 / 44100 = 9739155 (0.0000089 % error) and a unit change in frequency variable is about 10.3 micro Hz!!

    The output could be done with a DAC or a cog doing PWM, or whatever. You wanted 0.3V p-to-p so a resistive divider and a blocking capacitor could be used to reduce the output (you'll need to know the input impedance of the 428XL).
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-08-22 10:01
    Mark_T wrote:
    You wanted 0.3V p-to-p so a resistive divider and a blocking capacitor could be used to reduce the output.
    That would have to be a huge cap to operate down to 10 Hz. That's why I suggested the differential amp approach.

    -Phil
  • jmgjmg Posts: 15,183
    edited 2012-08-22 18:24
    TCP71 wrote: »
    Again, thanks for all the ideas! My design doesn't need a perfect sine. harmonics and distortion are ok to a certain point, as long as the frequency of the primary doesn't fluctuate. This will not be used as an audio signal, but as a frequency reference to QC the system clock on a Seismic survey record. The client simply needs a frequency stable signal to make sure there is no drift of the acquisition system's clock during a longer record (typically 30-60seconds). The actual signal could be distorted up to a square wave as the input channel into the acquisition system is actually filtered above 300hz or so. I just want to make sure I can create a time-stable, repeatable waveform using the propeller, if I clock the propeller from a known, stable 10MHz GPS sync'd clock device.

    The code linked to here, should work out of the box
    http://forums.parallax.com/showthread.php?140989-Using-counter-modules-to-control-frequency-of-sine-square-or-triangle-wave&p=1107683&viewfull=1#post1107683
    and a recorded sine wave would allow the more accurate post-processing.
    (you can also derive a distortion value using this too )

    A square wave has information only in the samples right at the edges, whilst a sine wave record can be fitted to many points.

    The loop-rate of the code above is 1.25MHz, so has 800ns time quanta, but the sine 'position', is good to 12.5ns on average (because that is the adder-rate).

    Given the average analog trigger circuit struggles to get above 15-16 bits, you should be fine.
  • Mark_TMark_T Posts: 1,981
    edited 2012-08-23 04:58
    That would have to be a huge cap to operate down to 10 Hz. That's why I suggested the differential amp approach.

    -Phil

    This is frequently done in audio, so as long as the input impedance is reasonably high, a few mF is enough.
  • TCP71TCP71 Posts: 38
    edited 2012-08-27 09:07
    So I've got something going. This puts out the waveform I need:
    CON
      _CLKMODE = xinput + pll16x
      _XINFREQ = 5_000_000 
         
    OBJ
      psg : "PropellerSignalGenerator"
     
    PUB main | i
    
      'Start "Propeller Signal Generator" and output signal on pin 10 (inverted signal on pin 11)
      psg.start(14, 15, 32) ' Sync pin = 32 = No pin
      psg.setUserWaveform(@userWaveform, 3) 
      psg.setParameters(psg#SINE, 50, 0, 0)
      psg.start(3, 4, 32) ' Sync pin = 32 = No pin
      psg.setUserWaveform(@userWaveform, 3) 
      psg.setParameters(psg#SINE,100, 0, 0)
     
     
    dat
    userWaveform  word -$7FFF, $0000, $7FFF, $4444, $1111, $2222, $3333, $4444
    

    As you can see, I'm trying to create two frequencies out of the same propeller (on different cogs simultaneously) . Is this possible? The code as above only puts out the signal on the Pin 3 and 14 no longer works. Thanks for any input.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-08-27 09:19
    You need to define two instances of psg and start them separately. This can be done with an object array, viz:
    CON
      _CLKMODE = xinput + pll16x
      _XINFREQ = 5_000_000 
         
    OBJ
      psg[2] : "PropellerSignalGenerator"
     
    PUB main | i
    
      'Start "Propeller Signal Generator" and output signal on pin 10 (inverted signal on pin 11)
      psg[0].start(14, 15, 32) ' Sync pin = 32 = No pin
      psg[0].setUserWaveform(@userWaveform, 3) 
      psg[0].setParameters(psg#SINE, 50, 0, 0)
      psg[1].start(3, 4, 32) ' Sync pin = 32 = No pin
      psg[1].setUserWaveform(@userWaveform, 3) 
      psg[1].setParameters(psg#SINE,100, 0, 0)
     
     
    dat
    userWaveform  word -$7FFF, $0000, $7FFF, $4444, $1111, $2222, $3333, $4444
    

    -Phil
  • TCP71TCP71 Posts: 38
    edited 2012-08-27 09:32
    wonderful. thank you.
Sign In or Register to comment.