Friday, July 30, 2010

Making an Optimal Log Pot


After taking a look at the famed "The Secrete Life of Pots" again, I realized that it might be useful for me to make my own blend pot.  I have discovered that the blend pot I have unfortunately does not cross the streams the way it should.  At the center detent, both pots are at full volume.  Deviating in either direction lowers the volume of one of the pots.  So this means that I will be much louder in the middle than at either of the extremes, which is undesirable.

The author mentions that it is possible to get arbitrarily close to a logarithmic pot, so I decided to bust out Matlab and see if that was true.


First I verified that the calculations were indeed correct.  Actually I found a small typo in them.  He uses two different definitions of the b variable that are reciprocals of each other.  On the graph, the numbers say "b=0,1,2,3,4,5,6" when, going by the previous calculations, "b=1/0, 1/1, 1/2, 1/3, 1/4, 1/6" to produce the graph shown.  The actual equations were correct, both the resistor-based and the ratio-based.

Secondly, what should a log pot actually look like?  Incidentally, the plot is actually an exponential 10^x graph.  The plot will look like a line on a semi-log plot.  But which part of this plot should we choose?  Each section looks different, and wider range will have a different curve than a smaller one.  After reading the Wikipedia article on sound pressure, I decided to pick the range from 0-60db (10^(0...60/20) as my target range.  This represents the range from silent to coming close to hearing damage.  And that's what we want right? :)

After that, I used the "fminunc" (for function minimize unconstrained) function in Matlab to minimize the difference between the chosen log plot and the attempt to copy it.  The independent variable was b.


It is not quite true that you can get arbitrarily close to the log pot, at least not with this choice for the log pot curve.  I used two methods for the error calculation: least sum of absolute value and least sum of squares.  Here are the results.

Running the minimization on both methods produced values of
b = 0.0574 for the least sum of absolute value of errors
b = 0.0709 for the least sum of squared errors

So the resistor at the wiper should be 5.74% or 7.09% of the total resistance of the pot, depending on which method of optimisation you choose.  

Here are the plots for those values.


As you can see, the plots are fairly close, but by no means perfect.  To the ear, you probably couldn't tell very much difference. 

As mentioned in TSLoP, using this method severely drops the resistance of the load to the pickup.  Also it changes the resistance depending on wiper position.  So you probably would want to put an opamp buffer or something in between the pickup and the fake log pot.

The drop in resistance is by a factor of 0.0543 for the ABS result and 0.0662 for the LSQ result in the worst position (1/(1+1/b) from TSLoP).  The worst position is full volume, since there will be no top resistor in series with the parallel pair. So we're talking about turning a 500K pot into 27K or 33K at the worst wiper position.  Still easily drive from an opamp, but pretty nasty for a pickup.

I'm considering adding a couple of opamps to the circuit so that I can take a dual-ganged linear pot and turn it into a dual log pot where one is the opposite of the other.  That's hard to explain.  Just look at the graph.

That way the volume should remain pretty constant as you sweep from one side to the other.

Now if only I could find one with a center detent...

Code used for calculating follows...

function G = logpot(b) % logpot accepts one row matrix "b" that contains % all values of "b" for which a dataset should be generated % It returns the "ideal log gain" followed by the generated % datasets for the b values provided. % setup pot position values a = repmat(linspace(0,1,50)', size(b), 1); % replicate b to match a's height b = repmat(b, 50, 1); % do the math G = 1./ ((ones(size(a))-a)./a + (ones(size(a))-a)./b + ones(size(b))); % create our "ideal log gain" (0-60dB) glog = logspace(0,60/20,50); glog = glog ./ max(glog); % concatenate "ideal log gain" with the generated datasets G = [ glog' G ]; ---------------------------------------- The command to do the optimisation is fminunc(@myfun, 1/6) This is the function used in the optimisation to calculate total error. function f = myfun(b) % function is % 1 %--------------------- % _1-a_ + _1-a_ + 1 % b a % precalculated to make things faster. % a = linspace(0,1,50); % a1 = 1-a % a2 = (1-a)/a a1 =[ 1.0000 0.9796 0.9592 0.9388 0.9184 0.8980 0.8776 0.8571 0.8367 0.8163 0.7959 0.7755 0.7551 0.7347 0.7143 0.6939 0.6735 0.6531 0.6327 0.6122 0.5918 0.5714 0.5510 0.5306 0.5102 0.4898 0.4694 0.4490 0.4286 0.4082 0.3878 0.3673 0.3469 0.3265 0.3061 0.2857 0.2653 0.2449 0.2245 0.2041 0.1837 0.1633 0.1429 0.1224 0.1020 0.0816 0.0612 0.0408 0.0204 0 ]; a2 =[ Inf 49.0004 24.5004 16.3337 12.2504 9.8004 8.1671 6.9997 6.1248 5.4443 4.8999 4.4545 4.0833 3.7693 3.5001 3.2667 3.0626 2.8825 2.7224 2.5788 2.4499 2.3333 2.2272 2.1304 2.0417 1.9600 1.8846 1.8149 1.7500 1.6897 1.6334 1.5806 1.5312 1.4848 1.4411 1.4000 1.3611 1.3243 1.2895 1.2564 1.2250 1.1952 1.1667 1.1395 1.1136 1.0889 1.0652 1.0425 1.0208 1.0000 ]; % glog is a 0-60 db curve normalized to 0-1 % glog = logspace(0,60/20,50); glog = glog ./ max(glog) glog =[ 0.0010 0.0012 0.0013 0.0015 0.0018 0.0020 0.0023 0.0027 0.0031 0.0036 0.0041 0.0047 0.0054 0.0063 0.0072 0.0083 0.0095 0.0110 0.0126 0.0146 0.0168 0.0193 0.0222 0.0256 0.0295 0.0339 0.0391 0.0450 0.0518 0.0596 0.0687 0.0791 0.0910 0.1048 0.1207 0.1389 0.1600 0.1842 0.2121 0.2442 0.2812 0.3237 0.3728 0.4292 0.4942 0.5690 0.6551 0.7543 0.8685 1.0000 ]; %f = 1./ ( a1./b + a2 ); f1 = 1./ ( a1./b + a2 ) - glog; f = sum(abs(f1)); %f = sum(f1.^2); ---------------------------------------- This is the code I used to generate the main results graph plot(100*linspace(0,1,50)', 100*logpot([0.0574 0.0709])); xlabel('Wiper Position (%)'); ylabel('Gain (%)'); legend('Real Log 0-60 dB', 'Simulated b=0.0574 (Least ABS)', 'Simulated b=0.0709 (Least Squares)', 'Location', 'NorthWest'); title('Simulated Log Pots');

Thanks for reading,

Sunday, July 18, 2010

Wiring Started on Guitar!

Well after being extremely busy with work, and taking on a couple of other projects, I am finally getting back to the guitar.  It's been sitting in pieces in my room for over a month now.

Today the guitar finally has reclaimed its original shape!  I've wired the original pickups back into the guitar with the Series/Parallel/Coil Cut switch in place.  The result is a 3 wire + shield output that has signal ground, neck out, bridge out, and shield.  Soon I will make a prototype of the active circuit on the breadboard again.  I started it a while back but didn't finish it. 

Unfortunately, the sound is still limited by the pickups themselves.  I will have to go for a higher quality pickup (like the Seymour Duncan Seth Lover SH-55's mentioned before) before I get a really great sound.  That being said, I do hear a substantial difference from before. 

Right now, the wires are plugged straight into the amp itself, so the impedance presented to the pickups is probably on the order of 1M.  The highs are coming out nicely in all modes.  The neck pickup sounds great, but the bridge is a little harsh. 

Switching between Series, Parallel, and Coil Cut produces a noticable difference in tone.  I am very happy to have the guitar in a playable state again.  I will post pictures and the new schematics later.

Thanks for reading,