From b3b58965b6ae6f763faadef2309e7ebca0c59f2b Mon Sep 17 00:00:00 2001 From: xavierp7 Date: Sun, 5 Dec 2021 14:09:20 -0500 Subject: [PATCH 1/6] Create project.html --- project.html | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 project.html diff --git a/project.html b/project.html new file mode 100644 index 0000000..e950c6d --- /dev/null +++ b/project.html @@ -0,0 +1,59 @@ + + + + HLSI Ex 5 + + + + + + + + + + + + + +

Exercise 5 - Information Capacity

+

[exercises]

+ + + + From 8e9c9faf784df7c9d54ee0971bb6a3474570e1fc Mon Sep 17 00:00:00 2001 From: xavierp7 Date: Sun, 5 Dec 2021 14:11:46 -0500 Subject: [PATCH 2/6] Create powerSpectrumPlot2.js --- powerSpectrumPlot2.js | 198 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 powerSpectrumPlot2.js diff --git a/powerSpectrumPlot2.js b/powerSpectrumPlot2.js new file mode 100644 index 0000000..f8dcfc3 --- /dev/null +++ b/powerSpectrumPlot2.js @@ -0,0 +1,198 @@ +"use strict"; // A must for debugging code. + +// TODO: +// +// 1. We need to find the axis vertical scale based on all the signals +// gn_min and gn_max (and etc). +// +// 2. Optional HTML element to place the plot on, like in Slider() and +// Label(). Now it just appends the plot at the end of the . +// This may be okay for all 15 starting exercises. +// + +// This function does not expose/return any object or other functions. +// Yes, it's magic. +// +// Generates a Power Spectrum Plot with one or more signals that are in +// the environment Signal.env +// +// +// opts: options object +// +// yMax: maximum y plot values in dB +// yMin: manimum y plot values in dB +/// +// +function PowerSpectrumPlot(opts = {}) { + + if(typeof(opts.yMax) === 'undefined') + opts.yMax = 20; + if(typeof(opts.yMin) === 'undefined') + opts.yMin = -60; + + var sigs = []; + var noises = []; // We can only have one noise. + + var freq_plot_min = 1.0e32; // large number that we change + var freq_plot_max = -1.0; // small number that we change + + // We'll display spectrum from all signals in Signal.env; + // + Object.keys(Signal.env).forEach(function(key) { + + let sig = Signal.env[key]; + + // Setup the plot to be updated when sig parameters change. + + if(sig.is_noise) { + noises.push(sig); + return; + } + + // sig is not noise, so we add it to the list of signals. + sigs.push(sig); + + // Get the limits freq_plot_min and freq_plot_max + if(freq_plot_min > sig.freq_plot_min) + freq_plot_min = sig.freq_plot_min; + if(freq_plot_max < sig.freq_plot_max) + freq_plot_max = sig.freq_plot_max; + }); + + + // filter semi-length(m), over-sampling rate(k), total length + const m = 80, // ! increasing this value squares off the signal + k = 20, + n = 2 * k * m + 1; + var bw = 0.2, // bw + gn = 0.0; // gain + var nfft = 2048; + + var generator = new siggen(nfft); + generator.m = m; + + // determine time and frequency scale/units + var [scale_freq, units_freq] = scale_units( + sigs[0].freq_init + sigs[0].bw_max * 0.5, + 0.1 + ); // freq scale + + // 5. X scale will use the index of our data + var fScale = d3 + .scaleLinear() + .domain([freq_plot_min * scale_freq, freq_plot_max * scale_freq]) + .range([0, plot.width]); + + // 6. Y scale will use the randomly generate number + var pScale = d3.scaleLinear().domain([opts.yMin, opts.yMax]).range([plot.height, 0]); + + const df = (freq_plot_max - freq_plot_min) / (nfft - 1); + + // 7. d3's line generator + var linef = d3 + .line() + .x(function (d, i) { + return fScale((freq_plot_min + i * df) * scale_freq); + }) // map frequency + .y(function (d) { + return pScale(d.y); + }); // map PSD + + // 8. An array of objects of length N. Each object has key -> value + // pair, the key being "y" and the value is a random number + var dataf = d3.range(0, nfft - 1).map(function (f) { + return { y: 0 }; + }); + + // create SVG objects + var svgf = svg_create(fScale, pScale, null); // ! null was formerly parentElement + + var labelPrefix = ""; + // TODO: This prefix label needs fixing so it works well for all the + // signals in "sigs' + //if(sigs[0].name.length > 0) + // labelPrefix = sigs[0].name + " "; + + // add labels + svg_add_labels( + svgf, + labelPrefix + "Frequency (" + units_freq + "Hz)", + labelPrefix + "Power Spectral Density (dB)" + ); + + // clip paths + svgf + .append("clipPath") + .attr("id", "clipf") + .append("rect") + .attr("width", plot.width) + .attr("height", plot.height); + + // 9. Append the path, bind the data, and call the line generator + var pathf = svgf + .append("path") + .attr("clip-path", "url(#clipf)") + .datum(dataf) + .attr("class", "stroke-med no-fill stroke-yellow") + .attr("d", linef); + + function update_plot() { + + generator.clear(); + // Iterate through signal array, calc values and pass to generator + sigs.forEach(function (sig) { + let df = sig.freq_plot_max - sig.freq_plot_min; + let fc = -0.5 + (sig.freq - sig.freq_plot_min) / df; + let bw = sig.bw / df; + let gn = sig.gn; + + //console.log("fc=" + fc + " bw=" + bw + " gn=" + gn); + // ! bw (slider %) is limited to 90% range, as log(0) == inf + generator.add_signal(fc, bw, gn + 10 * Math.log10(bw)); + //generator.add_signal(fc, bw, gn); + }); + + // use custom noise floor if given + + if(noises.length > 0) { + let n_gn = 0.0; // total noise gain will be summed to n_gn. + // + // Having more than one noise is odd, but nothing says we can't. + // We sum the noise gains this way: + noises.forEach(function(noise) { + // Sum the power. + n_gn += Math.pow(10, noise.gn/10.0); + }); + // Now make it be in dB. + n_gn = 10 * Math.log10(n_gn); + // + // Note: if there was just one noise than n_gn is just that + // one (noise.gn). + generator.generate(n_gn); + } else + // else default noise floor is used (-120db, see generator src) + generator.generate(); + + dataf = d3.range(0, nfft - 1).map(function (i) { + return { y: generator.psd[i] }; + }); + + pathf.datum(dataf).attr("d", linef); + } + + // Add the update_plot callback to all the signals callbacks. + + noises.forEach(function(noise) { + noise.onChange("gn", update_plot); + }); + + sigs.forEach(function(sig) { + // Setup the plot to be updated when sig parameters change. + sig.onChange("freq", update_plot); + sig.onChange("bw", update_plot); + sig.onChange("gn", update_plot); + }); + + // update_plot() will be called by the callbacks that are set just + // above. +} From 6e8306b0fae292672bcf15d05958daf7534da02e Mon Sep 17 00:00:00 2001 From: xavierp7 Date: Sun, 5 Dec 2021 14:12:58 -0500 Subject: [PATCH 3/6] Update project.html --- project.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.html b/project.html index e950c6d..894232c 100644 --- a/project.html +++ b/project.html @@ -9,7 +9,7 @@ - + From b6e4f965ea142ca70cffe0f08ac9a4c0ba029d3b Mon Sep 17 00:00:00 2001 From: xavierp7 Date: Sun, 5 Dec 2021 14:39:43 -0500 Subject: [PATCH 4/6] Update powerSpectrumPlot2.js --- powerSpectrumPlot2.js | 75 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/powerSpectrumPlot2.js b/powerSpectrumPlot2.js index f8dcfc3..01a9913 100644 --- a/powerSpectrumPlot2.js +++ b/powerSpectrumPlot2.js @@ -169,7 +169,7 @@ function PowerSpectrumPlot(opts = {}) { // Note: if there was just one noise than n_gn is just that // one (noise.gn). generator.generate(n_gn); - } else + } else // else default noise floor is used (-120db, see generator src) generator.generate(); @@ -195,4 +195,77 @@ function PowerSpectrumPlot(opts = {}) { // update_plot() will be called by the callbacks that are set just // above. + var margin = ({top: 10, right: 10, bottom: 30, left: 50}) + var height = 500 + var width = 200 + var x = d3.scaleLinear() + .domain([0, 100]) //REPLACE THIS WITH A PROPER FREQUENCY VALUE + .range([margin.left, width - margin.right]) + var y = d3.scaleLinear() + .domain(d3.extent(dataf)).nice() + .range([height - margin.bottom, margin.top]) + var xAxis = (g, x) => g + .attr("transform", `translate(0,${height - margin.bottom})`) + .call(d3.axisBottom(x)) + var yAxis = (g, y) => g + .attr("transform", `translate(${margin.left},0)`) + .call(d3.axisLeft(y)) + var polyline = (data,x,y) => data.map((d,i) => x(i) + ',' + y(d)).join(' ') //data.map is not a function + var changepos = (line) => { + //console.log(line); + const displace1 = 10; + const displace2 = -5; + let arr = line.split(" "); + for (let i = 0; i < arr.length; i++) { + let nums = arr[i].split(","); + nums[0] = parseFloat(nums[0]) + displace1; + nums[1] = parseFloat(nums[1]) + displace2; + arr[i] = (nums[0] + ',' + nums[1]) + } + return arr.join(' ') + } + + const maxlinesgenerated = 20; + + const svg = d3.create("svg") + .attr("viewBox", [0, 0, width, height]) + .property("value", {x:x}) + + const line = svg.append("polyline") + .attr("fill", "none") + .attr("stroke", "steelblue") + .attr("stroke-width", 1) + .attr("points", polyline(dataf,x,y)); + + const gx = svg.append("g") + .call(xAxis, x); + + const gy = svg.append("g") + .call(yAxis, y); + + var linescount = 0; + + function draw() { + // console.log("here"); + linescount++; + if (linescount > maxlinesgenerated) { + svg.select("polyline").remove(); + linescount--; + } + //const data = dataf; + svg.selectAll("polyline").attr("points",function() { return changepos(d3.select(this).attr("points"));}) + //console.log(linescount) + //console.log(d3.select(this).attr("points")) + svg.append("polyline") + .attr("fill", "none") + .attr("stroke", "steelblue") + .attr("stroke-width", 1) + .attr("points", polyline(dataf,x,y)); + } + + // draw every second + setInterval(draw, 1000); + + return svg.node(); + } From 5b8fd18ff88e7627d3e311dc55ad80d1e9dd7dff Mon Sep 17 00:00:00 2001 From: xavierp7 Date: Sun, 5 Dec 2021 14:49:26 -0500 Subject: [PATCH 5/6] Update powerSpectrumPlot2.js --- powerSpectrumPlot2.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/powerSpectrumPlot2.js b/powerSpectrumPlot2.js index 01a9913..e96e084 100644 --- a/powerSpectrumPlot2.js +++ b/powerSpectrumPlot2.js @@ -103,7 +103,6 @@ function PowerSpectrumPlot(opts = {}) { var dataf = d3.range(0, nfft - 1).map(function (f) { return { y: 0 }; }); - // create SVG objects var svgf = svg_create(fScale, pScale, null); // ! null was formerly parentElement @@ -137,7 +136,7 @@ function PowerSpectrumPlot(opts = {}) { .attr("d", linef); function update_plot() { - + console.log(dataf); generator.clear(); // Iterate through signal array, calc values and pass to generator sigs.forEach(function (sig) { @@ -202,7 +201,7 @@ function PowerSpectrumPlot(opts = {}) { .domain([0, 100]) //REPLACE THIS WITH A PROPER FREQUENCY VALUE .range([margin.left, width - margin.right]) var y = d3.scaleLinear() - .domain(d3.extent(dataf)).nice() + .domain(d3.extent(dataf.map(x => x['y']))).nice() .range([height - margin.bottom, margin.top]) var xAxis = (g, x) => g .attr("transform", `translate(0,${height - margin.bottom})`) @@ -227,7 +226,7 @@ function PowerSpectrumPlot(opts = {}) { const maxlinesgenerated = 20; - const svg = d3.create("svg") + const svg = svgf.append("svg") .attr("viewBox", [0, 0, width, height]) .property("value", {x:x}) @@ -235,7 +234,7 @@ function PowerSpectrumPlot(opts = {}) { .attr("fill", "none") .attr("stroke", "steelblue") .attr("stroke-width", 1) - .attr("points", polyline(dataf,x,y)); + .attr("points", polyline(dataf.map(x => x['y']),x,y)); const gx = svg.append("g") .call(xAxis, x); @@ -260,12 +259,9 @@ function PowerSpectrumPlot(opts = {}) { .attr("fill", "none") .attr("stroke", "steelblue") .attr("stroke-width", 1) - .attr("points", polyline(dataf,x,y)); + .attr("points", polyline(dataf.map(x => x['y']),x,y)); } // draw every second setInterval(draw, 1000); - - return svg.node(); - } From ab430ccd0d905f7dee08bac1dd282c876300dcb5 Mon Sep 17 00:00:00 2001 From: xavierp7 Date: Sun, 5 Dec 2021 15:12:17 -0500 Subject: [PATCH 6/6] Update powerSpectrumPlot2.js --- powerSpectrumPlot2.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/powerSpectrumPlot2.js b/powerSpectrumPlot2.js index e96e084..0b3ea9f 100644 --- a/powerSpectrumPlot2.js +++ b/powerSpectrumPlot2.js @@ -194,14 +194,15 @@ function PowerSpectrumPlot(opts = {}) { // update_plot() will be called by the callbacks that are set just // above. - var margin = ({top: 10, right: 10, bottom: 30, left: 50}) - var height = 500 - var width = 200 + var margin = ({top: 50, right: 100, bottom: 30, left: 50}) + var height = 300 + var width = 750 var x = d3.scaleLinear() - .domain([0, 100]) //REPLACE THIS WITH A PROPER FREQUENCY VALUE + .domain([0, nfft]) //REPLACE THIS WITH A PROPER FREQUENCY VALUE .range([margin.left, width - margin.right]) var y = d3.scaleLinear() - .domain(d3.extent(dataf.map(x => x['y']))).nice() + //.domain(d3.extent(dataf.map(x => x['y']))).nice() + .domain([-60,20]) .range([height - margin.bottom, margin.top]) var xAxis = (g, x) => g .attr("transform", `translate(0,${height - margin.bottom})`) @@ -212,7 +213,7 @@ function PowerSpectrumPlot(opts = {}) { var polyline = (data,x,y) => data.map((d,i) => x(i) + ',' + y(d)).join(' ') //data.map is not a function var changepos = (line) => { //console.log(line); - const displace1 = 10; + const displace1 = 5; const displace2 = -5; let arr = line.split(" "); for (let i = 0; i < arr.length; i++) { @@ -226,7 +227,8 @@ function PowerSpectrumPlot(opts = {}) { const maxlinesgenerated = 20; - const svg = svgf.append("svg") + const svg = d3.select("body").append("svg") + .attr("style","background-color: black") .attr("viewBox", [0, 0, width, height]) .property("value", {x:x})