I came across the Javascript YarnPattern program from Stanford's CS106AX. However, as I was going through the code, I have difficulty understanding some lines.
In the main function YarnPattern(), I don't quite understand the bold chunk written between the stars " ** ". I'm not quite sure what it means when the variables are initialised with thisPeg = 0 and nextPeg = -1.
Also, I'm not quite sure about the line "nextPeg = (thisPeg + DELTA) % pegs.length". I was wondering how this line of code can help reaching a suitable peg's index position.
It would be great if someone can provide a clear explanation with regards to these lines of code. Your help is much appreciated.
// Constants
const GWINDOW_WIDTH = 1000;
const GWINDOW_HEIGHT = 625;
const N_ACROSS = 80;
const N_DOWN = 50;
const DELTA = 113;
// main function
function YarnPattern() {
let gw = GWindow(GWINDOW_WIDTH, GWINDOW_HEIGHT);
let pegs = createPegArray(GWINDOW_WIDTH, GWINDOW_HEIGHT, N_ACROSS, N_DOWN);
**let thisPeg = 0;
let nextPeg = -1;
while (thisPeg !== 0 || nextPeg === -1) {
nextPeg = (thisPeg + DELTA) % pegs.length;
let p0 = pegs[thisPeg];
let p1 = pegs[nextPeg];
let line = GLine(p0.x, p0.y, p1.x, p1.y);**
line.setColor("Magenta");
gw.add(line);
thisPeg = nextPeg;
}
}
function createPegArray(width, height, nAcross, nDown) {
let dx = width / nAcross;
let dy = height / nDown;
let pegs = [ ];
for (let i = 0; i < nAcross; i++) {
pegs.push(Point(i * dx, 0));
}
for (let i = 0; i < nDown; i++) {
pegs.push(Point(nAcross * dx, i * dy));
}
for (let i = nAcross; i > 0; i--) {
pegs.push(Point(i * dx, nDown * dy));
}
for (let i = nDown; i > 0; i--) {
pegs.push(Point(0, i * dy));
}
return pegs;
}
function Point(x, y) {
if (x === undefined) {
x = 0;
y = 0;
}
return { x: x, y: y };
}
Related
I was using below code for downsampling my audio while recording
let inputSampleRate; let inputBuffer = [];
function init(x) {
inputSampleRate = x;
}
function process(inputFrame) {
for (let i = 0; i < inputFrame.length; i++) {
inputBuffer.push((inputFrame[i]) * 32767);
}
const PV_SAMPLE_RATE = 16000;
const PV_FRAME_LENGTH = 512;
while ((inputBuffer.length * PV_SAMPLE_RATE / inputSampleRate) > PV_FRAME_LENGTH) {
let outputFrame = new Int16Array(PV_FRAME_LENGTH);
let sum = 0;
let num = 0;
let outputIndex = 0;
let inputIndex = 0;
while (outputIndex < PV_FRAME_LENGTH) {
sum = 0;
num = 0;
while (inputIndex < Math.min(inputBuffer.length, (outputIndex + 1) * inputSampleRate / PV_SAMPLE_RATE)) {
sum += inputBuffer[inputIndex];
num++;
inputIndex++;
}
outputFrame[outputIndex] = sum / num;
outputIndex++;
}
postMessage(outputFrame);
inputBuffer = inputBuffer.slice(inputIndex);
}
}
Can anyone please suggest how can I edit this one, so that it can be used to upsample my audio from 8k to 16k?
The traditional way to do upsampling (and downsampling) can be found at Wikipedia article about upsampling.
If you want something really cheap and dirty, just linearly interpolate between samples. So if you have samples x0 and x1, the upsampled values are y0=x0, y2=x1, and the new sample y1=(x0+x1)/2. This isn't great and you might hear artifacts.
Edit:
In your code, you can try something like this:
s0 = inputBuffer[inputIndex];
s1 = inputBuffer[inputIndex + 1];
outputFrame[outputIndex] = s0;
outputFrame[outputIndex + 1] = (s0 + s1)/2;
outputFrame[outputIndex + 2] = s1
You'll have to keep track of the indices so you don't try to access beyond the length of the arrays. This is totally untested.
I am a beginner in javascript and have a problem with my code. It says NaN whereas I've been checking for a long time and haven't found the problem. Thanks for having a look at it !Here is my code
const a = -10;
const b = 10;
let X = [];
let p = 20;
for (let i = 0; i <= p; i++) {
X.push(a + i * ((b - a) / p));
}
function maFonction(antecedent) {
return antecedent ** 2;
}
function methRectangles() {
let aireTotale = 0;
for (let i = 0; i <= p; i++) {
aireTotale = aireTotale + maFonction(X[i]) * (X[i + 1] - X[i]);
}
return aireTotale;
}
methRectangles();
console.log(methRectangles());
I'm trying to generate the coordinates for a sphere with a given radius, but am only managing to produce a cylinder and I'm not really figuring out why. Here's my current code:
function makeSphere(radius){
var sphere3D = {};
var radiusX = radius + 0.5;
var radiusY = radius + 0.5;
var radiusZ = radius + 0.5;
var invRadiusX = 1 / radiusX;
var invRadiusY = 1 / radiusY;
var invRadiusZ = 1 / radiusZ;
var ceilRadiusX = Math.ceil(radiusX);
var ceilRadiusY = Math.ceil(radiusY);
var ceilRadiusZ = Math.ceil(radiusZ);
var nextXn = 0;
forX: for (var x = 0; x <= ceilRadiusX; ++x) {
var xn = nextXn;
nextXn = (x + 1) * invRadiusX;
var nextYn = 0;
forY: for (var y = 0; y <= ceilRadiusY; ++y) {
var yn = nextYn;
nextYn = (y + 1) * invRadiusY;
var nextZn = 0;
forZ: for (var z = 0; z <= ceilRadiusZ; ++z) {
var zn = nextZn;
nextZn = (z + 1) * invRadiusZ;
var distanceSq = lengthSq(xn, yn, zn);
if (distanceSq > 1) {
if (z == 0) {
if (y == 0) {
break forX;
}
break forY;
}
break forZ;
}
if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) {
continue;
}
sphere3D[[x,y,z]] = true;
sphere3D[[-x,y,z]] = true;
sphere3D[[x,-y,z]] = true;
sphere3D[[x,y,-z]] = true;
sphere3D[[-x,-y,z]] = true;
sphere3D[[x,-y,-z]] = true;
sphere3D[[-x,y,-z]] = true;
sphere3D[[-x,-y,-z]] = true;
}
}
}
}
function lengthSq(x, y, z) {
return (x * x) + (y * y) + (z * z);
}
function lengthSq(x, z) {
return (x * x) + (z * z);
}
Which gives the following output.
Any ideas on where I'm messing up? Thanks in advance for your attention.
Here's an approach that might be easier to follow. You'll want to break your code up into four parts:
Generating a set of points p within a particular n-dimensional domain
Filtering the set of points to those q that are within 1 unit of a spherical surface defined by a radius and n-dimensional origin
Reflecting the set of points across each of the Cartesian axes intersecting at the origin to create the reflected set of points r
Adding the set of points r to an object nSphere
Below is a set of functions that address each of these concerns to create an n-sphere.
// 0-sphere of radius 5 centered at [6]
console.log(makeNSphere(5, 6)); // { r: [6 - 5], [6 + 5] }
// 2-sphere of radius 2 centered at [0, 0, 0]
console.log(makeNSphere(2, 0, 0, 0));
function makeNSphere (radius, ...origin) {
function onSurface (p) {
const d = distance(
p.map(
(x, i) => x - origin[i]
)
);
return Math.abs(d - radius) < 1;
}
const nSphere = {};
const ps = range(
...origin.map(
x => [x, x + radius + 1]
)
);
const reflection = reflect(...origin);
for (const q of where(ps, onSurface)) {
for (const r of reflection(...q)) {
nSphere[r] = true;
}
}
return nSphere;
}
function distance (p) {
let sum = 0;
for (const x of p) {
sum += x * x;
}
return Math.sqrt(sum);
}
function* range (constraints = [], ...rest) {
const base = rest.length === 0;
let begin = 0;
let end = Infinity;
let increment = 1;
switch (constraints.length) {
case 0: break;
case 1: [end] = constraints; break;
case 2: [begin, end] = constraints; break;
default: [begin, end, increment] = constraints; break;
}
for (let i = begin; i < end; i += increment) {
if (base) {
yield [i];
continue;
}
for (const a of range(...rest)) {
yield [i, ...a];
}
}
}
function* where (ps, predicateFn) {
for (const p of ps) {
if (predicateFn(p)) {
yield p;
}
}
}
function reflect (...axes) {
return function* recurse (x, ...rest) {
if (rest.length === 0) {
yield* base(x);
return;
}
for (const xs of recurse(...rest)) {
yield* base(x, ...xs);
}
}
function* base (x, ...rest) {
yield [x, ...rest];
const axis = axes[axes.length - rest.length - 1];
const y = axis - (x - axis);
if (x !== y) {
yield [y, ...rest];
}
}
}
Not sure if this solves you problem but you can't have 2 functions having the same name. In your case, the second lengthSq() will supersede the first one even if the parameters are different.
There is no native function overloading in Javascript. However you can try these suggestions if it important to stick with same function name that handle multiple parameters Function overloading in Javascript - Best practices
The alternative is to rename it as as lengthSqXZ(x, z) if you are using it elsewhere outside the code you have provided.
I am doing a shooting game and animating seven enemies images.
the image of the begining position
And U can see that the distance between each other is quite well,just 10px.But after the animation finished ,the enemy image in the most left side got much farhter,which is higher than 10px.
I tried many ways and found out that the problem is in the update method.When I change the order of the loop
for(let i=0;i=0;i--) ,the most left side enemy image become much more further,the distance is higher than 10px.
<canvas
id="canvas"
width="700"
height="600"
style="border: 1px solid #333"
></canvas>
<script>
let canvas = document.querySelector("canvas");
let c = canvas.getContext("2d");
c.fillRect(30, 470, 640, 100);
let enemys = [];
let limitObj = {
enemyLimitDown: 470,
enemyLimitLeft: 30,
enemyLimitRight: 670,
enemyLimitTop: 30
};
class Enemy {
constructor(x) {
(this.x = x),
(this.y = 30),
(this.width = 50),
(this.height = 50),
(this.xstep = 2),
(this.ystep = 50),
(this.direction = "right"),
enemys.push(this);
}
draw(enemys) {
for (let i = 0; i < num; i++) {
c.drawImage(
imageEnemy,
enemys[i].x,
enemys[i].y,
enemys[i].width,
enemys[i].height
);
}
}
clear() {
c.clearRect(0, 0, canvas.width, canvas.height - 130);
}
update(enemys) {
for (let i = num-1; i >=0; i--) {
if (enemys[i].direction == "right") {
enemys[i].x += enemys[i].xstep;
let max = 0;
max = findMax();
if (max == limitObj.enemyLimitRight - enemys[i].width) {
for (let i = num - 1; i >= 0; i--) {
enemys[i].y += this.ystep;
enemys[i].direction = "left";
}
}
} else {
enemys[i].x -= enemys[i].xstep;
let min = findMin();
if (min == limitObj.enemyLimitLeft) {
for (let i = num - 1; i >= 0; i--) {
enemys[i].y += this.ystep;
enemys[i].direction = "right";
}
}
}
}
}
animate(enemys) {
this.update(enemys);
this.clear();
this.draw(enemys);
let canRequest = requestAnimationFrame(() => {
this.animate(enemys);
});
for (let i = 0; i < num; i++) {
if (enemys[i].y + this.height >= limitObj.enemyLimitDown) {
cancelAnimationFrame(canRequest);
}
}
}
}
function findMax() {
let max = 0;
for (let i = 0; i < num; i++) {
if (max <= enemys[i].x) {
max = enemys[i].x;
}
}
return max;
}
function findMin() {
let min = canvas.width + 1;
for (let i = 0; i < num; i++) {
if (min >= enemys[i].x) {
min = enemys[i].x;
}
}
return min;
}
// initialize enemy picture
let imageEnemy = new Image();
imageEnemy.src = "https://raw.githubusercontent.com/AbdullA-Ababakre/BlogImage/master/enemy.png";
function initEnemy(x) {
imageEnemy.addEventListener("load", () => {
c.drawImage(imageEnemy, x, 30, 50, 50);
});
}
let enemyStart = 10;
let enemyWidth = 50;
let num = 7;
for (let i = 0; i < num; i++) {
enemys[i] = new Enemy(enemyStart + i * enemyWidth + i * 10);
initEnemy(enemyStart + i * enemyWidth + i * 10);
}
enemys[0].animate(enemys);
</script>
wrong result which the last image is far away.
the final effect of the code above
Welcome to Slack.
I've had a look at your code, and I want you to know it was not immediately obvious what the issue was.
Ultimately I believe I've discovered the source of the problem for you, and fixed it with only a minor tweak;
[...]
let max = 0;
max = findMax();
if (max == limitObj.enemyLimitRight - enemys[i].width) {
for (let j = num - 1; j >= 0; j--) {
enemys[j].y += this.ystep;
enemys[j].direction = "left";
}
} else {
enemys[i].x += enemys[i].xstep;
}
} else {
let min = findMin();
if (min == limitObj.enemyLimitLeft) {
for (let j = num - 1; j >= 0; j--) {
enemys[j].y += this.ystep;
enemys[j].direction = "right";
}
} else {
enemys[i].x -= enemys[i].xstep;
}
[...]
Notice how I've moved your enemys[i].x -= enemys[i].xstep; and enemys[i].x += enemys[i].xstep; lines into the else condition of your limit checks.
I believe your issue was that you'd been incrementing enemy[i].x even on rounds where you'd met your x limit and intended to increment y only, leading to a slight increase in X per iteration, but only for the last enemy; enemy[6].
Hope that helps.
I'm beginner in deep learning, and trying to understand how algorithms works, writing them using JavaScript. Now I'm working on JavaScript implementation of conv2d like Tensorflow does, and misunderstand how to handle different count of filters, I have succeeded for one output filter and multiple output, but I'm confused how to produce operations with multiple filters input e.g. 32 -> 64
Here is example of code using ndarray
:
const outCount = 32 // count of inputs filters
const inCount = 1 // count of output features
const filterSize = 3
const stride = 1
const inShape = [1, 10, 10, outCount]
const outShape = [
1,
Math.ceil((inShape[1] - filterSize + 1) / stride),
Math.ceil((inShape[2] - filterSize + 1) / stride),
outCount
];
const filters = ndarray([], [filterSize, filterSize, inCount, outCount])
const conv2d = (input) => {
const result = ndarray(outShape)
// for each output feature
for (let fo = 0; fo < outCount; fo += 1) {
for (let x = 0; x < outShape[1]; x += 1) {
for (let y = 0; y < outShape[2]; y += 1) {
const fragment = ndarray([], [filterSize, filterSize]);
const filter = ndarray([], [filterSize, filterSize]);
// agregate fragment of image and filter
for (let fx = 0; fx < filterSize; fx += 1) {
for (let fy = 0; fy < filterSize; fy += 1) {
const dx = (x * stride) + fx;
const dy = (y * stride) + fy;
fragment.data.push(input.get(0, dx, dy, 0));
filter.data.push(filters.get(fx, fy, 0, fo));
}
}
// calc dot product of filter and image fragment
result.set(0, x, y, fo, dot(filter, fragment));
}
}
}
return result
}
For test I'm using a Tenforflow as a source of true and it algorithm works correct but with 1 -> N. But my question how to add a support of multiple filters in input value like N -> M.
Could someone explain how to modify this algorithm to make it more compatible with Tensorflow tf.nn.conv2d
A lot of thanks.
You would need to add another for loop. You didn't specify all of your input shapes and dimensions so it's actually kind of hard to write it exactly but it would look like this.
// agregate fragment of image and filter
for (let fx = 0; fx < filterSize; fx += 1) {
for (let fy = 0; fy < filterSize; fy += 1) {
//addition
for (let ch = 0; ch < input.get_channels) {
const dx = (x * stride) + fx;
const dy = (y * stride) + fy;
fragment.data.push(input.get(0, dx, dy, ch));
filter.data.push(filters.get(fx, fy, ch, fo));
}
}
}