565 lines
11 KiB
Text
565 lines
11 KiB
Text
<html>
|
|
<head>
|
|
<title>Type 3 Designer</title>
|
|
<script type="text/javascript">
|
|
|
|
/* support Opera and others that don't have Array foreach.
|
|
* These are not ECMA compliant. */
|
|
if (! Array.prototype.forEach) {
|
|
Array.prototype.forEach = function(f) {
|
|
for (var i = 0; i < this.length; i ++)
|
|
f(this[i]);
|
|
};
|
|
}
|
|
if (! Array.prototype.map) {
|
|
Array.prototype.map = function(f) {
|
|
var result = [];
|
|
for (var i = 0; i < this.length; i ++)
|
|
result.push(f(this[i]));
|
|
return result;
|
|
};
|
|
}
|
|
|
|
/* "jQuery". Maybe I start to use it for real later on. */
|
|
var $ = function(selector) {
|
|
if (selector.match(/^#/) != null) {
|
|
return document.getElementById(selector.replace("#", ""));
|
|
}
|
|
return null;
|
|
};
|
|
|
|
var cap = 470e-12;
|
|
var ymin = 140;
|
|
var ymax = 24000;
|
|
var cwidth = 512;
|
|
var cheight = 512;
|
|
|
|
function parse_type1(text) {
|
|
var list = [];
|
|
text.split(/\x0d?\x0a/).forEach(function(line) {
|
|
var res = line.match(/^\s*(\d+)\s+(\d+)\s*$/);
|
|
if (res == null)
|
|
return;
|
|
|
|
list.push([parseFloat(res[1]), parseFloat(res[2])])
|
|
});
|
|
return list;
|
|
}
|
|
|
|
function make_type3_list(vals) {
|
|
var approximate_dac = function(x) {
|
|
var value = 0;
|
|
var bit = 1;
|
|
var weight = 1;
|
|
var dir = 2 * vals.dac;
|
|
for (var i = 0; i < 11; i ++) {
|
|
if (x & bit)
|
|
value += weight;
|
|
bit <<= 1;
|
|
weight *= dir;
|
|
}
|
|
return value / (weight / vals.dac / vals.dac) * (1 << 11);
|
|
};
|
|
|
|
var list = [];
|
|
for (var x = 0; x < 2048; x ++) {
|
|
var kink = approximate_dac(x);
|
|
var dynamic = vals.minimumfetresistance + vals.offset / Math.pow(vals.steepness, kink);
|
|
var resistance = (vals.baseresistance * dynamic) / (vals.baseresistance + dynamic);
|
|
list.push([x, 1 / (2 * Math.PI * cap * resistance)])
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
function viewtransform(coords) {
|
|
var logscale = function(x) {
|
|
if (x < 1)
|
|
return 0;
|
|
return Math.log(x) / Math.log(10);
|
|
}
|
|
|
|
var x = coords[0];
|
|
var y = logscale(coords[1]);
|
|
|
|
y -= logscale(ymin);
|
|
y /= (logscale(ymax) - logscale(ymin)) / 512;
|
|
|
|
return [x / 4., 512 - y];
|
|
}
|
|
|
|
function clear_area(ctx) {
|
|
ctx.fillStyle = 'rgba(255, 255, 255, 255)';
|
|
ctx.fillRect(0, 0, cwidth, cheight);
|
|
}
|
|
|
|
function make_grid(ctx) {
|
|
ctx.strokeStyle = 'rgba(0, 0, 0, 255)';
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
ctx.lineTo(cwidth, 0);
|
|
ctx.lineTo(cwidth, cheight);
|
|
ctx.lineTo(0, cheight);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
|
|
for (var x = 0; x < 2048; x += 128) {
|
|
ctx.strokeStyle = x % 512 == 0 ? 'rgba(32, 32, 32, 128)' : 'rgba(128, 128, 128, 128)';
|
|
|
|
var coord1 = viewtransform([x, ymin]);
|
|
var coord2 = viewtransform([x, ymax]);
|
|
ctx.beginPath();
|
|
ctx.moveTo(Math.floor(coord1[0]), coord1[1]);
|
|
ctx.lineTo(Math.floor(coord2[0]), coord2[1]);
|
|
ctx.stroke();
|
|
}
|
|
|
|
for (var y = 0; y < ymax; y += 100) {
|
|
var color = 'rgba(192, 192, 192, 128)';
|
|
if (y == 1000 || y == 10000)
|
|
color = 'rgba(0, 0, 0, 128)';
|
|
ctx.strokeStyle = color;
|
|
if (y > 1000 && y % 1000 != 0)
|
|
continue;
|
|
if (y > 10000 && y % 10000 != 0)
|
|
continue;
|
|
var coord1 = viewtransform([0, y]);
|
|
var coord2 = viewtransform([2048, y]);
|
|
ctx.beginPath();
|
|
ctx.moveTo(coord1[0], Math.floor(coord1[1] + 0.5));
|
|
ctx.lineTo(coord2[0], Math.floor(coord2[1] + 0.5));
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
|
|
function draw_lines(ctx, list) {
|
|
if (list.length < 2)
|
|
return;
|
|
|
|
var coords = viewtransform(list[0]);
|
|
ctx.beginPath();
|
|
ctx.moveTo(coords[0], coords[1]);
|
|
for (var i = 1; i < list.length; i ++) {
|
|
coords = viewtransform(list[i]);
|
|
ctx.lineTo(coords[0], coords[1]);
|
|
}
|
|
ctx.stroke();
|
|
}
|
|
|
|
function update_view() {
|
|
var canvas = $('#renderarea');
|
|
var ctx = canvas.getContext("2d");
|
|
clear_area(ctx);
|
|
make_grid(ctx);
|
|
|
|
var list1 = parse_type1($('#type1def').value);
|
|
ctx.strokeStyle = 'rgba(255, 0, 0, 255)';
|
|
draw_lines(ctx, list1);
|
|
|
|
ctx.strokeStyle = 'rgba(255, 128, 128, 255)';
|
|
draw_lines(ctx, list1.map(function(x) { return [x[0], x[1]*1.1]; }));
|
|
draw_lines(ctx, list1.map(function(x) { return [x[0], x[1]/1.1]; }));
|
|
|
|
var vals = {};
|
|
['baseresistance', 'offset', 'steepness', 'minimumfetresistance', 'dac'].forEach(function(x) {
|
|
vals[x] = parseFloat($("#" + x).value);
|
|
});
|
|
|
|
var list2 = make_type3_list(vals);
|
|
ctx.strokeStyle = 'rgba(0, 255, 0, 255)';
|
|
draw_lines(ctx, list2);
|
|
}
|
|
|
|
function optimize() {
|
|
var list1 = parse_type1($('#type1def').value);
|
|
for (var i = 0; i < list1.length; i ++) {
|
|
len = i;
|
|
/* mistrust fits for > 20 kHz */
|
|
if (list1[i][0] > 20000)
|
|
break;
|
|
}
|
|
|
|
var scoring = function(list2) {
|
|
var j = 0;
|
|
var score = 0;
|
|
for (var i = 0; i < len; i ++) {
|
|
/* find corresponding spot on calculated type3 */
|
|
while (list2[j][0] < list1[i][0]) {
|
|
j ++;
|
|
}
|
|
var diff = Math.log(list1[i][1]) - Math.log(list2[j][1]);
|
|
score += diff * diff;
|
|
}
|
|
return score;
|
|
};
|
|
|
|
var bestvals = {};
|
|
['baseresistance', 'offset', 'steepness', 'minimumfetresistance', 'dac'].forEach(function(x) {
|
|
bestvals[x] = parseFloat($("#" + x).value);
|
|
});
|
|
|
|
var bestscore = scoring(make_type3_list(bestvals));
|
|
|
|
var i = 250;
|
|
while (i --) {
|
|
var tryvals = {};
|
|
var changed = false;
|
|
for (var key in bestvals) {
|
|
if (Math.random(1) > 0.5) {
|
|
tryvals[key] = bestvals[key] * (0.95 + Math.random(1) * 0.1);
|
|
changed = true;
|
|
} else {
|
|
tryvals[key] = bestvals[key];
|
|
}
|
|
}
|
|
|
|
var tryscore = scoring(make_type3_list(tryvals));
|
|
if (tryscore < bestscore) {
|
|
bestvals = tryvals;
|
|
bestscore = tryscore;
|
|
|
|
for (var key in bestvals) {
|
|
$('#' + key).value = bestvals[key];
|
|
}
|
|
update_view();
|
|
}
|
|
}
|
|
}
|
|
|
|
onload = function() {
|
|
['type1def', 'baseresistance', 'offset', 'steepness', 'minimumfetresistance', 'dac'
|
|
].forEach(function(x) {
|
|
$("#" + x).onchange = update_view;
|
|
});
|
|
$('#theform').onsubmit = function() {
|
|
return false;
|
|
};
|
|
$('#type1defreset').onclick = function() {
|
|
$('#type1def').value = '';
|
|
update_view();
|
|
};
|
|
$('#optimize').onclick = optimize;
|
|
|
|
update_view();
|
|
};
|
|
|
|
</script>
|
|
</head>
|
|
<body>
|
|
|
|
<h1>Type 3 designer (for Firefox and compatibles)</h1>
|
|
<p>You can use this program to approximate type 1 curves as type 3 curves.
|
|
Copypaste your type 1 definitions into the textarea below. The format is
|
|
simply two values on each line as in "50 1234" which means CF=50 gives 1234 Hz.
|
|
Then tune the type 3 params until a fit is obtained.
|
|
</p>
|
|
|
|
<p>Usually, the type3 equation is not a perfect fit to measured curves.
|
|
Firstly, the chip itself has nonlinear filtering effects that tend to
|
|
modify the frequency response between the lp and hp outputs. This often biases
|
|
hp level down with increasing frequency, but I have seen chips where there
|
|
is very little bias and sometimes the bias is U-shaped function. It follows
|
|
that the measurements themselves are imperfect. The error bars below are 10 %.
|
|
Results above 20 kHz are probably completely unreliable, because many
|
|
soundcards have imperfect frequency response in that range during recording.
|
|
</p>
|
|
|
|
<form id="theform" action="." method="GET">
|
|
<table>
|
|
<tr valign="top">
|
|
<td><textarea id="type1def" cols="10" rows="30">
|
|
0 256
|
|
8 257
|
|
16 264
|
|
24 248
|
|
32 253
|
|
40 267
|
|
48 262
|
|
56 260
|
|
64 259
|
|
72 254
|
|
80 259
|
|
88 267
|
|
96 275
|
|
104 265
|
|
112 252
|
|
120 258
|
|
128 260
|
|
136 253
|
|
144 261
|
|
152 268
|
|
160 263
|
|
168 260
|
|
176 261
|
|
184 256
|
|
192 258
|
|
200 272
|
|
208 262
|
|
216 265
|
|
224 267
|
|
232 257
|
|
240 275
|
|
248 260
|
|
256 265
|
|
264 260
|
|
272 268
|
|
280 267
|
|
288 270
|
|
296 263
|
|
304 271
|
|
312 271
|
|
320 286
|
|
328 260
|
|
336 276
|
|
344 278
|
|
352 275
|
|
360 279
|
|
368 264
|
|
376 291
|
|
384 282
|
|
392 284
|
|
400 289
|
|
408 297
|
|
416 285
|
|
424 297
|
|
432 289
|
|
440 288
|
|
448 288
|
|
456 302
|
|
464 306
|
|
472 307
|
|
480 298
|
|
488 311
|
|
496 311
|
|
504 335
|
|
512 309
|
|
520 324
|
|
528 312
|
|
536 319
|
|
544 324
|
|
552 331
|
|
560 324
|
|
568 341
|
|
576 340
|
|
584 349
|
|
592 343
|
|
600 360
|
|
608 351
|
|
616 364
|
|
624 370
|
|
632 378
|
|
640 382
|
|
648 394
|
|
656 392
|
|
664 393
|
|
672 411
|
|
680 413
|
|
688 450
|
|
696 446
|
|
704 457
|
|
712 469
|
|
720 492
|
|
728 499
|
|
736 489
|
|
744 536
|
|
752 521
|
|
760 559
|
|
768 528
|
|
776 553
|
|
784 563
|
|
792 562
|
|
800 603
|
|
808 607
|
|
816 633
|
|
824 645
|
|
832 678
|
|
840 688
|
|
848 727
|
|
856 743
|
|
864 776
|
|
872 788
|
|
880 840
|
|
888 875
|
|
896 883
|
|
904 905
|
|
912 967
|
|
920 1007
|
|
928 1039
|
|
936 1136
|
|
944 1157
|
|
952 1234
|
|
960 1292
|
|
968 1385
|
|
976 1422
|
|
984 1577
|
|
992 1613
|
|
1000 1733
|
|
1008 1812
|
|
1016 1975
|
|
1024 1342
|
|
1032 1371
|
|
1040 1485
|
|
1048 1536
|
|
1056 1638
|
|
1064 1680
|
|
1072 1788
|
|
1080 1911
|
|
1088 1974
|
|
1096 2057
|
|
1104 2198
|
|
1112 2267
|
|
1120 2449
|
|
1128 2582
|
|
1136 2776
|
|
1144 2865
|
|
1152 2878
|
|
1160 3091
|
|
1168 3220
|
|
1176 3349
|
|
1184 3550
|
|
1192 3739
|
|
1200 3890
|
|
1208 4113
|
|
1216 4254
|
|
1224 4414
|
|
1232 4627
|
|
1240 4856
|
|
1248 5043
|
|
1256 5294
|
|
1264 5528
|
|
1272 5807
|
|
1280 5483
|
|
1288 5789
|
|
1296 6016
|
|
1304 6258
|
|
1312 6415
|
|
1320 6729
|
|
1328 6898
|
|
1336 7218
|
|
1344 7328
|
|
1352 7634
|
|
1360 7779
|
|
1368 8161
|
|
1376 8314
|
|
1384 8568
|
|
1392 8866
|
|
1400 9106
|
|
1408 9247
|
|
1416 9490
|
|
1424 9688
|
|
1432 9920
|
|
1440 10199
|
|
1448 10514
|
|
1456 10743
|
|
1464 11090
|
|
1472 11255
|
|
1480 11596
|
|
1488 11802
|
|
1496 12046
|
|
1504 12312
|
|
1512 12513
|
|
1520 12818
|
|
1528 13100
|
|
1536 12511
|
|
1544 12836
|
|
1552 13022
|
|
1560 13347
|
|
1568 13552
|
|
1576 13649
|
|
1584 14055
|
|
1592 14371
|
|
1600 14390
|
|
1608 14706
|
|
1616 14946
|
|
1624 15049
|
|
1632 15296
|
|
1640 15565
|
|
1648 15805
|
|
1656 16068
|
|
1664 16156
|
|
1672 16314
|
|
1680 16589
|
|
1688 16864
|
|
1696 17123
|
|
1704 17304
|
|
1712 17508
|
|
1720 17755
|
|
1728 17973
|
|
1736 18210
|
|
1744 18462
|
|
1752 18723
|
|
1760 18831
|
|
1768 19116
|
|
1776 19483
|
|
1784 19583
|
|
1792 19454
|
|
1800 19577
|
|
1808 19865
|
|
1816 20068
|
|
1824 20309
|
|
1832 20321
|
|
1840 20522
|
|
1848 20760
|
|
1856 20941
|
|
1864 21191
|
|
1872 21209
|
|
1880 21483
|
|
1888 21510
|
|
1896 21687
|
|
1904 21926
|
|
1912 21974
|
|
1920 22119
|
|
1928 22260
|
|
1936 22265
|
|
1944 22422
|
|
1952 22441
|
|
1960 22575
|
|
1968 22656
|
|
1976 22729
|
|
1984 22824
|
|
1992 22896
|
|
2000 22974
|
|
2008 22989
|
|
2016 23055
|
|
2024 23091
|
|
2032 23090
|
|
2040 23151
|
|
</textarea><br/>
|
|
<input type="button" id="type1defreset" value="Clear"/>
|
|
</td>
|
|
<td><canvas id="renderarea" width="512" height="512">
|
|
<span style="color:red">Unsupported browser! No canvas element!</span>
|
|
</canvas></td>
|
|
<td>
|
|
<table>
|
|
<tr>
|
|
<td>BaseResistance:</td>
|
|
<td><input type="text" id="baseresistance" value="1.30e6" title="controls the start of curve -- get this right first"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Offset:</td>
|
|
<td><input type="text" id="offset" value="2.9e8" title="partially controls the point when the curve starts to rise"/>
|
|
</tr>
|
|
<tr>
|
|
<td>Steepness:</td>
|
|
<td><input type="text" id="steepness" value="1.007" title="controls the steepness around the midpoint and also the point it starts to rise"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td>MinimumFETResistance:</td>
|
|
<td><input type="text" id="minimumfetresistance" value="1.9e4" title="controls behaviour at the very top end"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td>DAC:</td>
|
|
<td><input type="text" id="dac" value="0.96" title="Kinkedness"/></td>
|
|
</tr>
|
|
</table>
|
|
<input type="button" id="optimize" value="Optimize"/>
|
|
<br/>
|
|
<p>All the graphs update automatically on changes in input.</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form>
|
|
|
|
</body>
|
|
</html>
|