i am trying to implement a molecular dynamics simulation with the Lennard Jones potential.
I have the time evolution of the positions and velocities of the particles in multiple config files (n = 0,...,99) in steps of dt, such that t=n dt. So the actual simulation part is taken care of in that sense, for now i only have to calculate the potential energy and the force on each particle.
I already implemented a function to read in the config.dat files and put them in vectors, that part works as far as i know without an error. Then i wrote functions that calculate the force and the potential energy with a given distance r_ij between two particles (also used Newtown's third law so that i don't have to calculate the forces multiple times for the same interaction).
I also (hopefully correctly) implemented the periodic boundary conditions so that the particles can interact with their own images in the image boxes.
To test if my code works, i wanted to plot the total potential energy for all t=n dt.
However that does not work as intended because for some reason the potential energy that is written into the output files is always zero (the function for the potential energy returns zero if r_ij > r_cut, r_cut is where the potential is set to zero).
#include <iostream>
#include <math.h>
#include <fstream>
#include <stdlib.h>
#include <vector>
#include <string>
#include <utility>
#include <stdexcept>
#include <sstream>
using namespace std;
// Python >> C/C++
// Reads the initial states from the files
// The whole simulation in Python would have been as long as the function in c++ that just reads in the input
void read_input(int num_file, vector<double>& n, vector<double>& x, vector<double>& y, vector<double>& vx, vector<double>& vy, double& lx, double& ly) {
// Variable file name + opening it
ifstream file("configurations/config_" + to_string(num_file) + ".dat");
// Temp variables for reading in the file
double num, temp_x, temp_y, temp_vx, temp_vy;
// Looping over it
if (file.is_open()) {
string line;
while (getline(file, line)) {
// For the header; The header contains only the dimensions, e.g, 14 14, there are only 5 characters
if (line.length() == 5) {
stringstream dim_str(line);
dim_str >> lx >> ly;
continue;
}
// For the rest files
stringstream temp_str(line);
temp_str >> num >> temp_x >> temp_y >> temp_vx >> temp_vy;
n.push_back(num);
x.push_back(temp_x);
y.push_back(temp_y);
vx.push_back(temp_vx);
vy.push_back(temp_vy);
}
file.close();
}
}
// Calculates the potential for rij
double calc_pot(double r) {
double sigma = 1.0;
double epsilon = 1.0;
if (r <= pow(2, (1.0 / 6)) * sigma) {
double res = 4.0 * epsilon * (pow(sigma / r, 12) - pow(sigma / r, 6)) + epsilon;
return res;
}
else {
return 0;
}
}
// Calculates the force for rij
double calc_force(double r) {
double sigma = 1.0;
// Replaced the sigma^n with 1 bcs sigma = 1
double epsilon = 1.0;
if (r <= pow(2, (1.0 / 6)) * sigma) {
double res = (48.0 * epsilon / pow(r, 13)) - (24 * epsilon / pow(r, 7));
return res;
}
else {
return 0;
}
}
// Calculates the distance of the
double dist(double rx, double ry) {
return sqrt(rx * rx + ry * ry);
}
int main() {
// Misc. parameters
int N = 144;
double mass = 1.0;
double sigma = 1.0;
double epsilon = 1.0;
// Tau = sqrt(mass*sigma^2/epsilon) = (here) 1
double tau = 1.0;
double dt = 0.02;
// Vectors for the read in values for i and i+1
vector<double> n, x, y, vx, vy;
double lx, ly;
// Vector for the potential and two for the force, x and y
vector<double> epot(N), f_x(N), f_y(N);
for (int i = 0; i < N; i++) {
epot[i], f_x[i], f_y[i] = 0;
}
// Outerloop for time steps (in this case the files n = {0,..,99})
for (int k = 0; k <= 99; k++) {
string fname = "output/epot_" + to_string(k) + ".txt";
ofstream output(fname);
read_input(k, n, x, y, vx, vy, lx, ly);
// Inner two loops to accses every possible interaction without doing them twice
for (int i = 0; i < N - 1; i++) {
// Vecctor for particle i
double rix = x[i];
double riy = y[i];
for (int j = i + 1; j < N; j++) {
// Vector for particle i+1
double rjx = x[j];
double rjy = y[j];
// Periodic boundary cond.
if (rix > lx) {
rix -= lx;
}
if (riy > ly) {
riy -= ly;
}
if (rjx > lx) {
rjx -= lx;
}
if (rjy > ly) {
rjy -= ly;
}
if (rix < 0) {
rix += lx;
}
if (riy < 0) {
riy += ly;
}
if (rjx < 0) {
rjx += lx;
}
if (rjy < 0) {
rjy += ly;
}
// Component wise distance for the force
double dist_x = rix - rjx;
double dist_y = riy - rjy;
// Minimum image convention
if (abs(dist_x) > lx / 2) {
dist_x = (lx - abs(dist_x)) * (-dist_x) / abs(dist_x);
}
if (abs(dist_y) > ly / 2) {
dist_y = (ly - abs(dist_y)) * (-dist_y) / abs(dist_y);
}
// Normalized Force/R
f_x[i] += calc_force(dist_x) * (1 / dist(dist_x, dist_y));
f_y[i] += calc_force(dist_y) * (1 / dist(dist_x, dist_y));
f_y[j] += -calc_force(dist_x) * (1 / dist(dist_x, dist_y));
f_y[j] += -calc_force(dist_y) * (1 / dist(dist_x, dist_y));
// Potential energy
epot[i] += calc_pot(dist(dist_x, dist_y));
}
// Potential energy per particle
output << fixed << std::setprecision(4) << epot[i] / (N) << endl;
}
}
}
A config file looks something like this
14 14
0 0 0 1.0292605474705 0.394157727758591
1 0 1.16666666666667 1.05721528014223 1.9850461002085
2 0 2.33333333333333 1.18385526103892 0.143930912297367
3 0 3.5 -0.938850340823852 1.71993225409788
4 0 4.66666666666667 1.99468650405917 0.952210892864475
5 0 5.83333333333333 -0.985361963654284 3.05201529674118
6 0 7 2.84071317501321 0.0689241023507716
7 0 8.16666666666667 3.56152464385237 2.88858201933488
8 0 9.33333333333333 0.147896423269195 1.40592679110988
The header contains the dimensions of the simulation box, here (14,14).
Then all the lines have the corresponding values of {#Particle, x, y, velocity x, Velocity y).
The file above shows this for the first 9 particles.
I am relatively new to c/c++ so have mercy with me 😄.
Also i am aware that the code has still potential to be optimised but i will deal with that when i can calculate the force on each particle correctly.
Edit:
Here is the formula for the potential energy:
The force can be calculated via F= -d/dr U(r).
I'm trying to learn how to find a rational approximation of a real number when both the numerator and denominator are constrained. I've looked at many pages now, including the following two, and learned about the continued fractions method, the Farey sequence, and the Stern-Brocot tree. However, in all of these examples, either the numerator or denominator are unconstrained.
Algorithm for simplifying decimal to fractions
https://gist.github.com/mikeando/7073d62385a34a61a6f7
Here's my situation:
I'm testing mixed-signal ICs.
In one of our tests, in order to find the IC's maximum operating frequency, the clock signal going into the IC is set to 12 MHz and continually decreased until the IC is able to run a simple digital sequence.
The test platform's main clock has a range of 25 to 66 MHz, and the function that sets it takes in a double.
In the current version of the test, it's set to a constant 50.0 MHz, then a function that divides that frequency is called in a loop. The divisor is an integer that can be anywhere between 1 and 4096.
However, this results in imprecise measurements.
The devices always pass at:
50 / 5 = 10 Mhz
50 / 6 = 8.333 MHz
If possible, to get more precise measurements, I'd like to be able to change the main clock's frequency AND the clock divisor in each loop iteration. That's why I'm trying to learn how to write something like a continued fractions algorithm with constraints to both the numerator and denominator. I'm envisioning something like this:
while(dFmax > dFmin)
{
std::pair<double, int> bestSettings = GetBestClkSettings(dFmax);
double dFreq = bestSettings.first;
int iDiv = bestSettings.second;
// Set up clock and timesets
clkset(dFreq);
clkdivide(iDiv);
// Run pattern
// ...
// Get results
// ...
dFmax -= 0.1;
}
Not only have I spent hours experimenting with the code in the second link, but I also tried writing a function that uses something like binary searching just to see what would happen. I'm fully aware that this is terrible code that I can't use to achieve my goals; I just wanted to show that I have been trying.
#include <iostream>
#include <stdio.h>
#include <cmath>
// The fraction struct and the main() function were largely taken from:
// https://gist.github.com/mikeando/7073d62385a34a61a6f7
struct fraction {
int n;
int d;
fraction()
{
this->n = -1;
this->d = -1;
}
fraction(int n, int d)
{
this->n = n;
this->d = d;
}
double asDouble()
{
double dReal = static_cast<double>(n) / static_cast<double>(d);
return dReal;
}
};
fraction ApproximateFrequency(double dTargetFreqMHz, double dTol)
{
fraction result;
if (dTargetFreqMHz < (25.0 / 4096) || dTargetFreqMHz > 66.0)
{
return result;
}
else if (dTargetFreqMHz >= 25.0 && dTargetFreqMHz <= 66.0)
{
result.n = static_cast<int>(dTargetFreqMHz);
result.d = 1;
return result;
}
int iFrqLo = 25;
int iFrqHi = 66;
int iDivLo = 1;
int iDivHi = 4096;
int iFrqCurr = (iFrqLo + iFrqHi) / 2;
int iDivCurr = (iDivLo + iDivHi) / 2;
double dFreq = static_cast<double>(iFrqCurr) / static_cast<double>(iDivCurr);
double dPrevFreq = 0;
int iNumIters = 1;
while (fabs(dTargetFreqMHz - dFreq) > dTol && fabs(dFreq - dPrevFreq) > 1e-8 && iNumIters < 25)
{
dPrevFreq = dFreq;
if (dFreq < dTargetFreqMHz)
{
// The frequency needs to be increased.
// The clock frequency could be increased:
int iFrqNew = (iFrqCurr + iFrqHi) / 2;
double dFrqIfClkInc = static_cast<double>(iFrqNew) / static_cast<double>(iDivCurr);
double dClkIncDiff = fabs(dTargetFreqMHz - dFrqIfClkInc);
// Or the divider could be decreased:
int iDivNew = (iDivLo + iDivCurr) / 2;
double dFrqIfDivDec = static_cast<double>(iFrqCurr) / static_cast<double>(iDivNew);
double dDivDecDiff = fabs(dTargetFreqMHz - dFrqIfDivDec);
// Find the option that produces a better result:
if (dClkIncDiff < dDivDecDiff && iFrqNew >= 25 && iFrqNew <= 66)
{
iFrqCurr = iFrqNew;
}
else if (dDivDecDiff < dClkIncDiff && iDivNew >= 1 && iDivNew <= 4096)
{
iDivCurr = iDivNew;
}
}
else
{
// The frequency needs to be decreased.
// The clock frequency could be decreased:
int iFrqNew = (iFrqLo + iFrqCurr) / 2;
double dFrqIfClkDec = static_cast<double>(iFrqNew) / static_cast<double>(iDivCurr);
double dClkDecDiff = fabs(dTargetFreqMHz - dFrqIfClkDec);
// Or the divider could be increased:
int iDivNew = (iDivCurr + iDivHi) / 2;
double dFrqIfDivInc = static_cast<double>(iFrqCurr) / static_cast<double>(iDivNew);
double dDivIncDiff = fabs(dTargetFreqMHz - dFrqIfDivInc);
// Find the option that produces a better result:
if (dClkDecDiff < dDivIncDiff && iFrqNew >= 25 && iFrqNew <= 66)
{
iFrqCurr = iFrqNew;
}
else if (dDivIncDiff < dClkDecDiff && iDivNew >= 1 && iDivNew <= 4096)
{
iDivCurr = iDivNew;
}
}
// See the frequency attainable with the current settings
dFreq = static_cast<double>(iFrqCurr) / static_cast<double>(iDivCurr);
std::cout << "prev = " << dPrevFreq << ", current = " << dFreq << std::endl;
iNumIters++;
}
result.n = iFrqCurr;
result.d = iDivCurr;
return result;
}
int main(int argc, char* argv[])
{
double dTargetFreqMHz = 20.0;
std::cout << "Target: " << dTargetFreqMHz << "\n\n";
double dTol = 0.05;
fraction mcf = ApproximateFrequency(dTargetFreqMHz, dTol);
printf("tol=%f, n/d = %d/%d = %f (err=%f)\n", dTol, mcf.n, mcf.d, mcf.asDouble(), mcf.asDouble()-dTargetFreqMHz);
}
Any advice or hints would be greatly appreciated. Thank you in advance.
Since your range is so constrained, you could just brute force it. There's only 172,032 possible combinations of numerator and denominator to check. The algorithm could be made more efficient by iterating from 25 to 66 and calculating the closest two denominators, in which case you only have to check 84 possibilities:
fraction ApproximateFrequency(double dTargetFreqMHz, double dTol)
{
fraction result;
if (dTargetFreqMHz < (25.0 / 4096) || dTargetFreqMHz > 66.0)
{
return result;
}
else if (dTargetFreqMHz >= 33.0 && dTargetFreqMHz <= 66.0)
{
result.n = static_cast<int>(dTargetFreqMHz);
result.d = 1;
return result;
}
double smallestError = 66.0;
int closestNum = 0;
int closestDenom = 0;
for (int num = 25; num <= 66; num++)
{
int denom = floor((double)num / dTargetFreqMHz);
if (denom >= 1 && denom <= 4096)
{
double freq = (double)num / double(denom);
double err = fabs(dTargetFreqMHz - freq);
if (err < smallestError)
{
closestNum = num;
closestDenom = denom;
smallestError = err;
}
if (denom <= 4095)
{
freq = (double)num / double(denom + 1);
err = fabs(dTargetFreqMHz - freq);
if (err < smallestError)
{
closestNum = num;
closestDenom = denom + 1;
smallestError = err;
}
}
}
}
result.n = closestNum;
result.d = closestDenom;
return result;
}
the dTol parameter isn't used so you could get rid of it.
I have a mathematical control problem which I solve through Backward induction. The mathematical problem is the following :
with K less than n.
And final conditions
What is J(0,0,0) ?
For this purpose I am using c++ and mingw 32 bit as a compiler.
The problem is the code (below) which solve the problem is an induction and does not provide any results if n,M > 15.
I have tried to launch n=M=100 for 4 days but no results.
Does anyone have a solution? Is it a compiler option to change (the processor memory is not enough)? The complexity is too big?
Here my code
const int n = 10;
const int M = 10;
double J_naive (double K, double Z, double W)
{
double J_tmp = exp(100.0);
double WGreaterThanZero = 0.0;
//Final condition : Boundaries
if (K == n)
{
if (W > 0) WGreaterThanZero = 1.0;
else WGreaterThanZero = 0.0;
if (Z >= WGreaterThanZero) return 0.0;
return exp(100.0);//Infinity
}
//Induction
else if (K < n)
{
double y;
for (int i = 0; i <= M; i++)
{
y = ((double) i)/M;
{
J_tmp = std::min (J_tmp, ((double) n)*y*y +
0.5*J_naive(K+1.0, Z+y, W + 1.0/sqrt(n)) +
0.5*J_naive(K+1.0, Z+y, W - 1.0/sqrt(n)) );
}
}
}
return J_tmp;
}
int main()
{
J_naive(0.0, 0.0, 0.0);
}
You can try the following, completely untested DP code. It needs around 24*n^3*M bytes of memory; if you have that much memory, it should run within a few seconds. If there is some value that will never appear as a true return value, you can get rid of seen_[][][] and use that value in result_[][][] to indicate that the subproblem has not yet been solved; this will reduce memory requirements by about a third. It's based on your code before you made edits to fix bugs.
const int n = 10;
const int M = 10;
bool seen_[n][n * M][2 * n]; // Initially all false
double result_[n][n * M][2 * n];
double J_naive(unsigned K, unsigned ZM, double W0, int Wdsqrtn)
{
double J_tmp = exp(100.0);
double WGreaterThanZero = 0.0;
double Z = (double) ZM / M;
double W = W0 + Wdsqrtn * 1./sqrt(n);
//Final condition : Boundaries
if (K == n)
{
if (W > 0) WGreaterThanZero = 1.0;
else WGreaterThanZero = 0.0;
if (Z >= WGreaterThanZero) return 0.0;
return exp(100.0);//Infinity
}
//Induction
else if (K < n)
{
if (!seen_[K][ZM][Wdsqrtn + n]) {
// Haven't seen this subproblem yet: compute the answer
for (int i = 0; i <= M; i++)
{
J_tmp = std::min (J_tmp, ((double) n)*i/M*i/M +
0.5*J_naive(K+1, ZM+i, W0, Wdsqrtn+1) +
0.5*J_naive(K+1, ZM+i, W0, Wdsqrtn-1) );
}
result_[K][ZM][Wdsqrtn + n] = J_tmp;
seen_[K][ZM][Wdsqrtn + n] = true;
}
}
return result_[K][ZM][Wdsqrtn + n];
}
Okay first of all, I am trying to implement the Perlin noise algorithm, and I managed to achived something strange, and I can't find the solution. I am using matlab to visualize the results I have already checked this question:
"Blocky" Perlin noise
I am doing it from this website:
http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
And another website which I can't find right now but I will update as soon as I can.
So here are some pictures about the problem:
This is the problem if increase zoom
http://i.stack.imgur.com/KkD7u.png
And here are the .cpp-s:
//perlin.cpp
#include "Perlin_H.h"
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <random>
using namespace std;
double Perlin::interp1(double a, double b, double x) {
double ft = x * 3.1415927;
double f = (1.0-cos(ft)) * 0.5;
//return (b-x > b-1/2) ? b-x : a+x;
return a * (1.0-f) + b * f;
}
double Perlin::smoothNoise(double x,double y) {
double corners = ( rand2(x-1, y-1)+rand2(x+1, y-1)+rand2(x-1, y+1)+rand2(x+1, y+1) ) / 16;
double sides = ( rand2(x-1, y) +rand2(x+1, y) +rand2(x, y-1) +rand2(x, y+1) ) / 8;
double center = rand2(x,y)/4;
return corners + sides +center;
}
double Perlin::lininterp1(double a,double b, double x) {
return a*(1-x) + b * x;
}
double Perlin::rand2(double x, double y) {
int n = (int)x + (int)y*57;
//n=pow((n<<13),n);
n=(n<<13)^n;
return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
double Perlin::noise(double x, double y) {
double floorX = (double)floor(x);
double floorY = (double)floor(y);
double s,t,u,v;
s = smoothNoise(floorX,floorY);
t = smoothNoise(floorX+1,floorY);
u = smoothNoise(floorY,floorY+1);
v = smoothNoise(floorX+1,floorY+1);
double int1 = interp1(s,t,x-floorX);
double int2 = interp1(u,v,x-floorX);
return interp1(int1,int2,y-floorY);
}
//main.cpp
#include "Perlin_H.h"
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>;
using namespace std;
int main() {
const int h=64,w=64,octaves=2;
double p=1/1;
double zoom = 30;
Perlin perlin;
double map[h][w];
ofstream output;
output.open("map.txt");
for(int i = 0; i < h ; i++) {
for(int j = 0; j < w ; j++) {
map[i][j] = 0;
}
}
double freq = 2;
for(int i = 0; i < h ; i++) {
for(int j = 0; j < w ; j++) {
double getnoise = 0;
for(int a=0; a < octaves; a++) {
double freq = pow(2,a);
double amp = pow(p,a);
getnoise = perlin.noise((((double)i)*freq)/zoom-(a*10),
((((double)j))*freq)/zoom+(a*10))*amp;
int color = (int)((getnoise * 128.0) + 128.0);
if(color > 255) color = 255;
if(color < 0) color = 0;
map[i][j] = color;
}
output << map[i][j] << "\t";
}
output << "\n";
}
output.close();
system("PAUSE");
return 0;
}
It's a typo!
s = smoothNoise(floorX,floorY);
t = smoothNoise(floorX+1,floorY);
u = smoothNoise(floorY,floorY+1);
v = smoothNoise(floorX+1,floorY+1);
Try:
u = smoothNoise(floorX, floorY +1)
This explains why the diagonal didn't have the blocky appearance (where x=y), and why many of the common feature shapes are subtly off in a mirrored and skewed fashion.
Since it is generally obvious that rand2(floor(y), floor(y)+1) != rand2(floor(x), floor(y+1)) the cell discontinuity will result.
Finding no mathematical error in your implementation, I suspect this is a number format issue.
Such block patterns are created when the grid point values are not actually the same when fetched from different sides - when rand2(floor(n) +1 ,y) != rand2(floor(n+1) ,y)
To fix it, declare floorX to be an int or long instead, and pass it as such to smoothNoise() and rand2().
This can happen due to floating point error in the representation of the Integer values floorX , floorX + 1. The epsilon of magnitude ulp or less can have either sign. the results of addition [floor(n) + 1] and flooring directly [floor(n+1)] are bound by different code, and so need not share a pattern of choosing which side to err on. When the results err on different sides, the int type cast strips the 0.99999999999 and the 0.0000000001 equally, treating the mathematically equivalent numbers as different.
I am implementing an image analysis algorithm using openCV and c++, but I found out openCV doesnt have any function for Butterworth Bandpass filter officially.
in my project I have to pass a time series of pixels into the Butterworth 5 order filter and the function will return the filtered time series pixels. Butterworth(pixelseries,order, frequency), if you have any idea to help me of how to start please let me know. Thank you
EDIT :
after getting help, finally I come up with the following code. which can calculate the Numerator Coefficients and Denominator Coefficients, but the problem is that some of the numbers is not as same as matlab results. here is my code:
#include <iostream>
#include <stdio.h>
#include <vector>
#include <math.h>
using namespace std;
#define N 10 //The number of images which construct a time series for each pixel
#define PI 3.14159
double *ComputeLP( int FilterOrder )
{
double *NumCoeffs;
int m;
int i;
NumCoeffs = (double *)calloc( FilterOrder+1, sizeof(double) );
if( NumCoeffs == NULL ) return( NULL );
NumCoeffs[0] = 1;
NumCoeffs[1] = FilterOrder;
m = FilterOrder/2;
for( i=2; i <= m; ++i)
{
NumCoeffs[i] =(double) (FilterOrder-i+1)*NumCoeffs[i-1]/i;
NumCoeffs[FilterOrder-i]= NumCoeffs[i];
}
NumCoeffs[FilterOrder-1] = FilterOrder;
NumCoeffs[FilterOrder] = 1;
return NumCoeffs;
}
double *ComputeHP( int FilterOrder )
{
double *NumCoeffs;
int i;
NumCoeffs = ComputeLP(FilterOrder);
if(NumCoeffs == NULL ) return( NULL );
for( i = 0; i <= FilterOrder; ++i)
if( i % 2 ) NumCoeffs[i] = -NumCoeffs[i];
return NumCoeffs;
}
double *TrinomialMultiply( int FilterOrder, double *b, double *c )
{
int i, j;
double *RetVal;
RetVal = (double *)calloc( 4 * FilterOrder, sizeof(double) );
if( RetVal == NULL ) return( NULL );
RetVal[2] = c[0];
RetVal[3] = c[1];
RetVal[0] = b[0];
RetVal[1] = b[1];
for( i = 1; i < FilterOrder; ++i )
{
RetVal[2*(2*i+1)] += c[2*i] * RetVal[2*(2*i-1)] - c[2*i+1] * RetVal[2*(2*i-1)+1];
RetVal[2*(2*i+1)+1] += c[2*i] * RetVal[2*(2*i-1)+1] + c[2*i+1] * RetVal[2*(2*i-1)];
for( j = 2*i; j > 1; --j )
{
RetVal[2*j] += b[2*i] * RetVal[2*(j-1)] - b[2*i+1] * RetVal[2*(j-1)+1] +
c[2*i] * RetVal[2*(j-2)] - c[2*i+1] * RetVal[2*(j-2)+1];
RetVal[2*j+1] += b[2*i] * RetVal[2*(j-1)+1] + b[2*i+1] * RetVal[2*(j-1)] +
c[2*i] * RetVal[2*(j-2)+1] + c[2*i+1] * RetVal[2*(j-2)];
}
RetVal[2] += b[2*i] * RetVal[0] - b[2*i+1] * RetVal[1] + c[2*i];
RetVal[3] += b[2*i] * RetVal[1] + b[2*i+1] * RetVal[0] + c[2*i+1];
RetVal[0] += b[2*i];
RetVal[1] += b[2*i+1];
}
return RetVal;
}
double *ComputeNumCoeffs(int FilterOrder)
{
double *TCoeffs;
double *NumCoeffs;
int i;
NumCoeffs = (double *)calloc( 2*FilterOrder+1, sizeof(double) );
if( NumCoeffs == NULL ) return( NULL );
TCoeffs = ComputeHP(FilterOrder);
if( TCoeffs == NULL ) return( NULL );
for( i = 0; i < FilterOrder; ++i)
{
NumCoeffs[2*i] = TCoeffs[i];
NumCoeffs[2*i+1] = 0.0;
}
NumCoeffs[2*FilterOrder] = TCoeffs[FilterOrder];
free(TCoeffs);
return NumCoeffs;
}
double *ComputeDenCoeffs( int FilterOrder, double Lcutoff, double Ucutoff )
{
int k; // loop variables
double theta; // PI * (Ucutoff - Lcutoff) / 2.0
double cp; // cosine of phi
double st; // sine of theta
double ct; // cosine of theta
double s2t; // sine of 2*theta
double c2t; // cosine 0f 2*theta
double *RCoeffs; // z^-2 coefficients
double *TCoeffs; // z^-1 coefficients
double *DenomCoeffs; // dk coefficients
double PoleAngle; // pole angle
double SinPoleAngle; // sine of pole angle
double CosPoleAngle; // cosine of pole angle
double a; // workspace variables
cp = cos(PI * (Ucutoff + Lcutoff) / 2.0);
theta = PI * (Ucutoff - Lcutoff) / 2.0;
st = sin(theta);
ct = cos(theta);
s2t = 2.0*st*ct; // sine of 2*theta
c2t = 2.0*ct*ct - 1.0; // cosine of 2*theta
RCoeffs = (double *)calloc( 2 * FilterOrder, sizeof(double) );
TCoeffs = (double *)calloc( 2 * FilterOrder, sizeof(double) );
for( k = 0; k < FilterOrder; ++k )
{
PoleAngle = PI * (double)(2*k+1)/(double)(2*FilterOrder);
SinPoleAngle = sin(PoleAngle);
CosPoleAngle = cos(PoleAngle);
a = 1.0 + s2t*SinPoleAngle;
RCoeffs[2*k] = c2t/a;
RCoeffs[2*k+1] = s2t*CosPoleAngle/a;
TCoeffs[2*k] = -2.0*cp*(ct+st*SinPoleAngle)/a;
TCoeffs[2*k+1] = -2.0*cp*st*CosPoleAngle/a;
}
DenomCoeffs = TrinomialMultiply(FilterOrder, TCoeffs, RCoeffs );
free(TCoeffs);
free(RCoeffs);
DenomCoeffs[1] = DenomCoeffs[0];
DenomCoeffs[0] = 1.0;
for( k = 3; k <= 2*FilterOrder; ++k )
DenomCoeffs[k] = DenomCoeffs[2*k-2];
return DenomCoeffs;
}
void filter(int ord, double *a, double *b, int np, double *x, double *y)
{
int i,j;
y[0]=b[0] * x[0];
for (i=1;i<ord+1;i++)
{
y[i]=0.0;
for (j=0;j<i+1;j++)
y[i]=y[i]+b[j]*x[i-j];
for (j=0;j<i;j++)
y[i]=y[i]-a[j+1]*y[i-j-1];
}
for (i=ord+1;i<np+1;i++)
{
y[i]=0.0;
for (j=0;j<ord+1;j++)
y[i]=y[i]+b[j]*x[i-j];
for (j=0;j<ord;j++)
y[i]=y[i]-a[j+1]*y[i-j-1];
}
}
int main(int argc, char *argv[])
{
//Frequency bands is a vector of values - Lower Frequency Band and Higher Frequency Band
//First value is lower cutoff and second value is higher cutoff
double FrequencyBands[2] = {0.25,0.375};//these values are as a ratio of f/fs, where fs is sampling rate, and f is cutoff frequency
//and therefore should lie in the range [0 1]
//Filter Order
int FiltOrd = 5;
//Pixel Time Series
/*int PixelTimeSeries[N];
int outputSeries[N];
*/
//Create the variables for the numerator and denominator coefficients
double *DenC = 0;
double *NumC = 0;
//Pass Numerator Coefficients and Denominator Coefficients arrays into function, will return the same
NumC = ComputeNumCoeffs(FiltOrd);
for(int k = 0; k<11; k++)
{
printf("NumC is: %lf\n", NumC[k]);
}
//is A in matlab function and the numbers are correct
DenC = ComputeDenCoeffs(FiltOrd, FrequencyBands[0], FrequencyBands[1]);
for(int k = 0; k<11; k++)
{
printf("DenC is: %lf\n", DenC[k]);
}
double y[5];
double x[5]={1,2,3,4,5};
filter(5, DenC, NumC, 5, x, y);
return 1;
}
I get this resutls for my code :
B= 1,0,-5,0,10,0,-10,0,5,0,-1
A= 1.000000000000000, -4.945988709743181, 13.556489496973796, -24.700711850327743,
32.994881546824828, -33.180726698160655, 25.546126213403539, -14.802008410165968,
6.285430089797051, -1.772929809750849, 0.277753012228403
but if I want to test the coefficinets in same frequency band in MATLAB, I get the following results:
>> [B, A]=butter(5, [0.25,0.375])
B = 0.0002, 0, -0.0008, 0, 0.0016, 0, -0.0016, 0, 0.0008, 0, -0.0002
A = 1.0000, -4.9460, 13.5565, -24.7007, 32.9948, -33.1806, 25.5461, -14.8020, 6.2854, -1.7729, 0.2778
I have test this website :http://www.exstrom.com/journal/sigproc/ code, but the result is equal as mine, not matlab. anybody knows why? or how can I get the same result as matlab toolbox?
I know this is a post on an old thread, and I would usually leave this as a comment, but I'm apparently not able to do that.
In any case, for people searching for similar code, I thought I would post the link from where this code originates (it also has C code for other types of Butterworth filter coefficients and some other cool signal processing code).
The code is located here:
http://www.exstrom.com/journal/sigproc/
Additionally, I think there is a piece of code which calculates said scaling factor for you already.
/**********************************************************************
sf_bwbp - calculates the scaling factor for a butterworth bandpass filter.
The scaling factor is what the c coefficients must be multiplied by so
that the filter response has a maximum value of 1.
*/
double sf_bwbp( int n, double f1f, double f2f )
{
int k; // loop variables
double ctt; // cotangent of theta
double sfr, sfi; // real and imaginary parts of the scaling factor
double parg; // pole angle
double sparg; // sine of pole angle
double cparg; // cosine of pole angle
double a, b, c; // workspace variables
ctt = 1.0 / tan(M_PI * (f2f - f1f) / 2.0);
sfr = 1.0;
sfi = 0.0;
for( k = 0; k < n; ++k )
{
parg = M_PI * (double)(2*k+1)/(double)(2*n);
sparg = ctt + sin(parg);
cparg = cos(parg);
a = (sfr + sfi)*(sparg - cparg);
b = sfr * sparg;
c = -sfi * cparg;
sfr = b - c;
sfi = a - b - c;
}
return( 1.0 / sfr );
}
I finally found it.
I just need to implement the following code from matlab source code to c++ . "the_mandrill" were right, I need to add the normalizing constant into the coefficient:
kern = exp(-j*w*(0:length(b)-1));
b = real(b*(kern*den(:))/(kern*b(:)));
EDIT:
and here is the final edition, which the whole code will return numbers exactly equal to MATLAB :
double *ComputeNumCoeffs(int FilterOrder,double Lcutoff, double Ucutoff, double *DenC)
{
double *TCoeffs;
double *NumCoeffs;
std::complex<double> *NormalizedKernel;
double Numbers[11]={0,1,2,3,4,5,6,7,8,9,10};
int i;
NumCoeffs = (double *)calloc( 2*FilterOrder+1, sizeof(double) );
if( NumCoeffs == NULL ) return( NULL );
NormalizedKernel = (std::complex<double> *)calloc( 2*FilterOrder+1, sizeof(std::complex<double>) );
if( NormalizedKernel == NULL ) return( NULL );
TCoeffs = ComputeHP(FilterOrder);
if( TCoeffs == NULL ) return( NULL );
for( i = 0; i < FilterOrder; ++i)
{
NumCoeffs[2*i] = TCoeffs[i];
NumCoeffs[2*i+1] = 0.0;
}
NumCoeffs[2*FilterOrder] = TCoeffs[FilterOrder];
double cp[2];
double Bw, Wn;
cp[0] = 2*2.0*tan(PI * Lcutoff/ 2.0);
cp[1] = 2*2.0*tan(PI * Ucutoff / 2.0);
Bw = cp[1] - cp[0];
//center frequency
Wn = sqrt(cp[0]*cp[1]);
Wn = 2*atan2(Wn,4);
double kern;
const std::complex<double> result = std::complex<double>(-1,0);
for(int k = 0; k<11; k++)
{
NormalizedKernel[k] = std::exp(-sqrt(result)*Wn*Numbers[k]);
}
double b=0;
double den=0;
for(int d = 0; d<11; d++)
{
b+=real(NormalizedKernel[d]*NumCoeffs[d]);
den+=real(NormalizedKernel[d]*DenC[d]);
}
for(int c = 0; c<11; c++)
{
NumCoeffs[c]=(NumCoeffs[c]*den)/b;
}
free(TCoeffs);
return NumCoeffs;
}
There are code which could be found online implementing butterworth filter. If you use the source code to try to get result matching MATLAB results, there will be the same problem.Basically the result you got from the code hasn't been normalized, and in the source code there is a variable sff in bwhp.c. If you set that to 1, the problem will be easily solved.
I recommend you to use this source code and
the source code and usage could be found here
I added the final edition of function ComputeNumCoeffs to the program and fix "FilterOrder" (k<11 to k<2*FiltOrd+1). Maybe it will save someone's time.
f1=0.5Gz, f2=10Gz, fs=127Gz/2
In MatLab
a={1.000000000000000,-3.329746259105707, 4.180522138699884,-2.365540522960743,0.514875789136976};
b={0.041065495448784, 0.000000000000000,-0.082130990897568, 0.000000000000000,0.041065495448784};
Program:
#include <iostream>
#include <stdio.h>
#include <vector>
#include <math.h>
#include <complex>
using namespace std;
#define N 10 //The number of images which construct a time series for each pixel
#define PI 3.1415926535897932384626433832795
double *ComputeLP(int FilterOrder)
{
double *NumCoeffs;
int m;
int i;
NumCoeffs = (double *)calloc(FilterOrder+1, sizeof(double));
if(NumCoeffs == NULL) return(NULL);
NumCoeffs[0] = 1;
NumCoeffs[1] = FilterOrder;
m = FilterOrder/2;
for(i=2; i <= m; ++i)
{
NumCoeffs[i] =(double) (FilterOrder-i+1)*NumCoeffs[i-1]/i;
NumCoeffs[FilterOrder-i]= NumCoeffs[i];
}
NumCoeffs[FilterOrder-1] = FilterOrder;
NumCoeffs[FilterOrder] = 1;
return NumCoeffs;
}
double *ComputeHP(int FilterOrder)
{
double *NumCoeffs;
int i;
NumCoeffs = ComputeLP(FilterOrder);
if(NumCoeffs == NULL) return(NULL);
for(i = 0; i <= FilterOrder; ++i)
if(i % 2) NumCoeffs[i] = -NumCoeffs[i];
return NumCoeffs;
}
double *TrinomialMultiply(int FilterOrder, double *b, double *c)
{
int i, j;
double *RetVal;
RetVal = (double *)calloc(4 * FilterOrder, sizeof(double));
if(RetVal == NULL) return(NULL);
RetVal[2] = c[0];
RetVal[3] = c[1];
RetVal[0] = b[0];
RetVal[1] = b[1];
for(i = 1; i < FilterOrder; ++i)
{
RetVal[2*(2*i+1)] += c[2*i] * RetVal[2*(2*i-1)] - c[2*i+1] * RetVal[2*(2*i-1)+1];
RetVal[2*(2*i+1)+1] += c[2*i] * RetVal[2*(2*i-1)+1] + c[2*i+1] * RetVal[2*(2*i-1)];
for(j = 2*i; j > 1; --j)
{
RetVal[2*j] += b[2*i] * RetVal[2*(j-1)] - b[2*i+1] * RetVal[2*(j-1)+1] +
c[2*i] * RetVal[2*(j-2)] - c[2*i+1] * RetVal[2*(j-2)+1];
RetVal[2*j+1] += b[2*i] * RetVal[2*(j-1)+1] + b[2*i+1] * RetVal[2*(j-1)] +
c[2*i] * RetVal[2*(j-2)+1] + c[2*i+1] * RetVal[2*(j-2)];
}
RetVal[2] += b[2*i] * RetVal[0] - b[2*i+1] * RetVal[1] + c[2*i];
RetVal[3] += b[2*i] * RetVal[1] + b[2*i+1] * RetVal[0] + c[2*i+1];
RetVal[0] += b[2*i];
RetVal[1] += b[2*i+1];
}
return RetVal;
}
double *ComputeNumCoeffs(int FilterOrder,double Lcutoff, double Ucutoff, double *DenC)
{
double *TCoeffs;
double *NumCoeffs;
std::complex<double> *NormalizedKernel;
double Numbers[11]={0,1,2,3,4,5,6,7,8,9,10};
int i;
NumCoeffs = (double *)calloc(2*FilterOrder+1, sizeof(double));
if(NumCoeffs == NULL) return(NULL);
NormalizedKernel = (std::complex<double> *)calloc(2*FilterOrder+1, sizeof(std::complex<double>));
if(NormalizedKernel == NULL) return(NULL);
TCoeffs = ComputeHP(FilterOrder);
if(TCoeffs == NULL) return(NULL);
for(i = 0; i < FilterOrder; ++i)
{
NumCoeffs[2*i] = TCoeffs[i];
NumCoeffs[2*i+1] = 0.0;
}
NumCoeffs[2*FilterOrder] = TCoeffs[FilterOrder];
double cp[2];
//double Bw;
double Wn;
cp[0] = 2*2.0*tan(PI * Lcutoff/ 2.0);
cp[1] = 2*2.0*tan(PI * Ucutoff/2.0);
//Bw = cp[1] - cp[0];
//center frequency
Wn = sqrt(cp[0]*cp[1]);
Wn = 2*atan2(Wn,4);
//double kern;
const std::complex<double> result = std::complex<double>(-1,0);
for(int k = 0; k<2*FilterOrder+1; k++)
{
NormalizedKernel[k] = std::exp(-sqrt(result)*Wn*Numbers[k]);
}
double b=0;
double den=0;
for(int d = 0; d<2*FilterOrder+1; d++)
{
b+=real(NormalizedKernel[d]*NumCoeffs[d]);
den+=real(NormalizedKernel[d]*DenC[d]);
}
for(int c = 0; c<2*FilterOrder+1; c++)
{
NumCoeffs[c]=(NumCoeffs[c]*den)/b;
}
free(TCoeffs);
return NumCoeffs;
}
double *ComputeDenCoeffs(int FilterOrder, double Lcutoff, double Ucutoff)
{
int k; // loop variables
double theta; // PI * (Ucutoff - Lcutoff)/2.0
double cp; // cosine of phi
double st; // sine of theta
double ct; // cosine of theta
double s2t; // sine of 2*theta
double c2t; // cosine 0f 2*theta
double *RCoeffs; // z^-2 coefficients
double *TCoeffs; // z^-1 coefficients
double *DenomCoeffs; // dk coefficients
double PoleAngle; // pole angle
double SinPoleAngle; // sine of pole angle
double CosPoleAngle; // cosine of pole angle
double a; // workspace variables
cp = cos(PI * (Ucutoff + Lcutoff)/2.0);
theta = PI * (Ucutoff - Lcutoff)/2.0;
st = sin(theta);
ct = cos(theta);
s2t = 2.0*st*ct; // sine of 2*theta
c2t = 2.0*ct*ct - 1.0; // cosine of 2*theta
RCoeffs = (double *)calloc(2 * FilterOrder, sizeof(double));
TCoeffs = (double *)calloc(2 * FilterOrder, sizeof(double));
for(k = 0; k < FilterOrder; ++k)
{
PoleAngle = PI * (double)(2*k+1)/(double)(2*FilterOrder);
SinPoleAngle = sin(PoleAngle);
CosPoleAngle = cos(PoleAngle);
a = 1.0 + s2t*SinPoleAngle;
RCoeffs[2*k] = c2t/a;
RCoeffs[2*k+1] = s2t*CosPoleAngle/a;
TCoeffs[2*k] = -2.0*cp*(ct+st*SinPoleAngle)/a;
TCoeffs[2*k+1] = -2.0*cp*st*CosPoleAngle/a;
}
DenomCoeffs = TrinomialMultiply(FilterOrder, TCoeffs, RCoeffs);
free(TCoeffs);
free(RCoeffs);
DenomCoeffs[1] = DenomCoeffs[0];
DenomCoeffs[0] = 1.0;
for(k = 3; k <= 2*FilterOrder; ++k)
DenomCoeffs[k] = DenomCoeffs[2*k-2];
return DenomCoeffs;
}
void filter(int ord, double *a, double *b, int np, double *x, double *y)
{
int i,j;
y[0]=b[0] * x[0];
for (i=1;i<ord+1;i++)
{
y[i]=0.0;
for (j=0;j<i+1;j++)
y[i]=y[i]+b[j]*x[i-j];
for (j=0;j<i;j++)
y[i]=y[i]-a[j+1]*y[i-j-1];
}
for (i=ord+1;i<np+1;i++)
{
y[i]=0.0;
for (j=0;j<ord+1;j++)
y[i]=y[i]+b[j]*x[i-j];
for (j=0;j<ord;j++)
y[i]=y[i]-a[j+1]*y[i-j-1];
}
}
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
//Frequency bands is a vector of values - Lower Frequency Band and Higher Frequency Band
//First value is lower cutoff and second value is higher cutoff
//f1 = 0.5Gz f2=10Gz
//fs=127Gz
//Kotelnikov/2=Nyquist (127/2)
double FrequencyBands[2] = {0.5/(127.0/2.0),10.0/(127.0/2.0)};//these values are as a ratio of f/fs, where fs is sampling rate, and f is cutoff frequency
//and therefore should lie in the range [0 1]
//Filter Order
int FiltOrd = 2;//5;
//Pixel Time Series
/*int PixelTimeSeries[N];
int outputSeries[N];
*/
//Create the variables for the numerator and denominator coefficients
double *DenC = 0;
double *NumC = 0;
//Pass Numerator Coefficients and Denominator Coefficients arrays into function, will return the same
printf("\n");
//is A in matlab function and the numbers are correct
DenC = ComputeDenCoeffs(FiltOrd, FrequencyBands[0], FrequencyBands[1]);
for(int k = 0; k<2*FiltOrd+1; k++)
{
printf("DenC is: %lf\n", DenC[k]);
}
printf("\n");
NumC = ComputeNumCoeffs(FiltOrd,FrequencyBands[0],FrequencyBands[1],DenC);
for(int k = 0; k<2*FiltOrd+1; k++)
{
printf("NumC is: %lf\n", NumC[k]);
}
double y[5];
double x[5]={1,2,3,4,5};
filter(5, DenC, NumC, 5, x, y);
return 1;
}