Skip to content

Commit

Permalink
Analog Filter Designer: added new tool
Browse files Browse the repository at this point in the history
  • Loading branch information
ChSotiriou committed Jan 3, 2025
1 parent a2ed9a3 commit 4e2ef3b
Show file tree
Hide file tree
Showing 16 changed files with 1,423 additions and 9 deletions.
13 changes: 12 additions & 1 deletion dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

<!-- __COMMON_HEAD_START__ -->
<style>
/* Make the body fill the height of the screen */
html, body {
height: 100%;
overflow: scroll;
}

.footer {
Expand All @@ -34,6 +34,12 @@
.footer i:hover {
color: #007bff;
}

.github-corner {
position: fixed;
top: 0;
right: 0;
}
</style>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">

Expand Down Expand Up @@ -102,6 +108,11 @@ <h2 class="text-left mb-4">General</h2>
<td>Simple design tool for DC-DC converters</td>
</tr>

<tr>
<td><a href="tools/general/analog-filter-designer" class="btn btn-link">Analog Filter Designer</a></td>
<td>A tool to simulitate different filters right in the browser</td>
</tr>

</tbody>
</table>

Expand Down
Empty file.
151 changes: 151 additions & 0 deletions dist/tools/general/analog-filter-designer/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Analog Filter Designer</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">

<!-- Custom CSS (now in the /css folder) -->
<link rel="stylesheet" href="css/style.css">

<script type="text/x-mathjax-config">
MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});
</script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<style>
.input-field:invalid {
background-color: lightcoral;
}
</style>

<!-- __COMMON_HEAD_START__ -->
<style>
html, body {
height: 100%;
overflow: scroll;
}

.footer {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #333;
padding: 10px 0;
text-align: left;
color: white;
margin-top: auto; /* Push the footer to the bottom of the page */
}
.footer i {
margin: 0 10px;
font-size: 18px;
cursor: pointer;
}
.footer i:hover {
color: #007bff;
}

.github-corner {
position: fixed;
top: 0;
right: 0;
}
</style>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">

<a href="https://github.com/ChSotiriou/SimpleElectronicsTools" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"/><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"/><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"/></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style><!-- __COMMON_HEAD_END__ -->
</head>

<body>

<div class="container-fluid my-5">
<div class="row">
<div class="col-md-8 offset-md-2">
<h1 class="text-center mb-4">Analog Filter Designer</h1>

<div class="input-group mb-3">
<span class="input-group-text bg-dark text-white" data-toggle="tooltip"
title="Filter Type Selection">Type</span>
<select class="form-control input-field" id="select-filter-type">
<option value="se_rc">Single Ended RC</option>
<option value="diff_rc">Differential RC</option>
</select>
</div>

<div class="input-group mb-3 div-type-se_rc div-type-diff_rc type-input-group">
<span class="input-group-text bg-dark text-white" data-toggle="tooltip"
title="Max Simulation Frequency">$f_{max}$</span>
<input required type="text" class="form-control mode-specific input-field type-se_rc type-diff_rc"
id="max-freq" placeholder="(e.g. 100k, 10Meg)" value="1Meg">

<span class="input-group-text bg-dark text-white" data-toggle="tooltip"
title="Resistance R1 value">$R_1$</span>
<input required type="text" class="form-control mode-specific input-field type-se_rc type-diff_rc"
id="RC_R1" placeholder="(e.g. 100k, 1Meg)" value="1k">

<span class="input-group-text bg-dark text-white" data-toggle="tooltip"
title="Capacitance C1 value">$C_1$</span>
<input required type="text" class="form-control mode-specific input-field type-se_rc type-diff_rc"
id="RC_C1" placeholder="(100n, 1u)" value="100n">
</div>

<hr />

<div id="plot">
</div>

<hr />
<!-- <div class="text-center w-50">
<img></img>
</div> -->
<!-- <hr /> -->

<div class="input-group mb-3 h-20">
<textarea class="form-control" id="spice-input" readonly></textarea>
</div>

<button class="btn btn-primary" id="downloadRawData">Download RAW</button>
</div>
</div>
</div>

<!-- __COMMON_BODY_START__ -->
<div style="height: 10%"></div>
<footer class="footer">
<div class="container">
<div class="row justify-content-left">
<div class="col-auto">
<a href="/" class="text-white"><i class="fas fa-home"></i></a>
</div>
<div class="col-auto">
<a href="https://github.com/chsotiriou/simpleelectronicstools" class="text-white"><i class="fab fa-github"></i></a>
</div>
<div class="col-auto">
<a href="https://csotiriou.com" class="text-white"><i class="fas fa-globe"></i></a>
</div>
</div>
</div>
</footer>
<!-- __COMMON_BODY_END__ -->

