I am a very beginner in C++ and for my internship I have to use the fftw library to get the fourier transform of a signal.
Actually, at first, I use python for my programm and then I tried to translate it into C++. However, it doesn't work and I really cannot understand why... I am not really used to pointers and stuff like that so maybe that is the problem. First, I would like to know why programms (the one in python and the in C++) do not give the same results ?
Moreover, I would be very grateful if someone could explain me how to use FFTW with vectors ? I would like to better understand things. Thank you very much :)
The python Code
import numpy as np
import matplotlib.pyplot as plt
from math import cos, sin, sqrt, pi, exp as cos, sin, sqrt, pi, exp
#parameters (suprathresold case)\
eps = 0.05
f = 0.215
mu = 1.1
D = 0.001
DeltaT = 0.001
period = int(1.0 / f / DeltaT)
num_periods_4_transient = 10
num_periods_4_spectrum = 100
#timewindow = 2 * period * DeltaT #quite long to be independant of the transient
l_transient = num_periods_4_transient * period
l_measure = num_periods_4_spectrum * period
#num_points = int(timewindow/DeltaT)
N = 100 # number of realization (number of neurons) should be at the end 10^8
DeltaT_ratio = 100
#signal that modulates the firing rate
#s = [sin(2*3.14*f*t) for t in T]
ts_transient = np.arange(l_transient)*DeltaT
ts_measure = np.arange(l_measure)*DeltaT
s = np.sin(2.0 * np.pi * f * ts_transient)
#Euler's method with FFT
v0 = np.zeros(N)
v = np.zeros((l_transient,N))
samples = np.random.normal(0, 1, (l_transient,N))
DeltaF = 1.0 / (l_measure * DeltaT)
#print "running transient..."
for i in range(1,l_transient):
v[i,:] = v[i-1,:] + DeltaT *(-v[i-1,:]+ mu + eps*s[i-1])+ sqrt(2*D*DeltaT)*samples[i,:]
mask_sp = v[i,:] > 1
v[i, mask_sp ] = 0
v0 = v[-1,:]
v = np.zeros((l_measure,N))
v[0,:] = v0
s = np.sin(2.0 * np.pi * f * ts_measure)
samples = np.random.normal(0, 1, (l_measure,N))
l_compteur = l_measure // DeltaT_ratio + 1
compteur=np.zeros((l_compteur, N))
DeltaT_prime = DeltaT * DeltaT_ratio
#print l_measure,l_measure // DeltaT_ratio
#print "running for measure..."
for i in range(1,l_measure):
v[i,:] = v[i-1,:] + DeltaT *(-v[i-1,:]+ mu + eps*s[i-1])+ sqrt(2*D*DeltaT)*samples[i,:]
mask_sp = v[i,:] > 1
compteur[ int(i / DeltaT_ratio), mask_sp ] = 1.0 / DeltaT_prime
v[i, mask_sp ] = 0
l_freq = int(l_compteur / 2) + 1
spectrum_matrix = np.abs(np.fft.rfft(compteur,axis=0)*DeltaT_prime)**2
powerspectra = np.mean(spectrum_matrix,axis=1)
powerspectra /= (l_measure*DeltaT)
powerspectra[0] = 0.0
plt.plot(np.arange(l_freq)*DeltaF, powerspectra )
plt.show()
The C++ Code
#include <iostream>
#include <cmath>
#include <complex>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <fftw3.h>
#define PI 3.1415926535897932384626433832795
#include <vector>
using namespace std;
double s(double x, double );
double AWGN_generator(void);
std::string double2str(const double x)
{
stringstream sss;
sss<<x;
return sss.str();
}
int main()
{
// srand (time(NULL));
//parameters
double eps = 0.05;
double f_1 = 0.215 ;
//double f_2 = 0.33;
double mu = 1.1 ;
double D = 0.001 ;
double deltaT = 0.001;
long period = 1.0 / f_1 / deltaT;
int N = 1000; //# number of realization (number of neurons) should be at the end 10^8
long DeltaT_ratio = 100;
double DeltaT_prime = DeltaT_ratio*deltaT;
int num_periods_4_transient = 10;
int num_periods_4_spectrum = 20;
long l_transient = num_periods_4_transient * period;
long l_measure = num_periods_4_spectrum * period;
long l_compteur = l_measure / DeltaT_ratio + 1 ;
long l_freq = int(l_compteur / 2) + 1;
double deltaf = 1.0 / (l_compteur * DeltaT_prime);
vector<double> powerspectrum(l_freq,0);
cout<<l_measure<<l_measure / DeltaT_ratio<<endl;
double a = 1.0;
ofstream m_out ;
string outfile = "/Users/Pierrot/powerspectrum_test.txt";
m_out.open(outfile.c_str());
vector< double > compteur(l_compteur,0);
std::vector< std::complex<double> > out(l_freq,0);
fftw_plan p;
p = fftw_plan_dft_r2c_1d(l_compteur, &compteur[0], reinterpret_cast<fftw_complex*>(&out[0]), FFTW_MEASURE);
//cout<<"test1"<<endl;
// Transient
vector< double > v(l_transient,0.0 );
vector<double> Time(l_transient, 0) ;
for (int i = 0 ; i < l_transient ; i++ )
{ Time[i] = deltaT*i ;
}
int pos_1 ;
for (pos_1 = 1 ; pos_1<l_transient ; pos_1 ++)
{
double t = Time[pos_1-1] ;
v[pos_1] = v[pos_1-1] + deltaT*(-v[pos_1-1]+ mu + eps*s(t, f_1)) + sqrt(2*D*deltaT)*AWGN_generator();
if (v[pos_1]>1)
{
v[pos_1]=0 ;
}
}
vector< double > v_bis(l_measure, v[l_transient-1]);
// v_bis[0]=v[l_transient-1];
for( int k=0; k<N ; k++)
{
//copy last value of transient in the new v
v_bis[0] = v_bis[l_measure-1];
double DeltaT_prime = deltaT * DeltaT_ratio ;
vector<double> Time_bis(l_measure) ;
for (int i = 0 ; i < l_measure ; i++ )
{ Time_bis[i] = deltaT*i ;
}
//cout<<"test2"<<endl;
for (int pos_1_bis = 1 ; pos_1_bis<l_measure ; pos_1_bis ++)
{
double t = Time_bis[pos_1_bis-1] ;
v_bis[pos_1_bis] = v_bis[pos_1_bis-1] + deltaT*(-v_bis[pos_1_bis-1]+ mu + eps*s(deltaT*(pos_1_bis-1), f_1)) + sqrt(2*D*deltaT)*AWGN_generator();
//cout<<v_bis[pos_1_bis]<<endl;
if (v_bis[pos_1_bis]>1)
{
v_bis[pos_1_bis]=0 ;
compteur[pos_1_bis/DeltaT_ratio] = 1.0/DeltaT_prime ;
// cout<<pos_1_bis/DeltaT_ratio<<endl;
}
}
fftw_execute(p);
for (long m(0);m<l_freq;m++)
{
powerspectrum[m] += (real( out[m] * conj(out[m]) ) * DeltaT_prime*DeltaT_prime) / (l_measure*deltaT*N);
}
}
//powerspectrum = powerspectrum *DeltaT_prime*DeltaT_prime/(l_measure*deltaT*N)
fftw_destroy_plan(p);
fftw_cleanup();
for (long m(1);m<l_freq;m++)
{
m_out<<deltaf*m <<"\t"<<powerspectrum[m]<<"\n";
}
m_out.close();
printf("ca a marche test.txt");
return 0;
}
double s(double x, double f)
{
return sin(2*PI*f*x);
}
double AWGN_generator()
{/* Generates additive white Gaussian Noise samples with zero mean and a standard
deviation of 1. */
double temp1;
double temp2;
double result;
int p;
p = 1;
while( p > 0 )
{
temp2 = ( rand() / ( (double)RAND_MAX ) ); /* rand() function generates an
integer between 0 and RAND_MAX,
which is defined in stdlib.h.
*/
if ( temp2 == 0 )
{// temp2 is >= (RAND_MAX / 2)
p = 1;
}// end if
else
{// temp2 is < (RAND_MAX / 2)
p = -1;
}// end else
}// end while()
temp1 = cos( ( 2.0 * (double)PI ) * rand() / ( (double)RAND_MAX ) );
result = sqrt( -2.0 * log( temp2 ) ) * temp1;
return result; // return the generated random sample to the caller
}
You are probably invoking undefined behaviour here
reinterpret_cast<fftw_complex*>(&out[0])
That section should be
std::vector<double> compteur(l_compteur);
std::vector<fftw_complex> out(l_freq);
fftw_plan p = fftw_plan_dft_r2c_1d(compteur.size(), compteur.data(), out.data(), FFTW_MEASURE);
This would be much easier to follow if you broke it up into functions, start by extracting each block of calculation that stands on it's own, but you can't go too far.
Other than that, you should avoid using namespace std;, consider using generators in <random>
Related
Alright so this program is meant to simulate a solar system by semi-randomly generating a star, semi-randomly generating planets around the star, simulating the passing of time (using MPI to spread out the computational load), and determining habitability of resulting planets. I should have it commented for readability.
I am however having a problem with getting MPI working. As far as I can tell I'm doing something wrong that prevents it from initializing properly. Here's the errors I get.
OrbitPlus.cpp:323:50: error: invalid conversion from ‘char’ to ‘char**’ [-fpermissive]
system1 = Time( system, n , dt , argc, **argv);
^
OrbitPlus.cpp:191:33: error: initializing argument 5 of ‘std::vector<std::vector<float> > Time(std::vector<std::vector<float> >, int, float, int, char**)’ [-fpermissive]
std::vector<std::vector<float>> Time( std::vector<std::vector<float>> system , int n, float dt, int argc, char **argv){
^
I do find it interesting that both errors are considered fpermissive errors if when I compile it with -
mpic++ -std=c++11 -o OrbitPlus OrbitPlus.cpp
So it seems if I was feeling adventurous I could just run the code with -fpermissive option and roll the dice, but I don't feel like being so brave. Clearly the errors are related to each other.
Here's my code.
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <tuple>
#include <vector>
#include <stdio.h>
#include <math.h>
#include <complex>
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <algorithm>
#include "mpi.h"
double MyRandom(){
//////////////////////////
//Random Number Generator
//Returns number between 0-99
//////////////////////////
double y = 0;
unsigned seed = time(0);
std::srand(seed);
uint64_t x = std::rand();
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
x = (1070739 * x) % 2199023255530;
y = x / 21990232555.31 ;
return y;
}
////////////////////////
///////////////////////
std::tuple< char , float , float , float , int > Star(){
////////////////////////////
//Star will generate a Star
//Randomly or User Selected
//Class, Luminosity, Probability, Radius, Mass, Temperature
//Stars always take up 99% of the mass of the system.
///////////////////////////
char Class;
int choice = 8;
float L, R, M, T;
double y = 4;
std::tuple< char , float , float , float , float > star( Class , L , R , M , T) ;
std::cout << "Select Star Class (OBAFGKM) or Select 8 for Random" << std::endl;
std::cout << "1 = O, 2 = B, 3 = A, 4 = F, 5 = G, 6 = K, 7 = M : ";
std::cin >> choice;
if ( choice == 8 ) {
y = MyRandom();
if (y <= 0.003) choice = 1;
if ((y > 0.003) && (y <= 0.133)) choice = 2;
if ((y > 0.133) && (y <= 0.733)) choice = 3;
if ((y > 0.733) && (y <= 3.733)) choice = 4;
if ((y > 3.733) && (y <= 11.333)) choice = 5;
if ((y > 11.333) && (y <= 23.433)) choice = 6;
else choice = 7;
}
if (choice == 1) {
Class = 'O';
L = 30000;
R = 0.0307;
M = 16;
T = 30000;
}
if (choice == 2) {
Class = 'B';
L = 15000;
R = 0.0195;
M = 9;
T = 20000;
}
if (choice == 3) {
Class = 'A';
L = 15;
R = 0.00744;
M = 1.7;
T = 8700;
}
if (choice == 4) {
Class = 'F';
L = 3.25;
R = 0.00488;
M = 1.2;
T = 6750;
}
if (choice == 5) {
Class = 'G';
L = 1;
R = 0.00465;
M = 1;
T = 5700;
}
if (choice == 6) {
Class = 'K';
L = 0.34;
R = 0.00356;
M = 0.62;
T = 4450;
}
if (choice == 7) {
Class = 'M';
L = 0.08;
R = 0.00326;
M = 0.26;
T = 3000;
}
return star;
}
////////////
///////////
std::vector< std::vector<float> > Planet( float L, float R, float M, int T, int n){
///////////////////////////
//Planet generates the Planets
//Random 1 - 10, Random distribution 0.06 - 6 JAU unless specified by User
//Frost line Calculated, First Planet after Frost line is the Jupiter
//The Jupiter will have the most mass of all Jovian worlds
//Otherwise divided into Jovian and Terrestrial Worlds, Random Masses within groups
//Also calculates if a planet is in the Habitable Zone
////////////////////////////
float frostline, innerCHZ, outerCHZ;
float a = 0.06; // a - albedo
float m = M / 100; //Mass of the Jupiter always 1/100th mass of the Star.
std::vector<float> sys;
std::vector<std::vector <float>> system;
for (int i = 0 ; i < n ; i++){
sys.push_back( MyRandom()/10 * 3 ) ; //Distances in terms of Sol AU
}
sort(sys.begin(), sys.end() );
for (int i = 0 ; i < n ; i++){
system[i].push_back(sys[i]);
system[i].push_back(0); //system[i][0] is x, system[i][1] is y
}
frostline = (0.6 * T / 150) * (0.6 * T/150) * R / sqrt(1 - a);
innerCHZ = sqrt(L / 1.1);
outerCHZ = sqrt(L / 0.53);
for (int i = 0 ; i < n ; i++){
if (system[i][0] <= frostline) {
float tmass = m * 0.0003 * MyRandom();
system[i].push_back(tmass) ; //system[i][2] is mass, [3] is marker for the Jupiter
system[i].push_back(0) ;
}
if ((system[i][0] >= frostline) && (system[i-1][0] < frostline)){
system[i].push_back(m) ;
float J = 1;
system[i].push_back(J) ;
}
if ((system[i][0] >= frostline) && (system[i-1][0] >= frostline)) {
float jmass = m * 0.01 * MyRandom();
system[i].push_back(jmass) ;
system[i].push_back(0) ;
}
if ((system[i][0] >= innerCHZ) && (system[i][0] <= outerCHZ)){
float H = 1;
system[i].push_back(H);
}
else system[i].push_back(0); //[4] is habitable marker
}
return system;
}
////////////
////////////
std::vector<std::vector<float>> Time( std::vector<std::vector<float>> system , int n, float dt, int argc, char **argv){
#define ASIZE 3 //Setup
int MPI_Init(int *argc, char ***argv);
int rank, numtasks = n, namelen, rc;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Status status;
MPI_Init( &argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Get_processor_name(processor_name, &namelen);
rc = MPI_Bcast(&system, ASIZE, MPI_DOUBLE, 0, MPI_COMM_WORLD); //Master
// Broadcast computed initial values to all other processes
if (rc != MPI_SUCCESS) {
fprintf(stderr, "Oops! An error occurred in MPI_Bcast()\n");
MPI_Abort(MPI_COMM_WORLD, rc);
}
//Slaves
const float pi = 4 * atan(1.0);
const float G = 6.67 * pow(10,-11);
float a_x, a_y;
for (int i = 0 ; i < n; i++) {
if (rank != i){
a_x = G * system[i][2] * (system[i][0]-system[rank][0]) / ((system[i][0]-system[rank][0]) * (system[i][0]-system[rank][0]));
a_y = G * system[i][2] * (system[i][1]-system[rank][1]) / ((system[i][1]-system[rank][1]) * (system[i][1]-system[rank][1]));
}
if (rank == i){
a_x = G * system[i][2] * 100 * system[i][0] / (system[i][0] * system[i][0]);
a_y = G * system[i][2] * 100 * system[i][1] / (system[i][1] * system[i][1]);
}
a_x += a_x;
a_y += a_y;
}
for (int i=0; i < n; i++){
system[i][0] += system[i][5] * dt + 0.5 * a_x * dt * dt;
system[i][1] += system[i][6] * dt + 0.5 * a_y * dt * dt;
system[i][5] += a_x * dt;
system[i][6] += a_y * dt;
}
for(int i=0 ; i<n ; i++){
for(int j=0 ; j<i ; j++){
if (system[j][0] == 0 && system[j][1] == 0){
system.erase(system.begin() + j);
} // crash into star
if (system[j][0] == system[i][0] && system[j][1] == system[i][1]){
system[i][2] += system[j][2];
system.erase(system.begin() + j);
} // planet crash
} //check co-ordinates
} // planet destroy loop
for(int i = 0 ; i < n ; i++){
if (sqrt(system[i][0]*system[i][0] + system[i][1]*system[i][1]) >= 60) system.erase(system.begin() + i);
}
//Send results back to the first process
if (rank != 0){// All processes except the one of rank 0
MPI_Send(&system, 1, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD);
}
else {
for (int j = 1; j < numtasks; j++) {
MPI_Recv(&system, 1, MPI_DOUBLE, MPI_ANY_SOURCE, 1,
MPI_COMM_WORLD, &status);
}
}
MPI_Finalize();
///////////////////////////
//Time advances the solar system.
//Plots the Orbits
//Uses MPI to spread it's calculations.
///////////////////////////
return system;
}
////////////
////////////
std::vector<bool> FinalCheck( std::vector<std::vector<float>> system, std::vector<bool> Water, int n){
///////////////////////////
//Final Checks
//Reports if a Planet spent the whole Time in the Habitable Zone
///////////////////////////
for (int i = 0 ; i < n ; i++){
if (system[i][4] == 1.0) Water.push_back(true);
else Water.push_back(false);
}
return Water;
}
////////////
////////////
int main(int argc, char** argv){
char Class;
float L, R, M, T;
std::tuple< char , float , float , float , float > star( Class , L , R , M , T );
star = Star();
int n = MyRandom()/10 + 1;
std::vector<std::vector <float>> system ;
std::vector<std::vector <float>> system1 ;
system = Planet( L , R , M, T, n);
float G = 6.67 * pow(10,-11), pi = 4 * atan(1.0), dt;
for (int i = 0; i < n; i++){
if (system[i][3] == 1){
dt = 2 * pi * .01 * pow(system[i][0] * 1.5 * pow(10,8), 1.5) / sqrt(G * M * 2 * pow(10,30));
}
system[i].push_back(0.0); //system[i][5] is speed in x-axis
system[i].push_back( sqrt(6.67 * pow(10,-11) * 2 * pow(10,30) * M / system[i][0])); //system[i][6] is speed in y-axis
}
std::ofstream Finder;
std::ofstream Report;
Finder.open("plotdata.dat");
Report.open("report.txt");
Finder << "# Plot Co-ordinates" << std::endl;
for (int i = 0 ; i < 1000 ; i++) {
system1 = Time( system, n , dt , argc, argv);
for (int j=0 ; j<n ; j++){
Finder << "[color " << j << "] " << system[j][0] << " " << system[j][1] << std::endl;
if((system[j][4] == 1.0) && ( (sqrt(system[j][0] * system[j][0] + system[j][1] * system[j][1]) < sqrt(L / 1.1) ) || ((sqrt(system[j][0] * system[j][0] + system[j][1] * system[j][1]) > sqrt(L / 0.53)) ))) system[j][4] = 0.0;
}
system = system1;
}
Finder.close();
int m;
m = system.size()/system[0].size();
std::vector<bool> Water;
Water = FinalCheck( system, Water, n);
//Report
for (int i = 0 ; i < n ; i++){
Report << "Planet " << i << "ends up at" << system[i][0] << " and " << system[i][1] << "has mass " << system[i][2] ;
if (system[i][3] == 1) Report << ", which is the 'Jupiter' of the system." ;
if (system[i][4] == 1) Report << ", which can have liquid water on the surface." ;
}
Report.close();
///////////////////////////
//Report cleans everything up and gives the results
//Shows the plot, lists the Planets
//Reports the Positions and Masses of all Planets
//Reports which was the Jupiter and which if any were Habitable
//////////////////////////
return 0;
}
Any thoughts the gurus here have would be appreciated, especially with getting rid of those -fpermissive errors.
EDIT 1 - Code as presented will now completely compile - but will return a Segmentation fault during the Star routine. After the user inputs the star type but before it actually makes a star as far as I can tell.
I want to calculate value of x in this equation to 4 digits after the decimal with divide and conquer method.Values of p,q,r,s,t,u are input. How to do it in?
Time limits: 1 sec
Memory limits: 64 MB
float results[10000];
int n = 0;
for( float step = 0; i < 1; i+=0.00001 )
{
results[n] = callProblem( i );
}
some divide and conquer approach
float x = 0;
float diff = 1;//Startvalue
while( )
{
result = callProblem(x);
if( result > 0 )
{
x -= diff;
diff = diff/2;
result = callProblem(x);
}
else
{
x += diff;
diff = diff/2;
result = callProblem(x);
}
}
I have generalized the bisection method into an untested recursive multi-section method:
#include <math.h>
#include <stdio.h>
#include <time.h>
#define P 1.0
#define q 2.0
#define r 3.0
#define s 1.0
#define t 5.0
#define u -6.0
// number of sub-intervals in search interval
#define INTERVALS 10
// accuracy limit for recursion
#define EPSILON 1.0e-4
double f(double x) {
double y = P * exp(-x) + q*sin(x) + r*cos(x) + s*tan(x) + t*x*x + u;
return y;
}
// sign macro: -1 for val < 0, +1 for val > 0
#define SGN(val) ((0.0 < val) - (val < 0.0))
// return approximate x for function(x)==0.0
// "function" points to the function to be solved
double solve(double xMin, double xMax, double (*function)(double)) {
double arguments[INTERVALS + 1];
double values[INTERVALS + 1];
int prevSign;
int sign;
if (fabs(xMax - xMin) < EPSILON) {
// interval quite tight already
return (xMax + xMin) / 2.0;
}
// split the interval into sub-intervals
// evaluate the function for INTERVALS+1 equidistant points
// across our search interval
for (int i = 0; i <= INTERVALS; i++) {
double x = xMin + i*((xMax - xMin) / INTERVALS);
arguments[i] = x;
values[i] = function(x);
}
// look for adjacent intervals with opposite function value signs
// if f(Xi) and f(Xi+1) have different signs, the root must be
// between Xi and Xi+1
prevSign = SGN(values[0]);
for (int i = 1; i <= INTERVALS; i++) {
sign = SGN(values[i]);
if (sign * prevSign == -1) {
// different signs! There must be a solution
// Shrink search interval to the detected sub-interval
double x = solve(arguments[i - 1], arguments[i], function);
return x;
}
// remember sign for next round
prevSign = sign;
}
// no solution found: return not-a-number
return NAN;
}
int main(unsigned argc, char **argv) {
clock_t started = clock();
clock_t stopped;
double x = solve(0.0, 1.0, &f);
if (isnan(x)) {
printf("\nSorry! No solution found.\n");
} else {
printf("\nOK! Solution found at f(%f)=%f\n", x, f(x));
}
stopped = clock();
printf("\nElapsed: %gs", (stopped - started) / (double)CLOCKS_PER_SEC);
// wait for user input
getchar();
}
I am having trouble explaining/understanding the following phenomenon:
To test fftw3 i am using the 2d poisson test case:
laplacian(f(x,y)) = - g(x,y) with periodic boundary conditions.
After applying the fourier transform to the equation we obtain : F(kx,ky) = G(kx,ky) /(kx² + ky²) (1)
if i take g(x,y) = sin (x) + sin(y) , (x,y) \in [0,2 \pi] i have immediately f(x,y) = g(x,y)
which is what i am trying to obtain with the fft :
i compute G from g with a forward Fourier transform
From this i can compute the Fourier transform of f with (1).
Finally, i compute f with the backward Fourier transform (without forgetting to normalize by 1/(nx*ny)).
In practice, the results are pretty bad?
(For instance, the amplitude for N = 256 is twice the amplitude obtained with N = 512)
Even worse, if i try g(x,y) = sin(x)*sin(y) , the curve has not even the same form of the solution.
(note that i must change the equation; i divide by two the laplacian in this case : (1) becomes F(kx,ky) = 2*G(kx,ky)/(kx²+ky²)
Here is the code:
/*
* fftw test -- double precision
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fftw3.h>
using namespace std;
int main()
{
int N = 128;
int i, j ;
double pi = 3.14159265359;
double *X, *Y ;
X = (double*) malloc(N*sizeof(double));
Y = (double*) malloc(N*sizeof(double));
fftw_complex *out1, *in2, *out2, *in1;
fftw_plan p1, p2;
double L = 2.*pi;
double dx = L/(N - 1);
in1 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*(N*N) );
out2 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*(N*N) );
out1 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*(N*N) );
in2 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*(N*N) );
p1 = fftw_plan_dft_2d(N, N, in1, out1, FFTW_FORWARD,FFTW_MEASURE );
p2 = fftw_plan_dft_2d(N, N, in2, out2, FFTW_BACKWARD,FFTW_MEASURE);
for(i = 0; i < N; i++){
X[i] = -pi + i*dx ;
for(j = 0; j < N; j++){
Y[j] = -pi + j*dx ;
in1[i*N + j][0] = sin(X[i]) + sin(Y[j]) ; // row major ordering
//in1[i*N + j][0] = sin(X[i]) * sin(Y[j]) ; // 2nd test case
in1[i*N + j][1] = 0 ;
}
}
fftw_execute(p1); // FFT forward
for ( i = 0; i < N; i++){ // f = g / ( kx² + ky² )
for( j = 0; j < N; j++){
in2[i*N + j][0] = out1[i*N + j][0]/ (i*i+j*j+1e-16);
in2[i*N + j][1] = out1[i*N + j][1]/ (i*i+j*j+1e-16);
//in2[i*N + j][0] = 2*out1[i*N + j][0]/ (i*i+j*j+1e-16); // 2nd test case
//in2[i*N + j][1] = 2*out1[i*N + j][1]/ (i*i+j*j+1e-16);
}
}
fftw_execute(p2); //FFT backward
// checking the results computed
double erl1 = 0.;
for ( i = 0; i < N; i++) {
for( j = 0; j < N; j++){
erl1 += fabs( in1[i*N + j][0] - out2[i*N + j][0]/N/N )*dx*dx;
cout<< i <<" "<< j<<" "<< sin(X[i])+sin(Y[j])<<" "<< out2[i*N+j][0]/N/N <<" "<< endl; // > output
}
}
cout<< erl1 << endl ; // L1 error
fftw_destroy_plan(p1);
fftw_destroy_plan(p2);
fftw_free(out1);
fftw_free(out2);
fftw_free(in1);
fftw_free(in2);
return 0;
}
I can't find any (more) mistakes in my code (i installed the fftw3 library last week) and i don't see a problem with the maths either but i don't think it's the fft's fault. Hence my predicament. I am all out of ideas and all out of google as well.
Any help solving this puzzle would be greatly appreciated.
note :
compiling : g++ test.cpp -lfftw3 -lm
executing : ./a.out > output
and i use gnuplot in order to plot the curves :
(in gnuplot ) splot "output" u 1:2:4 ( for the computed solution )
Here are some little points to be modified :
You need to account for all small frequencies, including the negative ones ! Index i corresponds to the frequency 2PI i/N but also to the frequency 2PI (i-N)/N. In the Fourier space, the end of the array matters as much as the beginning ! In our case, we keep the smallest frequency : it's 2PI i/N for the first half of the array, and 2PI(i-N)/N on the second half.
Of course, as Paul said, N-1 should be Nin double dx = L/(N - 1); => double dx = L/(N ); N-1 does not correspond to a continious periodic signal. It woud be hard to use it as a test case...
Scaling...I did it empirically
The result i obtain is closer to the expected one, for both cases. Here is the code :
/*
* fftw test -- double precision
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fftw3.h>
using namespace std;
int main()
{
int N = 128;
int i, j ;
double pi = 3.14159265359;
double *X, *Y ;
X = (double*) malloc(N*sizeof(double));
Y = (double*) malloc(N*sizeof(double));
fftw_complex *out1, *in2, *out2, *in1;
fftw_plan p1, p2;
double L = 2.*pi;
double dx = L/(N );
in1 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*(N*N) );
out2 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*(N*N) );
out1 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*(N*N) );
in2 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*(N*N) );
p1 = fftw_plan_dft_2d(N, N, in1, out1, FFTW_FORWARD,FFTW_MEASURE );
p2 = fftw_plan_dft_2d(N, N, in2, out2, FFTW_BACKWARD,FFTW_MEASURE);
for(i = 0; i < N; i++){
X[i] = -pi + i*dx ;
for(j = 0; j < N; j++){
Y[j] = -pi + j*dx ;
in1[i*N + j][0] = sin(X[i]) + sin(Y[j]) ; // row major ordering
// in1[i*N + j][0] = sin(X[i]) * sin(Y[j]) ; // 2nd test case
in1[i*N + j][1] = 0 ;
}
}
fftw_execute(p1); // FFT forward
for ( i = 0; i < N; i++){ // f = g / ( kx² + ky² )
for( j = 0; j < N; j++){
double fact=0;
in2[i*N + j][0]=0;
in2[i*N + j][1]=0;
if(2*i<N){
fact=((double)i*i);
}else{
fact=((double)(N-i)*(N-i));
}
if(2*j<N){
fact+=((double)j*j);
}else{
fact+=((double)(N-j)*(N-j));
}
if(fact!=0){
in2[i*N + j][0] = out1[i*N + j][0]/fact;
in2[i*N + j][1] = out1[i*N + j][1]/fact;
}else{
in2[i*N + j][0] = 0;
in2[i*N + j][1] = 0;
}
//in2[i*N + j][0] = out1[i*N + j][0];
//in2[i*N + j][1] = out1[i*N + j][1];
// in2[i*N + j][0] = out1[i*N + j][0]*(1.0/(i*i+1e-16)+1.0/(j*j+1e-16)+1.0/((N-i)*(N-i)+1e-16)+1.0/((N-j)*(N-j)+1e-16))*N*N;
// in2[i*N + j][1] = out1[i*N + j][1]*(1.0/(i*i+1e-16)+1.0/(j*j+1e-16)+1.0/((N-i)*(N-i)+1e-16)+1.0/((N-j)*(N-j)+1e-16))*N*N;
//in2[i*N + j][0] = 2*out1[i*N + j][0]/ (i*i+j*j+1e-16); // 2nd test case
//in2[i*N + j][1] = 2*out1[i*N + j][1]/ (i*i+j*j+1e-16);
}
}
fftw_execute(p2); //FFT backward
// checking the results computed
double erl1 = 0.;
for ( i = 0; i < N; i++) {
for( j = 0; j < N; j++){
erl1 += fabs( in1[i*N + j][0] - out2[i*N + j][0]/(N*N))*dx*dx;
cout<< i <<" "<< j<<" "<< sin(X[i])+sin(Y[j])<<" "<< out2[i*N+j][0]/(N*N) <<" "<< endl; // > output
// cout<< i <<" "<< j<<" "<< sin(X[i])*sin(Y[j])<<" "<< out2[i*N+j][0]/(N*N) <<" "<< endl; // > output
}
}
cout<< erl1 << endl ; // L1 error
fftw_destroy_plan(p1);
fftw_destroy_plan(p2);
fftw_free(out1);
fftw_free(out2);
fftw_free(in1);
fftw_free(in2);
return 0;
}
This code is far from being perfect, it is neither optimized nor beautiful. But it gives almost what is expected.
Bye,
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;
}
Does someone know where i can get code or a library to perform the Goertzel algorithm with a complex output?
(or any other 1-bin-DFT algorithm?)
The following is code that I wrote do this, some several years ago. Feel free to use it as you wish, with appropriate attribution.
goertzelfilter.h
/* goertzelfilter.h
*/
#ifndef GOERTZELFILTER_H_
#define GOERTZELFILTER_H_
#include <complex.h>
typedef struct goertzelfilterstruct {
double coeff ;
double sine ;
double cosine ;
} GoertzelFilter;
GoertzelFilter goertzelSetup( double normalizedfreq );
double complex goertzelFilterC( double *sample, int nsamples, GoertzelFilter *g );
#endif
goerzelfilter.c
/* goertzelfilter.c
*/
#include <math.h>
#include <stdlib.h>
#include <complex.h>
#include "goertzelfilter.h"
GoertzelFilter goertzelSetup( double normalizedfreq )
{
double w = 2*M_PI*normalizedfreq;
double wr, wi;
GoertzelFilter g;
wr = cos(w);
wi = sin(w);
g.coeff = 2 * wr;
g.cosine = wr;
g.sine = wi;
return g;
}
double complex goertzelFilterC( double *samples, int nsamples, GoertzelFilter *g )
{
double sprev = 0.0;
double sprev2 = 0.0;
double s, imag, real;
int n;
for (n=0; n<nsamples; n++ ) {
s = samples[n] + g->coeff * sprev - sprev2;
sprev2 = sprev;
sprev = s;
}
real = sprev*g->cosine - sprev2;
imag = -sprev*g->sine;
return real + I*imag;
}
And for a test, you can try this,
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include "goertzelfilter.h"
#define LEN(a) (sizeof(a)/sizeof(a[0]) )
int main() {
// This will hold our input and output data
double data[1024] = { 0. };
double complex filtered[1024] = { 0. };
// This will hold the filter constants
GoertzelFilter g = { 0. };
int n;
int nwindow = 16;
double f = 4./LEN(data) ;
// Generate data with noise
for ( n = 0 ; n < LEN(data) ; n++ ) {
data[n] = sin( n * (2.*M_PI) * f ) + 0.5*((float)rand()/RAND_MAX - 0.5);
}
// Set up the filter constants, note that we choose a frequency
g = goertzelSetup( f );
// Filter the data using a sliding window
for( n = 0 ; n < LEN(data)-nwindow ; n++ ) {
filtered[n+nwindow/2] = goertzelFilterC( &data[n], nwindow, &g )/nwindow;
}
// Print the real Valued Data (1st column) and complex valued Goertzel output
for( n = 0 ; n < LEN(data); n++ ) {
printf( "%g %g %g\n", data[n], creal(filtered[n]), cimag(filtered[n]) );
}
}
And here is a graph showing the input and output from the test code: