Oscilloscope algorithm, dynamic data input, limit output data - c++

I'm trying to make a simple filter incoming data (save maximum and minimum pick), for example: 44100 comes samples per second, but the screen must be displayed 1000. I choose a maximum or minimum in the range of 44.1 samples, and output the screen. However, this algorithm is not very accurate. In the code, it looks like this:
example pseudo algorithm
float max = 0;
float min = 0;
float filter = 0;
float step = 44100/1000;
for(int i = 0 ; i < 44100; i++){
if(input[i] > 0)
if(max < input[i])
max = input[i];
if(input[i] < 0)
if(min > input[i])
min = input[i];
filter++;
if(filter >= step){
filter = filter - step;
//1st version (bad version)
memory[count] = max + min;
//2nd version (bad version)
if(max > abs(min))
memory[count] = max;
else if(max < abs(min))
memory[count] = min;
//3nd version (only maximum)
memory[count] = max; //work great, but only > 0
//4nd version (only minimum)
memory[count] = min; //work great, but only < 0
max = 0;
min = 0;
count++;
if(count >= 1000)
count = 0;
};
};
What am I doing wrong? Separately, everything works fine (max or min), but when connecting all together, result bad.
I have picture, but I can not paste them here.
Links to pictures under this post.

To properly compute the min/max of a set of numbers you have to initialize the values correctly. By setting them to 0 you run into the problems you've found. You have basically two ways to initialize min/max:
Set them to a value larger/smaller than any of your input data.
Set them to the first value in the array.
For (1), if you know your data is, for example, always between -100 and +100 you can simply do:
min = 101;
max = -101;
Note that this doesn't work if your inputs can be any value in the range of the type. For (2) you can do something like:
float max = input[0];
float min = input[0];
...
for (int i ... )
{
...
if (filter >= step)
{
...
min = input[i + 1]; // Be aware of overflow on the last element if
max = input[i + 1]; // input[] is exactly 44100 elements in size
}
}

What do you actually want to see? If it is audio sample, zero means quiet, you probably want to see the envelope - store minimum and maximum for each bin (your bin here=1000 counts) together and display the two in the same picture.
Your sample rate (after division) is 44 Hz, so you can forget some nice simplified waveform (if it is audio)...

The problem that you're seeing in the third graph is that you are storing either a minimum (about -1) or a maximum (about +1). And it's pretty random which of the two you store.
When you then connect the dots, you see a short line segment (2 pixels) whenever you stored two minima or two maxima. But if you store a minimum followed by a maximum, connecting the two gives you a line with a very steep upwards slope. A maximum followed by a minimum gives you a strong downward slope.
The real problem here is that you probably don't realize what you wanted to draw. You should have two arrays, memory_min[] and memory_max[]. And don't mix those two.

Related

Make all elements of the array equal under given conditions

Given an array of size n. Each element denotes the work assigned to some student. Taking some amount of work from a student and assigning it some other student will increase it by a factor of k.
Now we have to redistribute the work such that each student will do equal work. Determine minimum possible work value. And round it off to two decimal places.
A={2,8} K= 1.5 You can take 2.4 from 8 and give it to 2. A={ 2+2.4*1.5 , 8-2.4} Answer is 5.60.
How can we approach to this question. For n=2, I am able to do this simply by solving equations. But for n>2, how can we approach to this. I tried binary search. But I am getting Time limit Exceeded.
sort(a.begin(),a.end());
double low=a[0];
double high= a[n-1];
double res=INT_MAX;
double mid;
int i,j;
while(low<=high){
mid=(low+high)/(2.0);
i=0, j=n-1;
while(i<=j){
if((a[i]+k*a[j])==(k+1)*mid){
i++;
j--;
}
else if((a[i]+k*a[j])<(k+1)*mid){
high=mid;
break;
}
else{
low=mid;
break;
}
}
if(i>j){
res=mid;
high=mid;
}
}
return res;
Please give me suggestions how I can overcome with Time limit exceeded.
If I'm understanding correctly you have an array of doubles and you want to make all elements the same but, the condition is when you subtract you subtract normal but when you add you add multiplied by 1.5, it's basically calculating the average with a condition, so you want make an average and see if its close enough or not so, I made new variable difference that see if the average that we used is bigger or less than the real one, note that difference not give any real value just positive or negative
sort(a.begin(), a.end());
double low = a[0];
double high = a[n - 1];
double average, difference= 0;
average = (low + high) / 2;
do
{
if (difference > 0)
{
low = average;
average = average + high / 2;
}
else if (difference<0)
{
high = average;
average = average + low / 2;
}
for (int i = 0, difference = 0; i < n; i++)
if (a[i] < average)
difference = difference + (a[i]-average) * 1.5;
else
difference = difference + a[i] - average;
} while (difference > 0.01 || difference < -0.01);
The while will done when difference is under 0.01 that's mean average is closer than 0.01 (you can say its 0.01/n almost).
I hope I answered your question, it's my first time to answer question here.
I'd start with some math.
If you graph the values, and you found the target value X, then you would have valleys below X and mountains above X. The volume of the mountains above X, times k, must equal the volume of the valleys.
If you sort the elements, then calculating the net mountain-valley volumes is a linear process. Starting at a_0, all there is is mountain; this is a function of the sum of the a_is and k.
Going from a_i to a_{i+1} makes the a_0 to a_i valleys deeper by a_{i+1}-a_i, and makes the a_{i+1} to a_{last} mountains shallower by the same amount.
In that region the valley/mountain transformation is linear, if it is within that region you can do linear math to find the zero.
Walk from least to greatest, and find the point where the valleys match the mountains.

