Go Down

Topic: Precision resistors in the output (Read 899 times) previous topic - next topic

Trastevere

First time poster here. Hi to all!

Im reverse ingenieering one module that I love. Its a synth module. It spits audio by the D9 and D10 pins, but in a configuration that I have never seen before.

Pin D9 has a 3k9 resistor
Pin D10 has a 499k resistor

Both resistors are high precision (0.1%). The two ends of resistors are soldered together and with a 100nF cap. The other end of the cap is the audio out.

Im puzzled. Why it uses 2 precisin resistors? Why this values?

The module makes sme really cool noises, quite different from every arduino that I have listen before. I was wondering how he achieves this and why wuld be the reason f this mysterius output configuration.

Thanks for elucubrate!!
Red glooming hot chips

Trastevere

I forgot: the cpu is an atmega328p (arduino nano)
Red glooming hot chips

JohnRob

Are you sure they are not 1% values? 

There is no reason to use 0.1% resistors,  there is no reason to use 1% resistors.  The output of the Auduino is not a precision voltage and will change over a number of parameters.

If indeed they are 0.1% then to only reason is that they had them.  Same goes for 1%.

I use exclusively 1% resistors as they are not so much more expensive as to matter to me and if I actually need a 1% (vert seldom) I have them.

Please do not PM me with thread based messages.  If your thoughts are worth responding,  the group should benefit from your insight.

MorganS

It's mixing together two digital outputs in a voltage divider. This gives you 4 possible voltage levels on the output. Then the capacitor rounds off the harshest digital edges.
"The problem is in the code you didn't post."

Trastevere

#4
Dec 11, 2018, 01:23 am Last Edit: Dec 11, 2018, 01:25 am by Trastevere
It's mixing together two digital outputs in a voltage divider. This gives you 4 possible voltage levels on the output. Then the capacitor rounds off the harshest digital edges.
Yeah, that´s what I thought, he is using the 8 possible bits to achieve ... amaybe 12 bits output?

But why 499k vs 3k9?. Is there a special relationship that makes this two amounts ideal for 12bits? Or is simulating 16bits?

And why 0.1% (as listed in his BOM) precision ones?. He offers partial kits with only this 2 resistors plus the programmed atmega, so he thinks that´s crucially important... Im puzzled and there´s some explanation t that.

Thanks for the responses, guys ;)
Red glooming hot chips

JohnRob


Quote
It's mixing together two digital outputs in a voltage divider. This gives you 4 possible voltage levels on the output
Keep in mind the outputs could each be PWM, and likely PWMs a different and or varying frequencies.


I'm very sure 0.1% resistors are not required.  As for the BOM perhaps its a typo, or he/she had 0.1% resistors and wanted to dissuade folks from brewing their own.



Please do not PM me with thread based messages.  If your thoughts are worth responding,  the group should benefit from your insight.

Grumpy_Mike

#6
Dec 11, 2018, 06:18 am Last Edit: Dec 11, 2018, 06:30 am by Grumpy_Mike
With only very sketchy information given I would suggest that he is trying to achieve a 16 bit analogue output by mixing two PWM outputs together, one being for the upper 8 bits and the other for the lower 8 bits. That would explain why the high precision resistors are needed.

Quote
The two ends of resistors are soldered together and with a 100nF cap. The other end of the cap is the audio out.
That is normal and is known as AC coupling, it removes any DC component from the audio.

Quote
Why this values?
499 / 3.9 = 499 / 3.9 = 127.948717949
which is very nearly 128 - a magic number when it comes to powers of two, representing 7 bits. So in this case it looks like he is trying to recreate a 14 bit analogue output.

Quote
And why 0.1% (as listed in his BOM) precision ones?
If it is not precise you do not get monotonicity.

TomGeorge

#7
Dec 11, 2018, 06:32 am Last Edit: Dec 11, 2018, 06:33 am by TomGeorge
Hi,
Have you measured the resistors, or are the values written on them, or the colour code?

I agree with @Grumpy_Mike, possibly a complex way of getting smooth analog conversion.

Does the module have any identifying numbers or model/make names?

Thanks.. Tom.. :)
Everything runs on smoke, let the smoke out, it stops running....

MarkT

#8
Dec 11, 2018, 12:09 pm Last Edit: Dec 11, 2018, 12:10 pm by MarkT
This is a very standard way to get high-precision output from two PWM pins, 0.1% resistors are
used as they are readily available (even though 0.5% would be adequate).

The ratio is about 127:1, if you allow for the approx 40 ohm output impedance of the µC
pins:  499040 / 3940 = 126.6

I suspect that's its possible to get a better resistor ratio closer to 128:1 with E48 values,
allowing for the output impedance correctly...

The PWM will probably be at 63kHz, using phase-correct 7 bit counting (phase correct has
lower harmonic distortion), ie count 0,1,2,...,126,127,126,...1,0

This is relatively easy to filter out from the audio band, whereas 8 bit phase-correct would be
harder to do.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Trastevere

#9
Dec 11, 2018, 04:04 pm Last Edit: Dec 11, 2018, 04:19 pm by Trastevere
Yeah, Im positive is exactly that. So he is doing a 14bit audio out dac with 2 resis and a cap. I love the idea... he is a mad scientist for sure.

By the way, the resistors are in the BOM, is not that I have measured it ;) The module is a Karplus-Strong by Maestro Meng Qi. The source code is closed and Im inspired to do a open source version of it... But I must confess Im quite a newbie and even getting it working in 8bits is a challenge, so how he is getting to d the multiplications in the audio loop to get 14bits of DSP in an atmega328p  makes the whole thing even more genial