<!-- Bootstrap JS (Popper and Bootstrap JS) -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>

<script src="https://cdn.plot.ly/plotly-2.35.2.min.js" charset="utf-8"></script>

<!-- External JavaScript (now in the /js folder) -->
<script src="js/ngrp.js"></script>
<script src="js/ngspice.js"></script>
<script src="js/models.js"></script>
<script src="js/main.js"></script>

</body>

</html>
91 changes: 91 additions & 0 deletions dist/tools/general/analog-filter-designer/js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
var sim_model = ""

function plottly_xline(x, y_min = -1e10, y_max = 1e10) {
return {
type: 'line',
x0: x, // X position where the vertical line starts
x1: x, // X position where the vertical line ends
y0: y_min, // Y position where the line starts
y1: y_max, // Y position where the line ends
line: {
color: 'red',
width: 1
}
}
}

function plottly_yline(y, x_min = -1e10, x_max = 1e10) {
return {
type: 'line',
y0: y, // X position where the vertical line starts
y1: y, // X position where the vertical line ends
x0: x_min, // Y position where the line starts
x1: x_max, // Y position where the line ends
line: {
color: 'red',
width: 1,
}
}
}

let rawData = ''

function processSimulation() {
runSpiceSim(sim_model).then(raw => {
rawData = raw
data = ngrp(raw)

freq = data['data'][0]['v1']
vout_p = data['data'].filter(x => x.name.toLowerCase() == 'v(vout+)')[0]
vout_n = data['data'].filter(x => x.name.toLowerCase() == 'v(vout-)')[0]

y_data = vout_p['v1']
if (vout_n != undefined) y_data = y_data.map((x, i) => x - vout_n['v1'][i])

y_data = y_data.map(x => 10*Math.log10(x))
cutoff = freq[y_data.indexOf(y_data.reduce((c, v) => Math.abs(v - (-3)) < Math.abs(c - (-3)) ? v : c ))]

Plotly.newPlot(document.getElementById('plot'), [{
x: freq,
y: y_data
}], {
margin: { t: 0 },
yaxis: {
title: "Attenuation (dB)",
},
xaxis: {
type: 'log',
title: "Frequency (Hz)",
},
shapes: [
plottly_xline(cutoff, y_min=Math.min(...y_data), y_max=0)
]
}, {
responsive: true
});

})
}

function update() {
sim_name = document.getElementById('select-filter-type').value

Array.from(document.getElementsByClassName('type-input-group')).forEach(x => x.hidden = true)
Array.from(document.getElementsByClassName(`div-type-${sim_name}`)).forEach(x => x.removeAttribute('hidden'))


args_elem = Array.from(document.getElementsByClassName(`type-${sim_name}`))
if (!args_elem.every(x => x.validity.valid)) return

args = args_elem.map(x => x.value)

sim_model = createFormattedString(sim_models[sim_name], args)
document.getElementById('spice-input').textContent = sim_model

processSimulation()
}

Array.from(document.getElementsByClassName('input-field')).forEach(x => x.addEventListener('change', update))
setTimeout(() => update(), 1000)

document.getElementById('downloadRawData').addEventListener('click', x => downloadBlob(rawData, 'out.raw'))
61 changes: 61 additions & 0 deletions dist/tools/general/analog-filter-designer/js/models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
createFormattedString = function(template, values) {
return template.replace(/{(\d+)}/g, (match, index) => {
return typeof values[index] !== 'undefined' ? values[index] : match;
});
}

downloadBlob = function(data, fileName='out.raw', mimeType='application/octet-stream') {
var blob, url;
blob = new Blob([data], {
type: mimeType
});
url = window.URL.createObjectURL(blob);
downloadURL(url, fileName);
setTimeout(function() {
return window.URL.revokeObjectURL(url);
}, 1000);
};

downloadURL = function(data, fileName) {
var a;
a = document.createElement('a');
a.href = data;
a.download = fileName;
document.body.appendChild(a);
a.style = 'display: none';
a.click();
a.remove();
};


const sim_command = `.ac dec 100 1 {0}`

const sim_models = {
'se_rc': `Single Ended RC
R1 Vin Vout+ {1}
C1 Vout+ 0 {2}
VCC Vin 0 AC 1.
${sim_command}
.save V(vout+)
.end`,

'diff_rc': `Differential RC
R1 Vin Vout+ {1}
R2 0 Vout- {1}
C1 Vout+ Vout- {2}
VCC Vin 0 AC 1.
${sim_command}
.save V(Vout+, Vout-)
.end`,

}

const spiceinit = `
set filetype=ascii
`
Loading

0 comments on commit 4e2ef3b

Please sign in to comment.