I'm trying to construct and use a basic audio resampler, taking WAVE file as input, resampling it to defined fs and returning resampled file. The code runs, but it generates inaudible output file that cannot be opened by Windows Media Player. I honestly don't know what causes this.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "wavfile.h"
#define FRAME_SIZE 256
void resample(float *in, float *out, int inputFrameSize, int outputFrameSize, float inputFs, float outputFs, float *index, float firstsampleofthenextframe)
{
float increment = inputFs/outputFs;
int i;
float frac;
int intp;
for (i=0;i<outputFrameSize;i++)
{
if ((*index) < inputFrameSize - 1) {
//linear interpolation
intp = (int)(*index);
frac = (*index) - (float)intp;
out[i] = frac * in[intp+1] + (1.0-frac) * in[intp];
} else { //index between inputFrameSize-2 and inputFrameSize-1
intp = (int)(*index);
frac = (*index) - (float)intp;
out[i] = frac * firstsampleofthenextframe + (1.0-frac) * in[intp];
}
//left_out[i] = 0.2*sin(0.001*3.141592635*(*index));
(*index) += increment;
}
}
int main()
{
struct wavfile_header readh;
struct wavfile_header writeh;
float left_in[FRAME_SIZE];
float right_in[FRAME_SIZE];
float left_out[FRAME_SIZE*2];
float right_out[FRAME_SIZE*2];
//float *left_out;
//float *right_out;
float indexL, indexR; //sample index used for interpolation
FILE * infile;
FILE * outfile;
fpos_t position;
int numBytes, numFrames;
int i;
int outFrameSize;
readh.num_channels = 2;
readh.sample_rate = 44100;
writeh.num_channels = 2;
writeh.sample_rate = 48000;
outFrameSize = (int)((float)FRAME_SIZE * (float)(writeh.sample_rate) / (float)(readh.sample_rate));
//left_out = (float*) malloc(sizeof(float)*outFrameSize);
//right_out = (float*) malloc(sizeof(float)*outFrameSize);
infile = wavfile_open_read("input.wav", &readh);
if(!infile) {
printf("read error");
return 1;
}
outfile = wavfile_open_write("output.wav", &writeh);
if(!outfile) {
printf("write error");
return 1;
}
//main processing loop
numBytes = readh.riff_length;
numFrames = numBytes / (2*FRAME_SIZE);
indexL = indexR = 0.f; //start from the 0th sample of the input signal
while(numFrames > 0)
{
float left_overlap, right_overlap;
short sl, sr;
for(i=0;i<FRAME_SIZE;i++) //read frame
{
short sleft, sright;
fread(&sleft ,sizeof(short),1, infile); //deinterleave samples
fread(&sright ,sizeof(short),1, infile);
fflush(infile);
left_in[i] = sleft * 0.0000305185f; // * (1/32767) - 16-bit input automatically normalized to (-1, 1)
right_in[i] = sright * 0.0000305185f; // * (1/32767) - 16-bit input automatically normalized to (-1, 1)
numBytes -= 4;
}
fgetpos (infile, &position);
//one sample ahead is needed to interpolate
fread(&sl ,sizeof(short),1, infile); //deinterleave samples [warning: bug if the input file length is an exact number of frames]
fread(&sr ,sizeof(short),1, infile);
left_overlap = sl * 0.0000305185f; // * (1/32767) - 16-bit input automatically normalized to (-1, 1)
right_overlap = sr * 0.0000305185f; // * (1/32767) - 16-bit input automatically normalized to (-1, 1)
fsetpos (infile, &position);
resample(left_in, left_out, FRAME_SIZE, outFrameSize, 44100, 48000, &indexL, left_overlap);
resample(right_in, right_out, FRAME_SIZE, outFrameSize, 44100, 48000, &indexR, right_overlap);
indexL -= (int)indexL;
indexR -= (int)indexR;
for(i=0;i<outFrameSize;i++) //read frame
{
short left, right;
//left_out[i] = 0.5;
//right_out[i] = 0.5;
left = (short)(left_out[i] * 32767.f);
right = (short)(right_out[i] * 32767.f);
fwrite(&left ,sizeof(short),1, outfile); //deinterleave samples
fwrite(&right ,sizeof(short),1, outfile);
numBytes -= 4;
}
fflush(outfile);
numFrames--;
}
/*
while(numBytes > 0)
{
//below: temp
short left, right;
//left_out[i] = 0.5;
//right_out[i] = 0.5;
left = left_out[i] * 32767;
right = right_out[i] * 32767;
fwrite(&left ,sizeof(short),1, outfile); //deinterleave samples
fwrite(&right ,sizeof(short),1, outfile);
numBytes--;
}
*/
fflush(outfile);
//free(left_out);
//free(right_out);
fclose(outfile);
fclose(infile);
return 0;
}
Related
I've coded a simple sequencer in C with SDL 1.2 and SDL_mixer(to play .wav file). It works well and I want to add some audio synthesis to this program. I've look up the and I found this sinewave code using SDL2(https://github.com/lundstroem/synth-samples-sdl2/blob/master/src/synth_samples_sdl2_2.c)
Here's how the sinewave is coded in the program:
static void build_sine_table(int16_t *data, int wave_length)
{
/*
Build sine table to use as oscillator:
Generate a 16bit signed integer sinewave table with 1024 samples.
This table will be used to produce the notes.
Different notes will be created by stepping through
the table at different intervals (phase).
*/
double phase_increment = (2.0f * pi) / (double)wave_length;
double current_phase = 0;
for(int i = 0; i < wave_length; i++) {
int sample = (int)(sin(current_phase) * INT16_MAX);
data[i] = (int16_t)sample;
current_phase += phase_increment;
}
}
static double get_pitch(double note) {
/*
Calculate pitch from note value.
offset note by 57 halfnotes to get correct pitch from the range we have chosen for the notes.
*/
double p = pow(chromatic_ratio, note - 57);
p *= 440;
return p;
}
static void audio_callback(void *unused, Uint8 *byte_stream, int byte_stream_length) {
/*
This function is called whenever the audio buffer needs to be filled to allow
for a continuous stream of audio.
Write samples to byteStream according to byteStreamLength.
The audio buffer is interleaved, meaning that both left and right channels exist in the same
buffer.
*/
// zero the buffer
memset(byte_stream, 0, byte_stream_length);
if(quit) {
return;
}
// cast buffer as 16bit signed int.
Sint16 *s_byte_stream = (Sint16*)byte_stream;
// buffer is interleaved, so get the length of 1 channel.
int remain = byte_stream_length / 2;
// split the rendering up in chunks to make it buffersize agnostic.
long chunk_size = 64;
int iterations = remain/chunk_size;
for(long i = 0; i < iterations; i++) {
long begin = i*chunk_size;
long end = (i*chunk_size) + chunk_size;
write_samples(s_byte_stream, begin, end, chunk_size);
}
}
static void write_samples(int16_t *s_byteStream, long begin, long end, long length) {
if(note > 0) {
double d_sample_rate = sample_rate;
double d_table_length = table_length;
double d_note = note;
/*
get correct phase increment for note depending on sample rate and table length.
*/
double phase_increment = (get_pitch(d_note) / d_sample_rate) * d_table_length;
/*
loop through the buffer and write samples.
*/
for (int i = 0; i < length; i+=2) {
phase_double += phase_increment;
phase_int = (int)phase_double;
if(phase_double >= table_length) {
double diff = phase_double - table_length;
phase_double = diff;
phase_int = (int)diff;
}
if(phase_int < table_length && phase_int > -1) {
if(s_byteStream != NULL) {
int16_t sample = sine_wave_table[phase_int];
sample *= 0.6; // scale volume.
s_byteStream[i+begin] = sample; // left channel
s_byteStream[i+begin+1] = sample; // right channel
}
}
}
}
}
I don't understand how I could change the sinewave formula to genrate other waveform like square/triangle/saw ect...
EDIT:
Because I forgot to explain it, here's what I tried.
I followed the example I've seen on this video series(https://www.youtube.com/watch?v=tgamhuQnOkM). The source code of the method provided by the video is on github, and the wave generation code is looking like this:
double w(double dHertz)
{
return dHertz * 2.0 * PI;
}
// General purpose oscillator
double osc(double dHertz, double dTime, int nType = OSC_SINE)
{
switch (nType)
{
case OSC_SINE: // Sine wave bewteen -1 and +1
return sin(w(dHertz) * dTime);
case OSC_SQUARE: // Square wave between -1 and +1
return sin(w(dHertz) * dTime) > 0 ? 1.0 : -1.0;
case OSC_TRIANGLE: // Triangle wave between -1 and +1
return asin(sin(w(dHertz) * dTime)) * (2.0 / PI);
}
Because the C++ code here uses windows soun api I could not copy/paste this method to make it work on the piece of code I've found using SDL2.
So I tried to this in order to obtain a square wave:
static void build_sine_table(int16_t *data, int wave_length)
{
double phase_increment = ((2.0f * pi) / (double)wave_length) > 0 ? 1.0 : -1.0;
double current_phase = 0;
for(int i = 0; i < wave_length; i++) {
int sample = (int)(sin(current_phase) * INT16_MAX);
data[i] = (int16_t)sample;
current_phase += phase_increment;
}
}
This didn't gave me a square wave but more a saw wave.
Here's what I tried to get a triangle wave:
static void build_sine_table(int16_t *data, int wave_length)
{
double phase_increment = (2.0f * pi) / (double)wave_length;
double current_phase = 0;
for(int i = 0; i < wave_length; i++) {
int sample = (int)(asin(sin(current_phase) * INT16_MAX)) * (2 / pi);
data[i] = (int16_t)sample;
current_phase += phase_increment;
}
}
This also gave me another type of waveform, not triangle.
You’d replace the sin function call with call to one of the following:
// this is a helper function only
double normalize(double phase)
{
double cycles = phase/(2.0*M_PI);
phase -= trunc(cycles) * 2.0 * M_PI;
if (phase < 0) phase += 2.0*M_PI;
return phase;
}
double square(double phase)
{ return (normalize(phase) < M_PI) ? 1.0 : -1.0; }
double sawtooth(double phase)
{ return -1.0 + normalize(phase) / M_PI; }
double triangle(double phase)
{
phase = normalize(phase);
if (phase >= M_PI)
phase = 2*M_PI - phase;
return -1.0 + 2.0 * phase / M_PI;
}
You’d be building tables just like you did for the sine, except they’d be the square, sawtooth and triangle tables, respectively.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I need to estimate for my internship the firing rate of neurons that follows an ODE. I code at first in python and it goes pretty well but for better performance, my supervisor told to write the same code in C. However, I never coded in C so I am a very beginner and the file in which i want to have the values for the firing rate is full of zero... Can someone help me ?
Thank you very much
So here is my 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
eps = 0.05
f = 0.215
mu = 1.1
D = 0.001
DeltaT = 0.01
timewindow = 40
num_points = int(timewindow/DeltaT)
T = np.linspace(0, timewindow, num_points)
#signal
s = [sin(2*3.14*f*t) for t in T]
N=30000
compteur=np.zeros(num_points)
v = np.zeros((num_points,N))
samples = np.random.normal(0, 1, (num_points,N))
for i in range(1,num_points):
for j in range(N):
v[i,j] = v[i-1,j] + DeltaT *(-v[i-1,j]+ mu + eps*s[i-1]) + \
sqrt(2*D*DeltaT)*samples[i,j]
if v[i,j]>1:
v[i,j]=0
compteur[i]+=1/DeltaT/N
plt.plot(T,compteur)
plt.show()
and here is my "translation" in C :
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PI 3.1415926536
float s(float x, float);
double AWGN_generator();
FILE* fopen(const char* nomDuFichier, const char* modeOuverture);
int fclose(FILE* pointeurSurFichier);
int main(int argc, char *argv[])
{
//parameters
double eps = 0.05;
float f = 0.215 ;
double mu = 1.1 ;
double D = 0.001 ;
int time_window = 90;
int num_points = 1000;
long num_neurons = 1000;
double deltaT = time_window/num_points;
int i ;
//time
double Time[num_points] ;
Time[0]= 0.0;
for (i = 1 ; i < num_points ; i++ )
{ Time[i] = Time[i-1] + deltaT;
}
//opening file for saving data
FILE* fichier = NULL;
fichier = fopen("challala.txt", "w");
if (fichier != NULL)
{
double v[num_points][num_neurons] ;
memset(v, 0, num_points*num_neurons*sizeof(long) );
long compteur[num_points];
memset( compteur, 0, num_points*sizeof(long) );
int pos_1 ;
int pos_2 ;
//Euler's method
for (pos_1 = 1 ; pos_1 < num_points ; pos_1 ++)
{
for (pos_2 = 0 ; pos_2<num_neurons ; pos_2 ++)
{
float t = Time[pos_1-1] ;
v[pos_1][pos_2] = v[pos_1-1][pos_2] + deltaT *(-v[pos_1-1]
[pos_2]+ mu + eps*s(t, f))+ sqrt(2*D*deltaT)*AWGN_generator();
if (v[pos_1][pos_2]>1)
{
v[pos_1][pos_2]=0 ;
compteur[pos_1]+=1/deltaT/num_neurons ;
}
}
fprintf(fichier, "%ld",compteur[pos_1]);
}
fclose(fichier);
printf("ca a marche test.txt");
}
else
{
// On affiche un message d'erreur si on veut
printf("Impossible d'ouvrir le fichier test.txt");
}
return 0;
}
float s(float x, float f)
{
return sin(2*M_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
}
Code repaired as able with old code commented out. See comments for change details.
Need to see challala.txt for a definitive test.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Why use a coarse approximation?
//#define PI 3.1415926536
#define PI 3.1415926535897932384626433832795
// Let us stick to double only.
//float s(float x, float);
double s(double x, double);
// Add void, else declaration does not check the parameters.
//double AWGN_generator();
double AWGN_generator(void);
// These should have already been declared in <stdio.h>
// FILE* fopen(const char* nomDuFichier, const char* modeOuverture);
// int fclose(FILE* pointeurSurFichier);
int main(int argc, char *argv[]) {
//parameters
double eps = 0.05;
// float f = 0.215;
double f = 0.215;
double mu = 1.1;
double D = 0.001;
int time_window = 90;
// Unclear why `int/long` used here. size_t would be idiomatic for array sizing.
int num_points = 1000;
long num_neurons = 1000;
// Avoid integer division when a FP quotinet is desired
// double deltaT = time_window / num_points;
double deltaT = 1.0*time_window / num_points;
int i;
//time
double Time[num_points];
Time[0] = 0.0;
for (i = 1; i < num_points; i++)
{
Time[i] = Time[i - 1] + deltaT;
}
//opening file for saving data
FILE* fichier = NULL;
fichier = fopen("challala.txt", "w");
if (fichier != NULL) {
double v[num_points][num_neurons];
// zero fill use wrong type in sizeof.
// Avoid type in sizeof, better to use sizeof object
// memset(v, 0, num_points * num_neurons * sizeof(long));
memset(v, 0, sizeof v);
// Let us use FP here.
//long compteur[num_points];
double compteur[num_points];
memset(compteur, 0, sizeof compteur);
int pos_1;
int pos_2;
//Euler's method
for (pos_1 = 1; pos_1 < num_points; pos_1++)
{
for (pos_2 = 0; pos_2 < num_neurons; pos_2++) {
// float t = Time[pos_1 - 1];
double t = Time[pos_1 - 1];
v[pos_1][pos_2] = v[pos_1 - 1][pos_2]
+ deltaT * (-v[pos_1 - 1][pos_2] + mu + eps * s(t, f))
+ sqrt(2 * D * deltaT) * AWGN_generator();
if (v[pos_1][pos_2] > 1) {
v[pos_1][pos_2] = 0;
compteur[pos_1] += 1 / deltaT / num_neurons;
}
}
// Change of type
// fprintf(fichier, "%ld", compteur[pos_1]);
fprintf(fichier, " %g", compteur[pos_1]);
}
fclose(fichier);
printf("ca a marche test.txt");
} else {
// Was not the file another name?
// printf("Impossible d'ouvrir le fichier test.txt");
printf("Impossible d'ouvrir le fichier \"%s\"\n", challala.txt);
}
return 0;
}
//float s(float x, float f) {
double s(double x, double f) {
// M_PI is not defined in the standard C library, although common in extensions.
//return sin(2 * M_PI * f * x);
return sin(2 * PI * f * x);
}
double AWGN_generator() {
double temp1;
double temp2;
double result;
int p;
p = 1;
while (p > 0) {
temp2 = (rand() / ((double) RAND_MAX));
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
}
Minor and advanced numeric issue:
Realize that quotient 1.0*time_window / num_points maybe be a little different than mathematical expected due to finite precision of double. This is, at worst, expected to be a very small amount, maybe about 0.5 parts in 253.
Yet the repetitive additions accumulate the error.
double deltaT = 1.0*time_window / num_points;
int i;
double Time[num_points];
Time[0] = 0.0;
for (i = 1; i < num_points; i++) {
Time[i] = Time[i - 1] + deltaT;
}
To avoid that accumulated error, code can re-calculate Time[i] anew on each iteration.
double deltaT = 1.0*time_window / num_points;
double Time[num_points];
for (int i = 0; i < num_points; i++) {
Time[i] = deltaT*i;
}
Of course, such small errors are often ignorable, but mayne not when num_points is large enough. This happens when your good code is applied to ever larger tasks.
regarding the following 3 statements
int time_window = 90;
int num_points = 1000;
double deltaT = time_window/num_points;
Since time_window and num_points are integers, the division is performed as an integer divide.
In an integer divide, all fractions are truncated.
the expression: time_window/num_points is actually:
90 / 1000
the resulting fraction has everything right of the decimal point truncated, so the result is 0
so: Time[0] + 0 results in 0.0.
The same (calculated) value: 0.0 is then propagated thorough the whole array
suggest changing:
int time_window = 90;
int num_points = 1000;
to
double time_window = 90.0;
double num_points = 1000.0;
regarding:
memset(v, 0, num_points*num_neurons*sizeof(long) );
this statement may (or may not) perform the desired functionality. It depends on if the size of double is the same as the size of long
Suggest using:
memset( v, 0, sizeof( v ) );
We know the streight line that mspaint can draw into a picture. Since nested loops fill the whole area (x/y) i was wondering whats the way of doing this. Drawing a line from (x0 y0) of the image to desired x/y. Im using this function for finding the x/y pixel of the bmp:
dword find (FILE* fp, dword xp, dword yp)
{
word bpx = (3*8);
dword offset = (2+sizeof(BMP)+sizeof(DIB));
dword w = 500;
dword row = (((bpx * w) * 4) / 32);
dword pixAddress = (offset) + row * yp + ((xp * bpx) / 8);
return pixAddress;
}
And I've tried with many functions for drawing line from 0x0 to xy, their results are close.. but not entirely.
byte color_pattern[] = { 255, 255, 255 };
dword xy_offset[] = {1, 1};
void bmp_lineto(dword endx, dword endy)
{
int dx = endx - xy_offset[0];
int dy = endy - xy_offset[1];
int twody = 2 * dy;
int twodxdy = 2 * (dy - dx);
int dp = twody - dx;
int X, Y, xEnd, yEnd;
FILE* fp = fopen(convert(FILENAME.text), "rb+");
if(xy_offset[0] > endx)
{
X = endx;
Y = endy;
xEnd = xy_offset[0];
}
else
{
X = xy_offset[0];
Y = xy_offset[1];
xEnd = endx;
}
while(X < xEnd)
{
X = X + 1;
if(dp < 0)
{
dp = dp + twody;
} else { Y = Y + 1; dp = dp + twodxdy;
}
fseek(fp, find(fp, X, Y), SEEK_SET);
fwrite(&color_pattern, 1, 3, fp);
}
}
But the result on the bmp from this code is so... uncertain:
bmp_lineto(200, 230); The entire image is x500 : y460
UPDATED. The y coordinate is same as x. Thats the problem
Take a look at the following code - I adapted this from Rosetta Code
#include <stdio.h>
#include <stdlib.h>
#define NX 40
#define NY 20
typedef unsigned char byte;
typedef struct {
int x;
int y;
} point;
typedef struct{
char M[NX][NY];
} bitmap;
void drawLine(point *a, point*b, bitmap *B, FILE* fp, byte *color_pattern) {
int x0 = a->x, y0 = a->y;
int x1 = b->x, y1 = b->y;
int dx = abs(x1-x0), sx = (x0<x1) ? 1 : -1;
int dy = abs(y1-y0), sy = (y0<y1) ? 1 : -1;
int err = (dx>dy ? dx : -dy)/2, e2;
int index;
while(1){
// the next three lines put the pixel right in the file:
index = (y0 * NX + x0)*3;
fseek(fp, index, SEEK_SET);
fwrite(color_pattern, 1, 3, fp);
B->M[x0][y0]=1; // for code testing
if (x0==x1 && y0==y1) break;
e2 = err;
if (e2 >-dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
void printLine(bitmap *B){
int ii, jj;
for(ii=0; ii<NY; ii++) {
for(jj=0; jj<NX; jj++) {
printf("%d", (int)B->M[jj][ii]);
}
printf("\n");
}
}
int main(void) {
FILE *fp;
point start = {34,7};
point end = {14, 17};
bitmap B;
byte color[]={255,255,255};
// initialize map to zero. Want to do same with file I suppose
int ii, jj;
for(ii=0; ii<NX; ii++) {
for(jj=0; jj<NY; jj++) {
B.M[ii][jj]=0;
}
}
fp = fopen("mypicture.bmp", "wb");
drawLine(&start, &end, &B, fp, color);
printLine(&B);
fclose(fp);
}
I think it should be easy to adapt it for your situation. Note I have tried to separate / localize variables a little more - that is usually a good idea; there are still many ways to further improve this code (this is a situation where C++ might be a better language...)
Output of the above:
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000001100000
0000000000000000000000000000000110000000
0000000000000000000000000000011000000000
0000000000000000000000000001100000000000
0000000000000000000000000110000000000000
0000000000000000000000011000000000000000
0000000000000000000001100000000000000000
0000000000000000000110000000000000000000
0000000000000000011000000000000000000000
0000000000000001100000000000000000000000
0000000000000010000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
Looks like the "right" line to me... even though it's got the X going in the negative direction. That's the advantage of starting with proven code (in this case, Bresenham's algorithm as implemented on Rosettacode).
You can look into Bresenham's line algorithm. There are extensions to it that handle anti-aliasing too.
I have a program which has the following function to write to a tiff file. However, the files produced are not recognized by any picture viewing software. What is wrong in this code, why is it not producing proper tiff files? Note that it uses the libtiff library.
long WriteGrayscaleTIFF(char *filename, long width,
long height, long scanbytes, unsigned char *data)
{
long y;
double factor;
long c;
unsigned long cmap[256]; /* output color map */
TIFF *outimage; /* TIFF image handle */
/* create a grayscale ramp for the output color map */
factor = (double)((1 << 16) - 1) / (double)((1 << 8) - 1);
for (c = 0; c < 256; c++)
cmap[c] = (long)(c * factor);
/* open and initialize output file */
if ((outimage = TIFFOpen(filename, "w")) == NULL)
return(0);
TIFFSetField(outimage, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(outimage, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(outimage, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(outimage, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(outimage, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(outimage, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
TIFFSetField(outimage, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
TIFFSetField(outimage, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
TIFFSetField(outimage, TIFFTAG_COLORMAP, cmap, cmap, cmap);
/* write the image data */
printf( "height = %d, width = %d!\n", height, width );
for (y = 0; y < height; y++) {
if (!TIFFWriteScanline(outimage, data, y, 0))
{
printf( "TIFFClose!\n" );
TIFFClose(outimage);
return(0);
}
data += scanbytes;
}
/* close the file */
TIFFClose(outimage);
return(1);
}
I am changing the phase of signal from 0 to 360 by each degree to get max voltage value.Because if i change phase of the signal the voltage also changes.I have the fallowing code to find max value.
void Maxphase(float *max, unsigned int *index)
{
*max = 0.0;
float value;
unsigned int i, data;
for (i=0;i<=360;i++)
{
phaseset(i);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > *max) //find max value
{
*max = value; //max voltage
*index = i;
}
}
}
from the above code I am getting Max value(voltage) after 38 sec(360*100) because for every read operation my device needs 100ms delay. This is too large, I can't change hardware thus i want to get the max value within 2 to 3 sec by optimizing software.
then I have tried with the fallowing code.
void Maxphase(float *max1, unsigned int *index1)
{
max = 0.0;
float value;
unsigned int i,j,data;
for (i=0;i<=360;i+=10)
{
phaseset(i);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > max) //find max value
{
max = value; //max voltage
index = i;
}
}
*max1=max;
*index1=index;
for (i=*index1-9;i<=*index1+9;i+=1)
{
j=i;
phaseset(j);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > *max1) //find max value
{
*max1 = value; //max voltage
*index1 = i;
}
}
}
I have reduced time from 45 sec to 7 sec. i have reduced iterations 360 to 54(54*100). I want to reduce it 7 sec to 2 sec.
Can any one help me with better algorithm that i can get max value from (0 to 360) with in 2 sec.
I have measured the voltage values using scope by changing phase. I have written below how it vary voltage with phase.
Phase (degree) voltage(max)
0 0.9mv
45 9.5mv
90 9.0mv
135 0.9mv
180 292mv
225 601mv
270 555mv
315 230mv
360 0.9mv
I am new to C programming. Can anyone provide sample code for the best algorithm.
Golden section search is probably what you are after. It is effective, but still pretty simple.
If you want something even faster and more sophisticated, you can use Brent's method.
If you can be sure that there is only a single highest point on your 360 degrees you can do a recursive divide and conquer.
You start by looking e.g. at 0, 180, 270. Let's say you find the answer is that 180 + 270 together have the highest value. Than you start by looking in at 210.... Which side is higher? And so on ...
Exploiting the various comments and suggestions here, I present this untested piece of code. I don't know whether this works at all or is an improvement over the existing source, but it was fun to try, anyway:
extern void phaseset(int);
extern void delay_ms(int);
extern float readvalue();
extern float voltage(int);
extern int mux1;
float probe(int phase)
{
float data;
phaseset(phase);
delay_ms(100);
data = readvalue(); /* data is ignored? */
return voltage(mux1); /* mux1? */
}
/* helper routine, find the max in a given range [phase1, phase2] */
void maxphase_aux(int phase1, float vol1, int phase2, float vol2, int *phaseret, float *volret)
{
float xvol1 = 0, xvol2 = 0;
int xphase1 = -1, xphase2 = -1;
/* test the voltage in the middle */
int phasem = abs(phase2 - phase1) / 2;
float volm = probe(phasem);
if (volm > vol1 && volm > vol2) {
/* middle point is the highest so far,
* search left and right for maximum */
*volret = volm;
*phaseret = phasem;
maxphase_aux(phase1, vol1, phasem, volm, &xphase1, &xvol1);
maxphase_aux(phase2, vol2, phasem, volm, &xphase2, &xvol2);
} else if (volm < vol1 && volm > vol2) {
/* vol1 is the highest so far,
* search between volm and vol1 for maximum */
maxphase_aux(phase1, vol1, phasem, volm, &xphase1, &xvol1);
} else if (volm > vol1 && volm < vol2) {
/* vol2 is the highest so far,
* search between volm and vol2 for maximum */
maxphase_aux(phase2, vol2, phasem, volm, &xphase2, &xvol2);
} else {
/* not possible? */
return;
}
if (xvol1 > volm) {
*volret = xvol1;
*phaseret = xphase1;
}
if (xvol2 > volm) {
*volret = xvol2;
*phaseret = xphase2;
}
}
void maxphase(int *phaseret, float *volret)
{
float v0 = probe(0);
float v360 = probe(360);
maxphase_aux(0, v0, 360, v360, phaseret, volret);
}
UPDATE: 2012-11-10.
#include <stdio.h>
#include <string.h>
#include <math.h>
#define FAKE_TARGET 89
unsigned fake_target = FAKE_TARGET;
float probe_one(unsigned int phase);
void Maxphase(float *max, unsigned int *index);
void Maxphase(float *max, unsigned int *index)
{
unsigned int aim, idx, victim;
struct best {
unsigned pos;
float val;
} samples[4] = {{0, 0.0}, };
for (aim = 0;aim < 360;aim += 90) {
idx=aim/90;
samples[idx].pos = aim;
samples[idx].val = probe_one(samples[idx].pos);
if (!idx || samples[idx].val < samples[victim].val ) victim = idx;
}
/* eliminate the weakist postion, and rotate the rest,
** such that:
** samples[0] := lower boundary.
** samples[1] := our best guess
** samples[2] := upper boundary
** samples[3] := scratch/probe element
*/
fprintf(stderr, "Victim=%u\n", victim );
switch(victim) {
case 0: samples[0] = samples[1]; samples[1] = samples[2]; samples[2] = samples[3]; break;
case 1: samples[1] = samples[3]; samples[3] = samples[0]; samples[0] = samples[2]; samples[2] = samples[3]; break;
case 2: samples[2] = samples[1]; samples[1] = samples[0]; samples[0] = samples[3]; break;
case 3: break;
}
/* Calculation is easier if the positions are increasing.
** (We can always perform the modulo 360 if needed)
*/
if (samples[0].pos > samples[1].pos ) samples[1].pos += 360;
if (samples[1].pos > samples[2].pos ) samples[2].pos += 360;
while( 1) {
int step;
step = samples[2].pos - samples[0].pos;
if (step < 3) break;
do {
fprintf(stderr, "\n[%u %u %u] Diff=%d\n"
, samples[0].pos , samples[1].pos , samples[2].pos , step);
if (step > 0) step++; else step--;
step /= 2;
aim = (samples[0].pos + step ) ;
/* avoid hitting the middle cell twice */
if (aim %360 != samples[1].pos %360) break;
step += 1;
aim = (samples[0].pos + step ) ;
if (aim %360 != samples[1].pos %360) break;
step -= 2;
aim = (samples[0].pos + step ) ;
break;
} while(0);
fprintf(stderr, "Step=%d Aim=%u, Idx=%u\n",step, aim,idx );
samples[3].pos = aim;
samples[3].val = probe_one( samples[3].pos );
victim= (samples[3].pos > samples[1].pos ) ? 2 : 0;
if (samples[3].val > samples[1].val) idx= 1; else idx = victim;
fprintf(stderr, "Victim=%u, TargetIdx=%u\n", victim, idx );
/* This should not happen */
if (samples[3].val < samples[victim].val) break;
if (idx != victim) samples[2-victim] = samples[idx];
samples[idx] = samples[3];
}
*max = samples[1].val;
*index = samples[1].pos % 360;
}
float probe_one(unsigned int phase)
{
float value;
#ifdef FAKE_TARGET
int dif;
dif = fake_target-phase;
if (dif < -180) dif = 360+dif;
else if (dif > 180) dif = 360-dif;
/* value = 1.0 / (1 + pow(phase-231, 2)); */
value = 1.0 / (1 + pow(dif, 2));
fprintf(stderr, "Target = %d: Probe(%d:%d) := %f\n", fake_target, phase, dif, value );
sleep (1);
#else
unsigned int data;
phase %= 360;
phaseset(phase);
delay_ms(100);
data = readvalue(); // what is this ?
value = voltage(mux1);
#endif
return value;
}
int main(int argc, char **argv)
{
float value;
unsigned int index;
if (argv[1]) sscanf (argv[1], "%u", &fake_target);
fake_target %= 360;
Maxphase(&value, &index) ;
printf("Phase=%u Max=%f\n", index, value );
return 0;
}