cog/Frameworks/libsidplay/sidplay-residfp-code/fc-curves/daglemdac.html

187 lines
4.7 KiB
HTML

<html>
<head>
<title>Dag Lem's DAC model</title>
<script type="text/javascript">
/* "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 term = false;
var dac = 0.966;
var _2R_div_R = 2.22;
var INFINITY = 1e6;
var bits = 12;
function make_type3_list(l1, l2) {
var approximate_dac_daglem = function(x) {
var vbit = [];
var Vsum = 0;
for (var set_bit = 0; set_bit < bits; set_bit++) {
var Vn = 1.0; // Normalized bit voltage.
var R = 1.0; // Normalized R
var _2R = _2R_div_R*R; // 2R
var Rn = term ? // Rn = 2R for correct termination,
_2R : INFINITY; // INFINITY for missing termination.
// Calculate DAC "tail" resistance by repeated parallel substitution.
for (var bit = 0; bit < set_bit; bit++) {
if (Rn == INFINITY) {
Rn = R + _2R;
}
else {
Rn = R + _2R*Rn/(_2R + Rn); // R + 2R || Rn
}
}
// Source transformation for bit voltage.
if (Rn == INFINITY) {
Rn = _2R;
} else {
Rn = _2R*Rn/(_2R + Rn); // 2R || Rn
Vn = Vn*Rn/_2R;
}
// Calculate DAC output voltage by repeated source transformation from
// the "tail".
for (; bit < bits; bit++) {
Rn += R;
var I = Vn/Rn;
Rn = _2R*Rn/(_2R + Rn); // 2R || Rn
Vn = Rn*I;
}
vbit[set_bit] = Vn;
Vsum += Vn;
}
Vo = 0;
for (var j = 0; j < bits; j++) {
Vo += (x & 0x1)*vbit[j];
x >>= 1;
}
return ((1 << bits) - 1)*Vo/Vsum
};
var approximate_dac_mine = function(x) {
var value = 0;
var bit = 1;
var weight = 1;
var dir = 2 * dac;
var sum = 0;
for (var i = 0; i < 12; i ++) {
if (x & bit)
value += weight;
sum += weight;
bit <<= 1;
weight *= dir;
}
return ((1 << bits) - 1) * value / sum;
};
for (var x = 0; x < 2048; x ++) {
var y1 = approximate_dac_mine(x);
var y2 = approximate_dac_daglem(x);
l1.push([x, y1])
l2.push([x, y2])
}
}
function viewtransform(coords) {
var x = coords[0];
var y = coords[1];
return [x, 2047 - y];
}
function clear_area(ctx) {
ctx.fillStyle = 'rgba(255, 255, 255, 255)';
ctx.fillRect(0, 0, 2048, 2048);
}
function make_grid(ctx) {
ctx.strokeStyle = 'rgba(0, 0, 0, 255)';
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(2048, 0);
ctx.lineTo(2048, 2048);
ctx.lineTo(0, 2048);
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, 0]);
var coord2 = viewtransform([x, 2048]);
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 < 2048; y += 128) {
ctx.strokeStyle = y % 512 == 0 ? 'rgba(32, 32, 32, 128)' : 'rgba(128, 128, 128, 128)';
var coord1 = viewtransform([0, y]);
var coord2 = viewtransform([2048, y]);
ctx.beginPath();
ctx.moveTo(Math.floor(coord1[0]), coord1[1]);
ctx.lineTo(Math.floor(coord2[0]), coord2[1]);
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);
ctx.beginPath();
ctx.moveTo(0, 2048);
ctx.lineTo(2048, 0);
ctx.stroke();
var l1 = [];
var l2 = [];
make_type3_list(l1, l2);
ctx.strokeStyle = 'rgba(0, 255, 0, 255)';
draw_lines(ctx, l1);
ctx.strokeStyle = 'rgba(0, 0, 255, 255)';
draw_lines(ctx, l2);
}
onload = function() {
update_view();
};
</script>
</head>
<body>
<canvas id="renderarea" width="2048" height="2048">
<span style="color:red">Unsupported browser! No canvas element!</span>
</canvas>
</body>
</html>