How do I average a signal over time using RMS in JS? - javascript

I have created a function to get the average of an incoming signal over time. The end goal is to get a singular average number from a microphone signal every five minutes, but I have put two seconds in the setInterval part to speed up the testing process. I've tried out some code using RMS equations, but I cannot seem to figure out what is going wrong.
The absoluteLevel is the incoming linear level between 0 and 1, which is being produced in a function above. The absoluteLevel variable is global. The sample rate is set to 44100.
Thanks in advance.
function measureLevel() {
rmsTotal = Math.pow(absoluteLevel, 2) / sampleRate;
counter++;
if (counter === sampleRate) {
rmsAverage = rmsTotal / counter;
counter = 0;
rmsTotal = 0;
}
console.log(rmsTotal);
}
window.setInterval(measureLevel, 2000);

I've assume that all of your variables were initialized already, and available like absoluteLevel. From what I can see there could be two problems:
rmsTotal was getting reset each time instead of accumulating.
I changed the name to 'meanSquare'
You need the square root of that mean square (average of squares)
I renamed rmsAverage to 'rootMeanSquare'
So I would suggest:
function measureLevel() {
meanSquare += Math.pow(absoluteLevel, 2) / sampleRate;
counter++;
if (counter === sampleRate) {
rootMeanSquare = Math.pow(meanSquare, 0.5);
console.log('Counter reached. RMS: ' + rootMeanSquare);
counter = 0;
meanSquare = 0;
}
console.log(meanSquare);
}
window.setInterval(measureLevel, 2000);
I do have a worry though for you. If you run this function once every 2 seconds, and need 44100 samples for a rms, then you'll need 88200 seconds before you get your RMS output!!
If you can get your absoluteLevel very quickly, you might get a faster test with a loop:
function measureLevel() {
counter = 0;
meanSquare = 0;
while counter < sampleRate {
//RUN A SET ABSOLUTE LEVEL FUNC
meanSquare += Math.pow(absoluteLevel, 2) / sampleRate;
counter++;
console.log(meanSquare);
}
rootMeanSquare = Math.pow(meanSquare, 0.5);
console.log('Counter reached. RMS: ' + rootMeanSquare);
}
window.setInterval(measureLevel, 2000);

Related

Function that displays variable numbers from last minute

I am trying to make a function that will only retain its variable count from the past minute.
For example, if I call function count 100 times, if 60 of those calls were from the past minute, it will only return 60, and not 100.
This is what I have tried so far, making the variable an array and adding numbers to it everytime its called, but I do not know how to remove a count when a minute has passed.
var count = 1;
var countArray = [];
UPDATE:
I have updated my code with this, but the array elements are not removing as they should,
function Count() {
var jNow = new Date();
jCountArray.push(jNow);
for (var i = 0; i <= jCountArray.length; i++) {
var secondsDiff = (new Date(jNow).getTime() - new Date(jCountArray[i]).getTime()) / 1000;
if (secondsDiff >= 10) { jCountArray.shift(); }
}
console.log(jCountArray);
return jCountArray.length;
}
If I understand your requirements correctly, and the only thing you need Count to do is return how many times it was called in the last minute, I think we could do something relatively easily leveraging setTimeout:
function getCounter() {
let count = 0;
let duration = 60000;
return function () {
count = count + 1;
setTimeout(function () {
count = count - 1;
}, duration);
return count;
}
}
let counter = getCounter();
function count() {
console.log(counter());
}
<button onclick="count()">Count</button>
The only trick here is, to keep the actual count private, we need a factory function to wrap it in a closure. If that's unimportant you can write it as a simple function and keep the count in the parent scope. Also, for testing purposes you can change the duration to a lower millisecond count to see it in action.

Coin Flip and Counter Javascript

So I'm trying to make this coin flip but it keeps flipping forever... when I want it to stop after 10 times. I also need a counter variable that tells me how many times it is flipped.
var coin = randomNumber (0,1);
write (coin);
while (coin < 10) {
coin = randomNumber (0,1);
write (coin);
}
The easiest way is to just use a for loop.
for (var i = 0; i < 10; i++) {
var coin = randomNumber (0, 1);
write (coin);
}
See this for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration
If you want to stick to the while loop:
var timesFlipped = 0;
while (timesFlipped < 10) {
var coin = randomNumber (0, 1);
write (coin);
timesFlipped = timesFlipped + 1; // alternatively: timesFlipped++;
}
You haven't shown us your randomNumber function, but it's likely that it only produces numbers that are less than 10. Since your while loop says to keep going as long as coin is less than 10, the loop goes forever.
while loops are notorious for resulting in infinite loops. I personally never use them. Since you know how many times you need to loop, a counting loop is the correct choice.
Here's what you need:
// Write the function that gets random number and report the results a certain number of times:
function coinToss(numTimes) {
// Instead of a while loop, use a counting loop that will
// have a definite end point
for(var i = 0; i < numTimes; i++){
// Get a random number from 0 to 1
var coin = Math.floor(Math.random() * 10);
// Test to see if it is even or odd by checking to see if
// it is divisible by 2 with no remainder.
var even = (coin % 2 === 0);
// Report the results
console.log("The coin was " + (even ? "heads " : " tails"));
}
}
// Now, call the function and tell it how many times to loop
coinToss(10);

Set a variable to 2 but console.log says it's undefined

