0 Members and 1 Guest are viewing this topic.

#### BrianHG

• Super Contributor
• Posts: 7294
• Country:
« Reply #75 on: October 08, 2022, 06:33:27 pm »
One note, if you want a digital attenuation, you should not be using fixed resistors with matched R2R values.  It is a waste as proper logarithmic constant impedance versions can be done with the right resistors and wiring.  Also, a proper 6 bit logarithmic attenuation, IE: set to a true 1.5db per lsb step, would offer the equivilant to a 16bit linear digital resistor.

Spread sheets/calculators exist for these resistor values.

Ignore this post if you just need a linear programmable resistor instead of a programmable attenuation.
« Last Edit: October 09, 2022, 12:11:03 am by BrianHG »

#### Nominal Animal

• Super Contributor
• Posts: 5031
• Country:
« Reply #76 on: October 09, 2022, 12:39:13 am »
Here's an idea for the series configuration, using n-MOSFETs.  I don't know if this works, but perhaps the experienced members here could tell.  I did simulate it, and it seems to work.

Let's say the series resistor set is between Vin and Vout, with Vin > Vout.
You use an n-channel power MOSFET with low Rds(on) to short out each resistor.  Each will have a high-value resistor (say, 1M) between gate and source, so by default they are non-conducting.  (The idea is that we just need to pump some current into the gate to short out each resistor.)

Microcontroller GND is at Vin, and Vcc at Vin+4V.  On each GPIO output, you have the gate of a P-channel MOSFET (like DMP610DL that can withstand (Vout-Vin)-4V drain-source and gate-source voltages, with low enough gate threshold voltage so it can be switched at -4V; the currents are tiny).  Their sources are connected to Vcc, and drains are connected (via current-limiting resistors) to the gates of the n-channel MOSFETs.

When the GPIO is high or tri-state/floating, the p-MOSFET gate and source are at the same potential, so it does not conduct.  Then, the n-MOSFET gate also has its gate and source at the same potential, so it does not conduct either, and the resistor is enabled (not shorted).

When the GPIO is low, the p-MOSFET has Vgs=-4V, so it conducts.  This lifts the n-MOSFET gate to at least 4V higher than its source (more, if the voltage has dropped in the preceding resistors).
« Last Edit: October 09, 2022, 12:47:00 am by Nominal Animal »

#### eslavko

• Contributor
• Posts: 29
• Country:
« Reply #77 on: October 09, 2022, 06:05:39 am »
Relay are still to bulky and all optocouplers suggested are to slow! Switching time in 5ms! I need to change resistance inside 100us window when PWM/PDM signal is in low state.

And to be more clear.
We have around 10 devices and I want just to upgrade them. The populated PCB cost around $150. The device as is have 11 bits in one leg and 13 bits in other leg (can simulate two resistors). But in present state have only one bit on each leg ON. So one leg can have 11 values, and other one 13 values. If I manage to make parallel resistor to cover required range the update is just firmware change and resistors change on PCB. To make both legs with 12 bits I need to cut one trace and make one bridge. Using serial resistors, relays optocouplers it's near impossible to use existing PCB. So is it possible to get required range from 12 bits? #### Zero999 • Super Contributor • Posts: 18151 • Country: • 0999 ##### Re: Digital adjustable resistor « Reply #78 on: October 09, 2022, 06:02:54 pm » Relay are still to bulky and all optocouplers suggested are to slow! Switching time in 5ms! I need to change resistance inside 100us window when PWM/PDM signal is in low state. And to be more clear. We have around 10 devices and I want just to upgrade them. The populated PCB cost around$150. The device as is have 11 bits in one leg and 13 bits in other leg (can simulate two resistors). But in present state have only one bit on each leg ON. So one leg can have 11 values, and other one 13 values.
If I manage to make parallel resistor to cover required range the update is just firmware change and resistors change on PCB. To make both legs with 12 bits I need to cut one trace and make one bridge. Using serial resistors, relays optocouplers it's near impossible to use existing PCB.
So is it possible to get required range from 12 bits?

Those relays are not bulky. They're tiny compared to the size of resistors required to dissipated the required power.

You should have stated the speed in first place. It's possible to get faster isolated gate drivers, but it's going to be very difficult to make something that fast, because the resistors form a RC time constants with the parasitic capacitances of the MOSFETs.

