I a have a 2D double complex array of size 1001(rows)*144(columns) in C. I want to apply FFT on each of the rows and finally want the output in 4096*144 format. Here N point = 4096. Finally compare the result with matlab ouput.
I am using renowned FFTW C library. I have read the tutorials but could not understand how to use properly. Which routine I should use, Like 1D routine or 2D routine and then how?
#Update
double complex reshaped_calib[1001][144]={{1.0 + 0.1 * I}};
double complex** input; //[4096][144];
// have to take dynamic array as I was getting segmentation fault here
input = malloc(4096 * sizeof(double complex*));
for (i = 0; i < 4096; i++) {
input[i] = malloc(144* sizeof(double complex));
}
// input is array I am sending to fftw to apply fft
for (i= 0; i< 1001; i++)
{
for (j= 0; j< 144; j++)
{
input[i][j]=reshaped_calib[i][j];
}
}
// Pad the extra rows
for (i= 1001; i< 4096; i++)
{
for (j= 0; j< 144; j++)
{
input[i][j] = 0.0;
}
}
int N=144, howmany=4096;
fftw_complex* data = (fftw_complex*) fftw_malloc(N*howmany*sizeof(fftw_complex));
i=0,j=0;
int dataCount=0;
for(i=0;i<4096;i++)
{
for(j=0;j<144;j++)
{
data[dataCount++]=CMPLX(creal(input[i][j]),cimag(input[i][j]));
}
}
int istride=1, idist=N;// as in C data as row major
// ... if data is column-major, set istride=howmany, idist=1
// if data is row-major, set istride=1, idist=N
fftw_plan p = fftw_plan_many_dft(1,&N,howmany,data,NULL,howmany,1,data,NULL,howmany,1,FFTW_FORWARD,FFTW_MEASURE);
fftw_execute(p);
Your attempt at padding the array with
int pad = 4096;
memset(reshaped_calib, 0.0, pad * sizeof(double complex)); //zero padding
essentially overwrites the first 4096 values of the array reshaped_calib. For proper padding, you would instead need to extend the size of the 2D array to your required size of 4096 x 144, and set to zero only the entries outside the input's 1001 x 144 range.
Since you are only extending the number of rows, the following could be used for the padding:
double complex input[1001][144]={{1.0 + 0.1 * I}};
// Allocate storage for the larger 4096x144 2D size, and copy the input.
double complex reshaped_calib[4096][144];
for (int row = 0; row < 1001; row++)
{
for (int col = 0; col < 144; col++)
{
reshaped_calib[row][col] = input[row][col];
}
}
// Pad the extra rows
for (int row = 1001; row < 4996; row++)
{
for (int col = 0; col < 144; col++)
{
reshaped_calib[row][col] = 0.0;
}
}
That said, if you want 1D FFT of each of the rows separately, you should instead use fftw_plan_dft_1d and call fftw_execute multiple times, or otherwise use fftw_plan_many_dft. This is described in more details in this answer by #Dylan.
Related
I'm trying to multiply two dynamic matrices by passing them through a function. I'm getting a segmentation fault during the multiplication.
The matrices are being passed through a function. The items in the arguments are correct because I had to use them for a different operation in this project. I have a feeling that I messed up with the pointers, but i'm pretty new to C and i'm not sure where I messed up.
double** multiplyMatrices(
double** a,
const uint32_t a_rows,
const uint32_t a_cols,
double** b,
const uint32_t b_cols){
uint32_t i = 0;
uint32_t j = 0;
uint32_t k = 0;
double** c;
//allocate memory to matrix c
c = (double **)malloc(sizeof(double *) * a_rows);
for (i = 0; i < a_rows; i++) {
*(c +i) = (double *)malloc(sizeof(double) * b_cols);
}
//clear matrix c
for(i = 0; i < a_rows; i++){
for(j = 0; j < a_cols; j++){
*c[j] = 0;
}
}
i = 0;
//multiplication
while(j = 0, i < a_rows ){
while(k = 0, j < b_cols){
while(k < a_cols){
//following line is where i'm getting the segmentation fault
*(*(c+(i*b_cols))+j) += (*(*(a+(i*a_cols))+k)) * (*(*(b+(k*b_cols))+j));
k++;
}
j++;
}
i++;
}
return c;
}
The obvious mistake is that you dereference c + i * b_cols while c is an array of pointers of size a_rows. So likely c + i * b_cols is outside of the area that you previously allocated with malloc().
I would suggest to simplify the matrix representation using a single array of double with the size equal to the total number of elements, i.e. rows * cols.
For example:
double *c;
c = malloc(sizeof(double) * a_rows * b_cols);
This not only has better overall performance, but simplifies the code. You would then have to "linearise" the offset inside your unidimensional array to convert from bi-dimensional matrix coordinates. For example:
c[i * b_cols + j] = ...
Of course, the other two matrices need to be allocated, filled and accessed in a similar manner.
For code clarity, I would also replace the while statements by for statements with the actual variable that they loop on. For example:
for (i = 0; i < a_rows; i++)
for (j = 0; j < b_cols; j++)
for (k = 0; k < a_cols; k++)
You can (ab)use the C language in many ways, but the trick is to make it more clear for you in the first place.
I am trying to optimise the divide operation from the Jacobi relaxation formula.
Also doing profiling using perf.
Here is my code
for (int l = 0; l < iter; l++) {
for (i = 1; i < height; i++) {
for (j = 1; j < width; j++) {
for (k = 1; k < length; k++) {
float val = 0.0f;
// Do the Jacobi additions here
// From profiling, fastest is to fetch k+/-1,j,i
// Slowest is to fetch k,j,i+/-1
// Scale with dimensions of the array
val -= dim * array[k][j][i];
// Want to optimise this
val /= 6.0; // profiling shows this as the slowest op
// Some code here to put the result into the output array
}
}
}
}
The size of the 3D array can be from 100x100x100 up to 1000x1000x1000.
I've tried to multiply it to 1.0f/6.0f but this does not seem to make a difference. The array is a 3D array of floats.
As an example here, I am creating a 2d array of doubles of 1000 by 2 and filling out every spot in the 2d array with 222222.0
What's really weird is that if I go for example to array[999][1000], I get 222222.0
But if I make my array size say only 100 by 2, this doesn't happen and if I try array[99][10], I just get 0.0
What's going on? Why do I get this "leakage"?
int N = 1000;
int dimension = 2;
double** nums = malloc(sizeof(double*) * N);
for(int i = 0; i < N; i++)
nums[i] = malloc(sizeof(double) * dimension);
for (int k = 0; k < dimension; k++)
for (int i = 0; i < N; i++)
nums[i][k] = 222222;
printf("%f\n", nums[99][1000]);
222222.000000
Huh?
I have been looking for a way to swap the names between two matrices in C. I have 2 square size x size matrices. I make some operation to the one of them, I put the result in a cell in the other matrix, then I swap their names and I repeat.
Below I am giving my code
int main(void){
int const size = 1000;
int const steps = 10;
float A[size][size], B[size][size];
int i,j,k;
int t = 0;
double sum = 0;
double sum1 = 0;
int const ed = size - 1;
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){// initialize the matrices
A[i][j] = i+j;
B[i][j] = 0;
}
}
for(i = 0; i < size; ++i){//find the sum of the values in the first matrix
for(j = 0; j < size; ++j){
sum = sum + A[i][j];
}
}
printf("The total sum of the matrix 1 is %lf \n",sum);
for(k = 0; k < steps; ++k){//for each cell of the matrix A calculate the average of the values' of the cell and its surroundings and put it in the coresponding place in the matrix B and then copy matrix B to matrix A and repeat. There are special cases for the cells who are at the edges and the last or first row/column.
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){
if(i==0){
if(j==0)
B[i][j]=(A[0][0]+A[0][1]+A[0][ed]+A[1][0]+A[ed][0])/5.0;
else if(j==ed)
B[i][j]=(A[0][ed]+A[0][0]+A[0][ed-1]+A[1][ed]+A[ed][ed])/5.0;
else
B[i][j]=(A[0][j]+A[0][j+1]+A[0][j-1]+A[1][j]+A[ed][j])/5.0;
}else if(i==ed){
if(j==0)
B[i][j]=(A[ed][0]+A[ed][1]+A[ed][ed]+A[0][0]+A[ed-1][0])/5.0;
else if(j==ed)
B[i][j]=(A[ed][ed]+A[ed][0]+A[ed][ed-1]+A[0][ed]+A[ed-1][ed])/5.0;
else
B[i][j]=(A[ed][j]+A[ed][j+1]+A[ed][j-1]+A[0][j]+A[ed-1][j])/5.0;
}else{
if(j==0)
B[i][j]=(A[i][0]+A[i][1]+A[i][ed]+A[i+1][0]+A[i-1][0])/5.0;
else if(j==ed)
B[i][j]=(A[i][ed]+A[i][0]+A[i][ed-1]+A[i+1][ed]+A[i-1][ed])/5.0;
else
B[i][j]=(A[i][j]+A[i][j+1]+A[i][j-1]+A[i+1][j]+A[i-1][j])/5.0;
}
}
}
sum1 = 0;
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){
sum1 = sum1 + B[i][j];
}
}
t=t+1;
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){
A[i][j] = B[i][j];
}
}
printf("%lf \n",sum1-sum);
}
printf("The total sum of the matrix 2 is %lf \n",sum1);
printf("Number of steps completed: %i \n",t);
printf("Number of steps failed to complete: %i \n", steps-t);
return 0;
}
I have used the method of copying each time the one matrix to the other, but this is not efficient.
I have a hint that I should use pointers but I can not figure it out. Any help will be much appreciated.
You can swap the values of any two variables of the same type by assigning the value of the first to a temporary variable then assigning the value of the second to the first, then assigning the value of the temporary variable to the second:
int a = 2, b = 3, tmp;
tmp = a;
a = b;
b = tmp;
In particular, it works exactly the same when the variables are of pointer type, so
/* The matrices */
double one[3][3], another[3][3];
/* pointers to the matrices */
double (*matrix1p)[3] = one;
double (*matrix2p)[3] = another;
double (*tmp)[3];
/* ... perform matrix operations using matrix1p and matrix2p ... */
/* swap labels (pointers): */
tmp = matrix1p;
matrix1p = matrix2p;
matrix2p = tmp;
/* ... perform more matrix operations using matrix1p and matrix2p ... */
Updated to clarify:
matrix1p is initially an alias for one, and matrix2p is initially an alias for another. After the swap, matrix1p is an alias for another, whereas matrix2p is an alias for one. Of course, you can perform such a swap as many times as you want. You cannot, however, swap one and another themselves, except via an element-by-element swap.
Note that this yields improved efficiency because pointers are quite small relative to the matrices themselves. You don't have to move the elements of the matrices, but only to change which matrix each pointer refers to.
Yes, you should definitely use pointers, for example:
void swap (int*** m1, int*** m2)
{
int** temp;
temp = *m1;
*m1 = *m2;
*m2 = temp;
}
And then invoke:
int m1[5][5] = 0;
int m2[5][5] = 0;
swap (&m1, &m2);
I'm trying to multiply two multidimensional arrays to form a matrix. I have this function. This should work in theory. However, I am just getting 0s and large/awkward numbers. Can someone help me with this?
int **matrix_mult( int **a, int **b, int nr1, int nc1, int nc2 )
{
int **c;
int i,j,k,l;
c = malloc(sizeof(int *)*nr1);
if (c == NULL){
printf("Insuff memm");
}
for(l=0;l<nr1;l++){
c[l] = malloc(sizeof(int)*nc1);
if (c[l] == NULL){
printf("Insuff memm");
}
}//for loop
for (i=0;i<nr1;i++){
for (j=0;j<nc2;j++){
for (k=0;k<nc1;k++){
c[i][j] = (a[i][k]) * (b[k][j]);
}
}
}
return( c );
}
Are you doing mathematical matrix multiplication? If so shouldn't it be:
for(i = 0; i < nr1; i++)
{
for(j = 0; j < nc1; j++)
{
c[i][k] = 0;
for(k = 0; k < nc2; k++)
{
c[i][k] += (a[i][j]) * (b[j][k]);
}
}
}
My full and final solution, tested to produce sensible results (I didn't actually do all the calculations myself manually to check them) and without any sensible niceties such as checking memory allocations work, is:
int **matrix_mult(int **a, int **b, int nr1, int nc1, int nc2)
{
int **c;
int i, j, k;
c = malloc(sizeof(int *) * nr1);
for (i = 0; i < nr1; i++)
{
c[i] = malloc(sizeof(int) * nc2);
for (k = 0; k < nc2; k++)
{
c[i][k] = 0;
for (j = 0; j < nc1; j++)
{
c[i][k] += (a[i][j]) * (b[j][k]);
}
}
}
return c;
}
There were a few typos in the core of the for loop in my original answer, mostly due to my being mislead by a different answer. These have been corrected for posterity.
If you change c[i][j] = (a[i][k]) * (b[k][j]); to c[i][j] += (a[i][k]) * (b[k][j]); in your code then it will work just fine provided that
nr1 is number of rows of matrix a
nc1 is the number of columns of the matrix a
nc2 is the number of columns of the matrix b
Just be sure that the matrix c is initiated with zeroes. You can just use calloc instead of malloc when allocating space, or memset the allocated array after a call to malloc.
One more tip is to avoid using the letter l when accessing array elements. when tired, you will have hard time noticing errors with l vs 1.