Published
Edited
Nov 20, 2018
Importers
1 star
Insert cell
Insert cell
target = (t) => 5
Insert cell
setpoint = (t) => {
if (t < 50) {
return 0
} else if (t < 100) {
return 100
} else if (t < 150) {
return 0
} else if (t < 300) {
return 150
} else if (t < 350) {
return 50
} else if (t < 400) {
return t - 300
} else if (t < 450) {
return 150
} else {
return 0
}
//return Math.sin(t / 60)*50+100
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = closedLoop(new Buffer(maxWip, maxFlow), new Controller(kp, ki, kd), tm) // Open loop
Insert cell
Insert cell
Insert cell
function chart (data) {
const svg = d3.select(DOM.svg(width, height))
const x = d3.scaleTime()
.domain(d3.extent(data, d => d.t))
.range([margin.left, width - margin.right])
const minY = d3.min(data, d => Math.min(d.u, d.e, d.y, d.s))
const maxY = d3.max(data, d => Math.max(d.u, d.y, d.s, d.e))
const y = d3.scaleLinear()
.domain([minY,maxY]).nice()
.range([height - margin.bottom, margin.top])
const u = d3.scaleLinear()
.domain([minY,maxY]).nice()
.range([height - margin.bottom, margin.top])
const s = d3.scaleLinear()
.domain([minY,maxY]).nice()
.range([height - margin.bottom, margin.top])
const e = d3.scaleLinear()
.domain([minY,maxY]).nice()
.range([height - margin.bottom, margin.top])
const lineU = d3.line()
.x(d => x(d.t))
.y(d => u(d.u))
const lineY = d3.line()
.x(d => x(d.t))
.y(d => y(d.y))
const lineE = d3.line()
.x(d => x(d.t))
.y(d => e(d.e))
const lineS = d3.line()
.x(d => x(d.t))
.y(d => s(d.s))
const xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x))
// .ticks(width / 80)
// .tickSizeOuter(0))
const yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
// .call(g => g.select(".domain").remove())
// .call(g => g.select(".tick:last-of-type text").clone()
// .attr("x", 3)
// .attr("text-anchor", "start")
// .attr("font-weight", "bold")
// .text(data.y))

const yAxis2 = g => g
.attr("transform", `translate(${width - margin.right},0)`)
.call(d3.axisRight(y))
// .call(g => g.select(".domain").remove())
// .call(g => g.select(".tick:last-of-type text").clone()
// .attr("x", 3)
// .attr("text-anchor", "start")
// .attr("font-weight", "bold")
// .text(data.y))
svg.append("g")
.call(xAxis);

svg.append("g")
.call(yAxis);
svg.append("g")
.call(yAxis2);
svg.append("path")
.datum(data)
.attr("fill", "salmon")
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("d", lineS)
.attr("opacity",0.5);
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2)
.attr("d", lineY)
.attr("opacity",1);
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "green")
.attr("stroke-width", 2)
.attr("d", lineE)
.attr("opacity",0.5);
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "brown")
.attr("stroke-width", 2)
.attr("d", lineU)
.attr("opacity",0.5);
return svg.node();
}
Insert cell
enqueue = (current) => current
Insert cell
dequeue = (queued, max) => Math.min(queued, Math.round(Math.random() * max))
Insert cell
class Buffer {
constructor (maxWip, maxFlow) {
this.queued = 0
this.wip = 0
this.maxWip = maxWip
this.maxFlow = maxFlow
this.work = function (u) {
// Add to ready pool
// Add {u} units (between 0 and maxWip)
const w = Math.min(this.maxWip, Math.max(0, Math.round(u)))
this.wip += w

// Transfer {t} units from ready pool (wip) to queue (between 0 and queued)
const t = enqueue(this.wip)
this.wip -= t
this.queued += t

// Release {r} units from queue (between 0 and queued)
const r = dequeue(this.queued, this.maxFlow)
this.queued -= r

return { q: this.queued }
}
}
}
Insert cell
class Controller {
constructor (kp, ki, kd) {
this.kp = kp
this.ki = ki
this.kd = kd
this.i = 0
this.le = 0
this.work = (e) => {
this.i += e
const y = this.kp * e + this.ki * this.i + this.kd * (e - this.le)
this.le = e
return y
}
}
}
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more