#### Nominal Animal

• Super Contributor
• Posts: 5031
• Country:
« Reply #79 on: October 09, 2022, 07:19:36 pm »
So is it possible to get required range from 12 bits?
The math says, when using selectable resistors in parallel, "all resistances in the upper half of your resistance range must be provided by individual resistors".

If the maximum resistance is 3000 Ohms, and you use 12 resistors linearly/evenly distributed between 1500 and 3000, your resolution at the upper end is 1500/(12-1) ≃ 136 Ohms.  The minimum resistance is then 179 Ohms, with 190 to 642 Ohms covered with better than 1 Ohm resolution.

If the maximum resistance is 4500 Ohms, and you use 10 resistors linearly/evenly distributed between 2250 and 4500, your resolution at the upper end is 2250/(10-1) = 250 Ohms.  The minimum resistance is then 322 Ohms, with the dense coverage from 346 Ohms to 1000 Ohms or so.

To cover the bottom end of your range, you'd need additional resistors, which just increases the step size at the upper half of the range.

In real life, we do not usually need a linear distribution of resistors, but an 1/N distribution (because for example I=U/R).  To see what kind of set of parallel resistances you can make, I suggest you start with the highest resistance you need, then the next highest, and so on.  The following simple Python program will tell you all the possible parallel combinations, in sorted order:
Code: [Select]
#!/usr/bin/python3
# -*- coding: utf-8 -*-

if __name__ == '__main__':
from sys import stdout, stderr, argv

if len(argv) < 3:
stderr.write('\n')
stderr.write('Usage: %s [ -h | --help ]\n' % argv[0])
stderr.write('       %s RESISTANCES...\n' % argv[0])
stderr.write('\n')
exit(0)

R = [ float(argv[k]) for k in range(1, len(argv)) ]
N = len(R)

R.sort()
value = []
for k in range(1, 2**N):
invsum = 0.0
for n in range(0, N):
if (k & (2**n)) > 0:
invsum += 1.0 / R[n]
value.append(1.0/invsum)
value.sort()

stdout.write('Resistors:')
for n in range(0, N):
stdout.write(' %.6f' % R[n])

stdout.write('\nPossible parallel resistances:\n')

for k in range(0, 2**N - 1):
stdout.write("%.9f\n" % value[k])
Running
python3 parallel.py 4500 4200 3950 3750 3600
tells you that they can be combined to the following parallel combinations:
Code: [Select]
794.959030140
965.526606786
980.554406289
995.260663507
1008.817269687
1020.253372145
1253.747134544
1277.890466531
1300.326583932
1304.347826087
1319.389215842
1327.731092437
1347.611827142
1354.838709677
1375.545851528
1401.577020558
1836.734693878
1883.443708609
1923.701298701
1938.461538462
1981.132075472
2000.000000000
2035.582822086
2045.454545455
2103.550295858
2172.413793103
3600.000000000
3750.000000000
3950.000000000
4200.000000000
4500.000000000
Notice the huge gap between 2172 and 3600?  That is because as the math says, "all resistances in the upper half of your resistance range must be provided by individual resistors".  Since I didn't have any between 2250 and 3600, there's a huge gap in there.
« Last Edit: October 09, 2022, 07:21:45 pm by Nominal Animal »

#### eslavko

• Contributor
• Posts: 29
• Country:
« Reply #80 on: October 10, 2022, 08:30:03 am »
Code: [Select]
#!/usr/bin/python3
# -*- coding: utf-8 -*-

if __name__ == '__main__':
from sys import stdout, stderr, argv

if len(argv) < 3:
stderr.write('\n')
stderr.write('Usage: %s [ -h | --help ]\n' % argv[0])
stderr.write('       %s RESISTANCES...\n' % argv[0])
stderr.write('\n')
exit(0)

R = [ float(argv[k]) for k in range(1, len(argv)) ]
N = len(R)

R.sort()
value = []
for k in range(1, 2**N):
invsum = 0.0
for n in range(0, N):
if (k & (2**n)) > 0:
invsum += 1.0 / R[n]
value.append(1.0/invsum)
value.sort()

stdout.write('Resistors:')
for n in range(0, N):
stdout.write(' %.6f' % R[n])

stdout.write('\nPossible parallel resistances:\n')

for k in range(0, 2**N - 1):
stdout.write("%.9f\n" % value[k])