Implementing iterative autocorrelation process in C++ using for loops

I am implementing pitch tracking using an autocorrelation method in C++ but I am struggling to write the actual line of code which performs the autocorrelation.
I have an array containing a certain number ('values') of amplitude values of a pre-recorded signal, and I am performing the autocorrelation function on a set number (N) of these values.
In order to perform the autocorrelation I have taken the original array and reversed it so that point 0 = point N, point 1 = point N-1 etc, this array is called revarray
Here is what I want to do mathematically:
(array[0] * revarray[0])
(array[0] * revarray[1]) + (array[1] * revarray[0])
(array[0] * revarray[2]) + (array[1] * revarray[1]) + (array[2] * revarray[0])
(array[0] * revarray[3]) + (array[1] * revarray[2]) + (array[2] * revarray[1]) + (array[3] * revarray[0])
...and so on. This will be repeated for array[900]->array[1799] etc until autocorrelation has been performed on all of the samples in the array.
The number of times the autocorrelation is carried out is:
values / N = measurements
Here is the relevent section of my code so far
for (k = 0; k = measurements; ++k){
for (i = k*(N - 1), j = k*N; i >= 0; i--, j++){
revarray[j] = array[i];
for (a = k*N; a = k*(N - 1); ++a){
autocor[a]=0;
for (b = k*N; b = k*(N - 1); ++b){
autocor[a] += //**Here is where I'm confused**//
}
}
}
}
I know that I want to keep iteratively adding new values to autocor[a], but my problem is that the value that needs to be added to will keep changing. I've tried using an increasing count like so:
for (i = (k*N); i = k*(N-1); ++i){
autocor[i] += array[i] * revarray[i-1]
}
But I clearly know this won't work as when the new value is added to the previous autocor[i] this previous value will be incorrect, and when i=0 it will be impossible to calculate using revarray[i-1]
Any suggestions? Been struggling with this for a while now. I managed to get it working on just a single array (not taking N samples at a time) as seen here but I think using the inverted array is a much more efficient approach, I'm just struggling to implement the autocorrelation by taking sections of the entire signal.
It is not very clear to me, but I'll assume that you need to perform your iterations as many times as there are elements in that array (if it is indeed only half that much - adjust the code accordingly).
Also the N is assumed to mean the size of the array, so the index of the last element is N-1.
The loops would looks like that:
for(size_t i = 0; i < N; ++i){
autocorr[i] = 0;
for(size_t j = 0; j <= i; ++j){
const size_t idxA = j
, idxR = i - j; // direct and reverse indices in the array
autocorr[i] += array[idxA] * array[idxR];
}
}
Basically you run the outer loop as many times as there are elements in your array and for each of those iterations you run a shorter loop up to the current last index of the outer array.
All that is left to be done now is to properly calculate the indices of the array and revarray to perform the calculations and accummulate a running sum in the current outer loop's index.

Generate random exponential value correctly c++

I want to generate random number belonging to an exponential distribution. I wrote this
int size = atoi(argv[2]);
double *values = (double*)malloc(sizeof(double)*size);
double gamma = atof(argv[1]);
if(gamma<=0.0){
cout<<"Insert gamma"<<endl;
return 0;
}
for(int i=0; i<size; i++){
values[i]=0;
}
srand ( time(NULL) );
for(int i=0; i<size; i++){
x = ((double) rand() / (RAND_MAX));
//cout << random <<endl;
value=(log(1.0-x)/(-gamma));
//count each value
values[value]=values[value]+1.0;
}
But they do not cover all the vector's size. More or less they cover 10% of the vector, the other fields are all 0 and due to the fact that after I need to do a linear interpolation I want to reduce those 'empty space' in order to have at least one value for each cell of the array, How can I do it?
for example I have a vector of 100000 only the first 60 fields are filled with values so cells from 60 to 999999 are all 0 and when I do linear regression they impact negatively on formula.
Ok, I see the bug
You'er generating size number of events. You really need more events to fill the histogram
PS
Probability for fill bin #n (n is in the range [0...size)) is given by expression
prob = exp(-gamma*n) - exp(-gamma*(n+1))
which for gamma equal to 0.01 and, say, n about 1000 will give you probability of about 4*10^-7. So to get even one event in this bin you'll need to sample about 2.5million times
PPS
and using library exponential sampling while it is good in general, won't buy you anything because as far as I know you sampling is ok

Iterate through all combinations in Gray code order [duplicate]