So anyone knows how to set the audio registers to get it running at 63Khz using D9 and D10 as outputs? (The audio registers part, after 2 weeks trying to understand it keeps been a fucking alien sudoku)

Thank you so much for your responses and insight, guys!!
Red glooming hot chips

Grumpy_Mike

Quote
The source code is closed and Im inspired to do a open source version of it
Lots of open source implementations. There is even one in by book:-
Code downloadable here http://www.apress.com/9781484217207
It is in Chapter 17 as Listing 17-2 for the Uno, Listing 17-3 for the Due and Listing 17-4 for a polyphonic version for the Due.
Also look at the Teensy they have example code of this as well.

JohnRob

@MarkT

I've not done any audio utilizing microcontrollers so I can't say from experience, but do you really think 0.5% resistors will make any difference?  Especially coming from an Arduino digital output.  I would have though .... maybe if there were some kind of buffer on the output.


Please do not PM me with thread based messages.  If your thoughts are worth responding,  the group should benefit from your insight.

MarkT

#12
Dec 11, 2018, 10:23 pm Last Edit: Dec 11, 2018, 10:26 pm by MarkT
Since the ratio between outputs is 2^7, you need the ratios to be accurate to better than one-part in 128
for good accuracy in the steps, remember this is just some passive resistors combining signals from
the supply rails - keep the supply rails clean and decoupled, there's no reason not to get towards 14 bit
accuracy.

Its helped by the ATmega microcontrollers being relatively low power and having low impedance
output transistors (in particular the variation of the impedance between pins will be measured as a few
ohms).

Something to note is that higher accuracy resistors have lower variation with temperature (the accuracy
is measured over some temperature range, like 0..70C).

There are other ways to get more accuracy from PWM without needing to combine outputs, by
moving the quantization noise up in frequency (the technique is called noise-shaping).
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Trastevere

So, I have this working in nano:

Code: [Select]
/*

  -= Karplusduino =-

  Pot0 = PITCH
  Pot1 = lowpass filter
  Pot2 = unused ATM

  PWM audio out - PIN 3

*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#define SIZE 1024
#define OFFSET 128

int out = 0;
int lastDelaySample = 0;
int currentDelaySample = 0;
uint8_t delaymem[SIZE];
uint8_t locat = 0;
uint8_t bound = SIZE;
int accum = 0;
int cutoff = 0;
int pot2 = 0;
static const unsigned long REFRESH_INTERVAL = 500; // ms
static unsigned long lastRefreshTime = 0;
bool isDebuggin = true;

int pitch = 0;



#define PWM_PIN        3
#define CUTTOF_PIN    1
#define TRIGGER_PIN   5
#define PWM_VALUE_DESTINATION     OCR2B
#define PWM_INTERRUPT TIMER2_OVF_vect

void initializeTimer() {

  TCCR2A = _BV(COM2B1) | _BV(WGM20);
  TCCR2B = _BV(CS20);
  TIMSK2 = _BV(TOIE2);
  //OCR2B = 777;

  pinMode(PWM_PIN, OUTPUT);
  pinMode(TRIGGER_PIN, INPUT_PULLUP);

}


SIGNAL(PWM_INTERRUPT)
{

  PWM_VALUE_DESTINATION = out;
 // OCR2B = pot2; //this should change speed
  delaymem[locat++] = out;

  if (locat >= bound) locat = 0;

  currentDelaySample = delaymem[locat];

  //old filtro
  out = accum >> cutoff;
  accum = accum - out + ((lastDelaySample >> 1) + (currentDelaySample >> 1));

  lastDelaySample = currentDelaySample;

}

void setup() {
  if (isDebuggin) {
    Serial.begin(9600);
  }
  initializeTimer();

}

void loop() {

  pitch = map(analogRead(0), 0, 1023, -125, 127);
  pot2 = map(analogRead(2), 0, 1023, 1, 12000);
   cutoff=  map(analogRead(CUTTOF_PIN), 0, 1023, 0, 5);
  if (digitalRead(TRIGGER_PIN) == LOW) {
    noiseBurst();
  }

  bound = OFFSET + pitch;

  if (isDebuggin) {

    if (millis() - lastRefreshTime >= REFRESH_INTERVAL)
    {
      lastRefreshTime += REFRESH_INTERVAL;
      Serial.print("pot 0 pitch: "); Serial.println(pitch);
      Serial.print("pot 1 lowpass: "); Serial.println(cutoff);
      Serial.print("pot 2: pot2 "); Serial.println(pot2);
    }
  }
}

void noiseBurst() {
  //int halfSize = SIZE / 2;
 
  for (int i = 0; i < SIZE; i++) {
    //delaymem[i] =  delaymem[i]-(128+random(pot2));
    //divide by modindex
    //saw
    delaymem[i] =  i;
    //noise
    // delaymem[i] =  random(255);
    //square
    /*
      if (i > halfSize) {
      delaymem[i] = 0;
      } else {
      delaymem[i] = 255;
      }*/

    if (delaymem[i] > 255) {
      delaymem[i] = 255;
    }
    if (delaymem[i] < 0) {
      delaymem[i] = 0;
    }
  }
}


It does a basic karplus, just trigger, pitch and cutoff frequency.

I would like to change the speed of the timers so I can get another parameter to play with. Currently is running at at unknown (to me) speed. I have tried to change the  OCR2B register like this:

OCR2B = pot2;

But it does nothing. What register(s) do change the execution speed?
Red glooming hot chips

MarkT

The datasheet for the processor will desribe all the fields in the control registers, TCCR2A/TCCR2B
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Go Up