To give a brief overview I am creating a loading bar that needs to go from 0 - 100 based on the total num of pins dropped onto a map in comparison to how many possible locations there are. So bellow I have some logic as to how I am going about achieving that.
//pin drop counter
var pDrop = 2;
//secondary drop counter
var dropCounter = pDrop
//result length counter
var rLength;
//pin drops and then runs the check marker count function
function dropPin(){ checkMarkerCount() }
//if a new pin was dropped then we increase the size of the bar
function checkMarkerCount() {
if (dropCounter != pDrop) {
moveBar();
}
function moveBar() {
//selects the loading bar from the DOM
var barEl = document.getElementById("pro-bar");
//states how wide the bar is
var barW = 1;
//dictates how fast it moves
var barid = setInterval(frame, 10);
//gets how many pins have dropped
var counter = pDrop;
function frame(counter) {
//rLength is the length of an array = the total amount of possible pin drops
if (counter >= rLength) {
clearInterval(barid);
} else {
barW = counter;
barEl.style.width = barW + '%';
console.log(barW)
}
}
}
}
The issues is that even if I say that pDrop is equal to 2 it will log that the length is undefined.... What have I done wrong?
You have to understand the concept of variables and arguments.
function frame(i_counter) {
//rLength is the length of an array = the total amount of possible pin drops
if (i_counter >= rLength) {
clearInterval(barid);
} else {
barW = i_counter;
barEl.style.width = barW + '%';
console.log(barW)
}
}
When you call the function frame, you should set params i_counter.
You think counter you passed as argument is the same you set above.
And barW = counter on your code take the argument you set.
I changed your code a bit, so you don't get rid of counter argument.
When executing frame, do this:
setInterval(function () {
frame(2);
}, 10);

How to run a function once inside the animation loop in Three.js?

I want to run a function once when a condition is true in Three.js.
I am sampling the FPS to send to a external service. The FPS is sampled and averaged. When I have 10 samples, the average is calculated and sent.
The FPS calculation is inspired from the Stats plugin to Three.js.
The problem is that this gets run multiple times(sendInfo()), it seems like it gets run the same amount of times as the FPS. (When FPS = 55, it gets run 55 times)
How can I avoid this? I only want it to call sendInfo() once.
Here is a sample of my animate() loop: (some vars are declared outside)
function animate() {
requestAnimationFrame(animate, renderer.domElement);
var beginTime = performance.now();
// Plus some computations, raycasting etc here
renderer.render(scene, camera);
var endTime = performance.now();
frames ++;
if (endTime > prevTime + 1000) {
var fps = Math.round(frames * 1000 / (endTime - prevTime));
fpsLog.push(fps);
prevTime = endTime;
frames = 0;
}
// When fpsLog has enough values to calculate a average from, we run function
if (fpsLog.length === 10) {
var totalFps = 0;
for (var i = 0; i < fpsLog.length; i++) {
totalFps += fpsLog[i];
}
var averageFps = Math.ceil(totalFps / fpsLog.length); //round up to nearest integer
sendInfo(averageFps); // send fps info to external service <--- THIS ONE GETS RUN MULTIPLE TIMES (it seems like its equal to the FPS, around 56-59 times on my computer)
}
}
I have tried to set a boolean after the sendInfo() is called, and checking this in the if (fpsLog.lenght === 10), but same result.
if (fpsLog.length === 10 && isExecuted === false) {
var totalFps = 0;
for (var i = 0; i < fpsLog.length; i++) {
totalFps += fpsLog[i];
}
var averageFps = Math.ceil(totalFps / fpsLog.length); //round up to nearest integer
sendInfo(averageFps); // send fps info to external service <--- THIS ONE GETS RUN MULTIPLE TIMES (it seems like its equal to the FPS, around 56-59 times on my computer)
isExecuted = true;
}
Declare the isExecuted variable outside the animate() loop solved this.

Incorrect syntax on setTimeout

I'm trying to make a faux loading screen, and I need delays between loading messages of about 20-50ms or so so that people can actually see what's going on before it cuts to the initialized screen. The button that activates this goes to the following function:
function gameinit() {
for (k = 0; k <=1; k += 0.125) {
setTimeout(function () {
var nexttxt = "Loading... " + toString(100 * k) + "%"
}, 20);
displayupdate(nexttxt);
}
}
However this comes up as an incorrect syntax (on JSfiddle - https://jsfiddle.net/YoshiBoy13/xLn7wbg6/2/) when I use JShint - specifically lines four and five. I've looked at the guides for this and everything seems to be in order. What am I doing wrong?
(Note: displayupdate(nexttxt) updates the <p> tags with the next line of text)
When executing the script, nothing happens - the sixteen lines of text on the HTML move up as normal, the top eight being replaced with the eight generated by the gameinit() function, but the gameinit() only generates blank. If the script is executed again, it just outputs eight lines of 112.5% (as if it was the 9th iteration of the for loop).
I'm almost certain it's something elementary that I've missed, could someone please tell me what I've done wrong?
Use setInterval() instead, you can clear interval using clearInterval()
function gameinit() {
displayupdate("Loading... 0%");
var k = 0;
var inter = setInterval(function() {
if (k < 1) {
k += .25;
displayupdate("Loading... " + 100 * k + "%")
} else {
clearInterval(inter);
}
}, 2000);
}
function displayupdate(d) {
console.log(d);
}
gameinit();
here is another function can do this better ---- setInterval
var txt = '';
var time = 0;
var id = setInterval(function(){
console.log("loading..."+time/8*100+"%");
if(time++>7)
clearInterval(id);
},1000);
setTimeout doesn't work as you would expect it to work inside loops. You have to create a closure for each loop variable passed on to setTimeout, or create a new function to execute the setTimeout operation.
function gameinit() {
for (var k = 0; k <= 1; k += 0.125) {
doSetTimeOut(k);
}
}
function doSetTimeOut(k) {
setTimeout(function() {
var nexttxt = "Loading... " + toString(100 * k) + "%"
}, 20);
displayupdate(nexttxt);
}

Categories