This question already has answers here:
Gray code increment function
(4 answers)
Closed 8 years ago.
Let's say i have n integers in an array a, and i want to iterate through all possible subsets of these integers, find the sum, and then do something with it.
What i immedieatelly did, was to create a bit field b, which indicated which numbers were included in the subset, and iterate through its possible values using ++b. Then, to compute the sum in each step, i had to iterate through all bits like this:
int sum = 0;
for (int i = 0; i < n; i++)
if (b&1<<i)
sum += a[i];
Then i realized that if i iterated through the possible values of b in a Gray code order, so that each time only a single bit is flipped, i wouldn't have to reconstruct the sum completely, but only needed to add or subtract the single value that is being added or removed from the subset. It should work like this:
int sum = 0;
int whichBitToFlip = 0;
bool isBitSet = false;
for (int k = 0; whichBitToFlip < n; k++) {
sum += (isBitSet ? -1 : 1)*a[whichBitToFlip];
// do something with sum here
whichBitToFlip = ???;
bool isBitSet = ???;
}
But i can't figure out how to directly and efficiently compute whichBitToFlip. The desired values are basically sequence A007814. I know that i can compute the Gray code using the formula (k>>1)^k and xor it with the previous one, but then i need to find the position of the changed bit, which might not be much faster.
So is there any better way to determine these values (index of flipped bit), preferably without a cycle, faster than recomputing the whole sum (of at most 64 values) every time?
To convert a bitmask to a bit index, you can use the ffs function (if you have one), which corresponds to a machine opcode on some machines.
Otherwise, the bit changed in the gray code corresponds to the ruler function:
0, 1, 0, 2, 0, 1, 0, 3, 0, 1...
for which there is a simple recursion. You can simulate the recursion with a stack (it will have maximum depth O(log N), so it's not much space), but probably ffs is a lot faster.
(By the way, even if you were to count bits one at a time from right-to-left, the increment function would be O(1) on average because the total number of trailing 0s in the integers from 1 to 2k is 2k-1.)
So i came up with this:
int sum = 0;
unsigned long grayPos = 0;
int graySign = 1;
for (uint64 k = 2; grayPos < n; k++) {
sum += graySign*a[grayPos];
// Do something with sum
#ifdef _M_X64
grayPos = n;
_BitScanForward64(&grayPos, k);
#else
for (grayPos = 0; !(k&1ull<<grayPos); grayPos++);
#endif
graySign = 2-(k>>grayPos&0x3);
}
It works really well, brought down the execution time (in comparison to always recomputing the whole sum) from 254 to only 7 seconds for n = 32. I also found that counting trailing zeroes with the for cycle is only slightly (~15%) slower than using _BitScanForward64 for the reasons mentioned by rici. So thanks.

Converting MatLab code - Confused

Basically, I have this final piece of code to convert from MatLab to C++.
The function takes in a 2D vector and then checks the elements of the 2D vector against 2 criteria and if not matched, it removes the blocks. But I'm confused to what the code in MatLab wants to be returned, a 2D or a 1D vector? Here is the code:
function f = strip(blocks, sumthresh, zerocrossthresh)
% This function removes leading and trailing blocks that do
% not contain sufficient energy or frequency to warrent consideration.
% Total energy is measured by summing the entire vector.
% Frequency is measured by counting the number of times 0 is crossed.
% The parameters sumthresh and zerocrossthrech are the thresholds,
% averaged across each sample, above which consideration is warrented.
% A good sumthresh would be 0.035
% A good zerocrossthresh would be 0.060
len = length(blocks);
n = sum(size(blocks)) - len;
min = n+1;
max = 0;
sumthreshtotal = len * sumthresh;
zerocrossthreshtotal = len * zerocrossthresh;
for i = 1:n
currsum = sum(abs(blocks(i,1:len)));
currzerocross = zerocross(blocks(i,1:len));
if or((currsum > sumthreshtotal),(currzerocross > zerocrossthreshtotal))
if i < min
min = i;
end
if i > max;
max = i;
end
end
end
% Uncomment these lines to see the min and max selected
% max
% min
if max > min
f = blocks(min:max,1:len);
else
f = zeros(0,0);
end
Alternatively, instead of returning another vector (whether it be 1D or 2D) might it be better to actually send the memory location of the vector and remove the blocks from it? So for example..
for(unsigned i=0; (i < theBlocks.size()); i++)
{
for(unsigned j=0; (j < theBlocks[i].size()); j++)
{
// handle theBlocks[i][kj] ....
}
}
Also, I do not understand this line:
currsum = sum(abs(blocks(i,1:len)));
Basically the: (i,1:len)
Any ideas? Thanks :)
blocks(i,1:len) is telling the array that it wants to go from blocks[i][1 to the end]. So if it was a 3x3 array it's doing something like:
blocks[i][1]
blocks[i][2]
blocks[i][3]
.
.
.
blocks[i][end]
Then it's taking the absolute value of the contents of the matrix and adding them together. It's returning a [x][x] matrix but the length is either going to be a 0x0 or of (max)X(len).