I use C++ in Xcode on Mac and a pipe method to communicate with Gnuplot. I am interested in converting my arrays into graphs directly through the program, after I run it. Using
FILE *f = popen("gnuplot -persist", "w");
I open the file and then communicate using fprintf.
Now, I have some data in arrays of interest. w is a "proposed" array of standard normal variables and I intend to check if it is indeed a Gaussian distribution with mean = 0 and variance = 1 .To do that I plot a histogram. After that I want to superimpose a real Gaussian function, which has ex as a x coordinate values and gauss as y coordinate values directly on the histogram. How can I do that?
Here's the code so far:
double start = -4; //min
double end = 4 ; //max
double numberofbins = 100;
double width = (end-start)/numberofbins ;
fprintf (f,
"set ylabel '# of elements'\n"
"set xlabel 'The numbers'\n"
"Min = %g\n" //where binning starts
"Max = %g\n" // where binning ends
"n = %g\n" // the number of bins
"width = 10**(-1)\n" // binwidth; (Max-Min)/n
"bin(x) = width*(floor((x-Min)/width)+0.5) + Min\n"
"f(x)= e**((-x**2)/2) / sqrt(2*pi)\n"
"plot '-' using (bin($1)):(1) smooth freq with boxes,'' u $2:$3 with lines linestyle 1\n",start,end,numberofbins)
for (int i= 0; i < numberofpoints; i++){
fprintf(f, "%g %g %g\n", w[i], ex[i], gauss[i]);
}
fclose(f);
Here is the result if I run the demonstrated code:
As we can see, the binning was successful but the line was omitted and gives the following error:
gnuplot> plot '-' using (bin($1)):(1) smooth freq with boxes,'' u $2:$3 with lines linestyle 1
^
line 100000: column() called from invalid context
I have checked online but nobody is practicing communicating with Gnuplot that way.
If I plot only the 2:3 part (without binning), I get this graph:
Thus, the problem might be with the compatibility of these two plots.
there are different ways to plot "inline" data
plot '-' u 1:2 w lines
1 11
2 22
3 33
e
From gnuplot help special-filenames
If you use both '-' and '' on the same plot command, you'll need to
have two sets of inline data, ...
This means:
plot '-' u 1:2 w boxes, '' u 1:2 w lines
1 11
2 22
3 33
e
1 11
2 22
3 33
e
So, instead, I would generate a datablock in the beginning of your generated command string and reuse the data as many times as you need it during your plotting command.
$Data <<EOD
1 11
2 22
3 33
EOD
plot $Data u 1:2 w boxes, '' u 1:2 w lines
I have solved the problem by creating a second y axis on the same graph and plotting according to it. The code used was:
fprintf (f,
"set xlabel 'The numbers'\n"
"Min = %g\n" //where binning starts
"Max = %g\n" // where binning ends
"n = %g\n" // the number of bins
"width = 10**(-1)\n" // binwidth; (Max-Min)/n
"bin(x) = width*(floor((x-Min)/width)+0.5) + Min\n"
"set ytics 100 nomirror tc lt 1\n"
"set ylabel '# of elements' tc lt 1\n"
"set y2tics 0.4 nomirror tc lt 2\n"
"set y2label 'Theoretical Gaussian' tc lt 2\n"
"plot '-' using (bin($1)):(1) smooth freq with boxes title 'Generator Histogram','-' u 1:2 with l axes x1y2 title 'Theoretical Gaussian (mean=0, std = 1)'\n",start,end,numberofbins) ;
for (int i= 0; i < numberofpoints; i++){
fprintf(f, "%g\n", w[i]);
}
fprintf(f,"e\n");
for (int i= 0; i < numberofpoints; i++){
fprintf(f, "%g %g\n",ex[i], gauss[i]);
}
fprintf(f,"e\n");
fclose(f);
which plots this:
Related
I am using OpenCV's aruco::CharucoBoard object for calibration purposes and noticed that its marker detection doesn't find all visible markers/corners in the images.
I started investigate the matter and tried to detect the markers on the image of the board that was printed for the calibration.
The aruco::detectMarkers fails to detect all markers unless the image size is 640x480.
I'm sure that some tweaking in the aruco::DetectorParameters is required, but I've yet to find the optimal values.
Here is the relevant code:
int nx = 16;
int ny = 10;
double sqrLength = 1.0;
double markerLength = 0.8;
Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
Ptr<aruco::CharucoBoard> board = aruco::CharucoBoard::create(nx, ny, sqrLength, markerLength, dictionary);
aruco::DetectorParameters params = aruco::DetectorParameters::create();
Mat boardImg;
Size boardImgSize = Size(640 * 2, 480 * 2);
board->draw(boardImgSize, boardImg);
vector<int> markerIds;
vector<vector<Point2f>> markerCorners, rejected;
aruco::detectMarkers(boardImg, board->dictionary, markerCorners, markerIds, params, rejected);
cout << markerIds.size() << endl;
aruco::drawDetectedMarkers(boardImg, markerCorners);
imshow("board", boardImg);
waitKey(30);
The total number of markers on the board is 80 and the above code manages to find all of them only for
Size boardImgSize = Size(640, 480)
Any idea on how to improve the detection/which parameters should be tweaked?
First of all it looks like the total number of markers on the board should be 160: nx * ny = 16 * 10 = 160.
But the reason of your issue is related to incorrect sqrLength and markerLength parameter values. As you may find at https://docs.opencv.org/4.5.0/d0/d3c/classcv_1_1aruco_1_1CharucoBoard.html#aa83b0a885d4dd137a41686991f85594c (create() description):
squareLength is a chessboard square side length (normally in meters)
markerLength is a marker side length (same unit than squareLength)
So you should provide values in meters which are measured from printed pattern.
Best choice for your case is to measure square side length and marker side length and set this to sqrLength and markerLength. For example, if your pattern was printed on paper 1x1m values will be:
sqrLength = PatternWidth / nx = 1 / 16 = 0.0625
markerLength = sqrLength * 0.8 = 0.0625 * 0.8 = 0.05
I have a large matrix and I would like to compare the adjacent elements to verify that the values are close to being equal.
For example, in this sequence 1006, 1004,999, 1000, 1003, 6, 1005, 1003 ..... the value 6 is not "close to" 1003 or 1005.
I would like an efficient method for doing the comparison.
Here is slow code to find anything outside of the range. It takes 190 seconds on my old computer.
Thank you.
big = 1e5;
tic;
a = 0;
x = rand(100,big);
for ii = 1:100
for jj = 1:big-1;
y = x(ii,jj) / x(ii,jj+1);
if (or(y < 0.999,y > 1.001)) a++;
endif
endfor;
endfor;
toc
Use vectorization instead of loop:
y = x(:, 1:end-1) ./ x(:, 2:end);
a = nnz(y < 0.999 | y > 1.001);
I am doing a music visualizer program in C++. It gives the frequency spectrum of the audio input. I used Aquila-dsp for getting audio samples, Kiss-fft for doing FFT, and SMFL to play the audio. The input is in (.wav) format. OpenGL is used to plot the graph.
Algorithm Used:
1. *framePointer = 0, N = 10000;*
2. Load audio file and play it using SFML.
3. For *i* = framePointer to --> *framePointer* + *N* < *total_samples_count*
Collect audio samples.
4. Apply Window Function (Hann window)
5. Apply *FFT*
6. Calculate magnitude of first N/2 *FFT* data
*Magnitude* = sqrt( re * re + im * im)
7. Convert to dB(log) scale (optional)
10*log(magnitude)
8. Plot N/2, log(magnitude) values
9. If *framaPointer* >= *toatl_samples_count - N*
Exit
Else go to step 3.
#define N 10000
int framePointer = 0;
void getData()
{
int i,j,x;
Aquila::WaveFile wav(fileName);
double mag[N/2];
double roof = wav.getSamplesCount();
//Get first N samples
for( i = framePointer, j = 0; i < (framePointer + N)
&& framePointer < roof - N ; i++,j++ ){
//Apply window function on the sample
double multiplier = 0.5 * (1 - cos(2*M_PI*j/(N-1)));
in[j].r = multiplier * wav.sample(i);
in[j].i = 0; //stores N samples
}
if(framePointer < roof-N -1){
framePointer = i;
}
else {
printf("Frame pointer > roof - N \n");
printf("Framepointer = %d\n",framePointer );
//get total time and exit
timestamp_t t1 = get_timestamp();
double secs = (t1 - tmain) / 1000000.0L;
std::cout<<"Program exit.\nTotal time: "<<secs<<std::endl;
exit(0);
}
// Apply FFT
getFft(in,out);
// calculate magnitude of first N/2 FFT
for(i = 0; i < N/2; i++ ){
mag[i] = sqrt((out[i].r * out[i].r) + (out[i].i * out[i].i));
graph[i] = log(mag[i]) *10;
}
}
I plot the graph using OpenGL.
Full source code
The problem I got is in choosing the frame length (N value).
For a certain length of audio having:
Length: 237191 ms
Sample frequency: 44100 Hz
Channels: 2
Byte rate: 172 kB/s
Bits per sample: 16b
The graph is synchronized with the audio if I choose N = 10000. Or at least it is stopping while the audio ends.
How to chose the N (frame length) such that the audio will be synchronized with the spectrum.
The audio is dual channel, will this algorithm work for that?
Start by deciding how often you want the visualizer to update. Let's say we want it to update 25 times per second (similar to TV or movie frame rates). That means every 1 / 25 seconds, or every 40 ms. At a sample rate of 44.1 kHz this translates to 44100 / 25 = 1764 samples. Since we typically want a power of 2 FFT size then let's go for N = 2048.
This gives a resolution in the frequency axis of 44100 / 2048 = 21.5 Hz. If you want higher resolution then you can overlap successive FFT windows, e.g. keeping the same update rate and overlapping by 50% then you can have N = 4096 for a resolution of 10.75 Hz.
I am trying to plot a function (gaussian function) with C++. The problem is that the outputs are not smooth and plot looks jagged. Below I attach the output of the same function one made with MATLAB and the other with C++ (Note: Plot is zoomed in so just the peak of function is visible to clarify the difference). And here is the C++ code:
#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;
int main(){
int matrix = 100000;
long double y[matrix], x=0.0, step=0.1;
double FWHM = 1000, alpha;
alpha = FWHM/(2*log(2));
for (int i=0; i<matrix; i++) {
x = x + step;
y[i] = exp(-pow((x-3000.0),2.0)/pow(alpha,2.0));
}
}
and this is MATLAB code:
matrix = 100000;
x=0.0; step=0.1;
FWHM = 1000;
alpha = FWHM/(2*log(2));
for i=1:matrix
x = x + step;
y(i) = exp(-((x-3000.0).^2.0)/alpha.^2.0);
end
How do you store data and plot that? Based on the graph shape, I think you dump y[i] in a text file, read from matlab, and plot them. Also I suspect you didn't set the precision while printing. If you don't set the precision, the default is 6, thus the output will be jagged as you mentioned (like, 11 of 1's in the graph and in the output).
Generally, it is not a good idea to dump double data in a text file, as you will lose precision. Use binary data, like hdf5, protobuf, etc...
std::cout << y[i] << std::endl;
std::cout << std::setprecision(16) << y[i] << std::endl;
The
# without std::setprecision. There are 11 of 1's. The graph has 11 of 1's too.
0.999998
0.999998
0.999999
0.999999
0.999999
1
1
1
1
1
1
1
1
1
1
1
0.999999
0.999999
0.999999
0.999998
# with std::setprecision
0.999998078189791
0.9999984433334466
0.9999987700410408
0.9999990583125361
0.9999993081478993
0.9999995195471015
0.9999996925101183
0.9999998270369299
0.9999999231275207
0.9999999807818797
1
0.9999999807818797
0.9999999231275207
0.9999998270369299
0.9999996925101183
0.9999995195471015
0.9999993081478993
0.9999990583125361
0.9999987700410408
0.9999984433334466
I am using raphael js in the following way to create multiple circles or rectangles according to an user input:
var xx =parseFloat(document.getElementById("Fem").value);
for(var i = 0; i < xx; i+=1) {
paper.circle(10 + (20*i) , 20 , 5).attr("fill","#FF2");
}
var xy =parseFloat(document.getElementById("Male").value);
for(var i = 0; i < xy; i+=1) {
paper.rect(35 + (20*i), 15 ,10 , 10 ).attr("fill","#FF2");
//paper.path("M 15 +(20*i) , 420 ,l 0 , -40 z");
}
This does the job more or less as I want to, but I would like to have a vertical line from the top of each shape when the iteration is run. paper.path does not work. Would someone please help. I am using this for the first time
I'm not sure entirely what you're trying to achieve, but you must make your arithmetic operations outside of the quotes...
paper.path("M " + (15 + (20*i)) + ", 15 L 0 , -40 z");
This shows the lines, you can then play around to get them where you want.