I already do near same python script using plot to show result.
When I playing with numbers I got interesting results.
Based on your writing the best I can get is with linear distribution betwen 1 and 0.5.
I do it like that:

Code: [Select]
res=[]
stp=1500/12
for i in range(12):
res.append(stp*i+1500)

The result is 8% difference from 174.968535 to 2875.000000, with 12 bits
[attachimg=1]

With binary weightrd resistors (each one is double the size of previous) like:
Code: [Select]
res=[150]
for i in range(11):
res.append(res[-1]*2)

I got 0.93% difference from 75.018315 to 2982.524272, with 12 bits.
[attachimg=2]

If I didn't make some mistake then seems that binary values will be better.
(I did mistake in 1st version of my script and based of bad result that thread is started at all)

#### Nominal Animal

• Super Contributor
• Posts: 5031
• Country:
« Reply #81 on: October 10, 2022, 09:44:46 pm »
Like I said, the distribution of resistances in the upper half of your resistance range is the key, when the selectable resistances are in parallel.

If you want a 1/N distribution of resistances, then power of two sequence is likely optimal (each resistance double the previous one).
If you want a linear distribution of resistances, then linear sequence is optimal.

In my own circuits –– I'm a hobbyist who interfaces all kinds of sensor and display circuits to microcontrollers and single board computers –– I tend to need either precision resistors under 100 Ω (and current shunt resistors under 1 Ω), or larger resistors picked from one of the E series of preferred numbers.  So even a bumblefuck hobbyist like myself has quite different needs for resistors.

You seem to be undecided on what kind of distribution of resistances your switchable box needs; only that 50 Ω to 3000 Ω or maybe 4500 Ω would be useful.
Yet, it is exactly the resistance distribution you desire, especially in the upper half of the resistance range (so 1500 Ω to 3000 Ω, or 2250 Ω to 4500 Ω), that is the determining factor here.

Logarithmic resistance ranges are a bit more complicated than either 1/N or linear, as discussed above.  Considering the 50 Ω to 4500 Ω range:

For example, in the E6 series, the desired resistances would be 47, 68, 100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700.
From the E6, only the three highest ones (2200, 3300, 4700) are needed for the upper half of the resistance range.

In the E12 series, the desired resistances would be 47, 56, 68, 82, 100, 120, 150, 180, 220, 270, 330, 390, 470, 560, 680, 820, 1000, 1200, 1500, 1800, 2200, 2700, 3300, 3900, 4700.
Only the four or five highest ones ([2200], 2700, 3300, 3900, 4700) are needed for the upper half of the resistance range –– without 2200, the closest value is 2131.4=2200-3.12%.

In the E24 series, the resistances would be 47, 51, 56, 62, 68, 75, 82, 91, 100, 110, 120, 130, 150, 160, 180, 200, 220, 240, 270, 300, 330, 360, 390, 430, 470, 510, 560, 620, 680, 750, 820, 910, 1000, 1100, 1200, 1300, 1500, 1600, 1800, 2000, 2200, 2400, 2700, 3000, 3300, 3600, 3900, 4300, 4700.
Only the eight or nine highest ones ([2200], 2400, 2700, 3000, 3300, 3600, 3900, 4300, 4700) are needed for the upper half of the resistance range.  Again, without 2200, the closest values the higher ones combine to are 2200+2.1% and 2200-3.12%.

I am not aware of any formula that directly generates the lower range resistances that (along with the fixed upper range resistors) yields the desired values, but a brute-force search ought to find good candidates that can be analysed to minimise relative error in the resistances.

#### eslavko

• Contributor
• Posts: 29
• Country:
« Reply #82 on: October 11, 2022, 08:21:13 am »
I am not aware of any formula that directly generates the lower range resistances that (along with the fixed upper range resistors) yields the desired values, but a brute-force search ought to find good candidates that can be analysed to minimise relative error in the resistances.

As I write it's not adjustable resistor box but testing/callibrating device. Until now some parameters are adjusted automatically and other manual, and I wish to make all adjustment automated. For that I need specific resistor ranges (and there can be some gaps present). Now with working "python calculator" I can see results quick and can do some changes in resistor sets to get desired results using like brute force approach. At least in this thread I learned that in high range whatever I do the step will be coarser.

Thanks for support and all ideas.

Smf