Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  1 778
Heisann freaks! I dag satt jeg meg ned for å rutte med å lage et program som outputter en sinusbølge, det kan jo brukes til så mangt. Det jeg ønsket her var å gjøre slik at jeg kan bestemme frekvensen på bølgen (hz - svingninger per sekund), og det er jo i teorien rimelig enkelt.

* Finne ut hvor lenge programmet har kjørt i millisekunder
(ikke POSIX, har brukt UNIX standard funksjoner, skal du prøve i windows så bytter du ut min milliseconds() med GetTickCount())
* Dele på 1000 for å få tallet i rekkeviden 0 - 1
* Multiplisere med frekvens, sørge for at tallet fremdeles er mellom 0 - 1 (i "graderegning" er 0.2 rotasjoner det samme som 1.2 rotasjoner, osv)
* Multiplisere med 2*pi for å få det i rekkevidden 0 - 2*pi (= konvertere til radianer)
* Regne ut sinus av dette tallet
* Konvertere til ønsket output-form

Og det har jeg gjort - men denne bølgen viste seg å være en smule motvillig. Den fungerer smertefritt på alt fra 0hz til omlag 10hz - så slutter den enkelt og greit å fungere som den skal. På 1000hz får jeg en output hvor alle tallene nesten ikke endrer seg, uavhengig av eksterne faktorer (ting påvirket av tid). Jeg merker at på 999hz beveger bølgen seg som en 1hz bølge, bare i negativ retning.

Og her er hele koden:

Kode

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sys/time.h>

/*
 * Name:	Wave
 * By:		Ratpoison
 * Description:	Produces an [X]hz sine wave and outputs to stdout
 */

int milliseconds()
{
	struct timeval tv;
	struct timezone tz;
	int result;

	gettimeofday(&tv, &tz);
	result = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);

	return result;
}

double pi ()
{
	double x=0, y=0, pi, i;

	y = sqrt(0.5);
	x = 0.5;

	for(i = 1; i<20; i++)
	{
		y = (1 - sqrt(1 - y * y)) / (1 + sqrt(1 - y * y));
		x = (pow((1 + y), 2) * x) - pow(2, i) * y;
		pi = 1.0/x;
	}

	return pi;
}

int main(int argc, char** argv)
{
	long long base_time, now_time, prev_time;
	double pos, rad;
	float freq;
	int outdata;
	char* outstring = (char*)malloc(1024);

	if (argc == 2)
	{
		if (sscanf(argv[1], "%f", &freq) == 0)
			goto failure;
	}
	else
	{
failure:
		printf("Frequency not specified\n%s freq\nUsing default value: 1\n",
				argv[0]);
		freq = 1;
	}

	base_time = milliseconds();
	prev_time = base_time;

	while(1)
	{
		int c;

		now_time = milliseconds();

		if (!((now_time - prev_time) > 20))
			goto notthisround;

		prev_time = now_time;

		//Calculate angle in radians, one round per second and multiply by hz
		rad = ((now_time - base_time) / 1000.0) * freq;
		while (rad >= 1.0) rad -= 1.0; //Make it within range 0-1
		rad *= 2.0 * pi();

		//Calculate the sine wave
		pos = sin(rad);

		//Calculate the data to write
		outdata = ((pos + 1.0) / 2.0) * 80;

		for (c=0; c<outdata; c++)
		{
			outstring[c] = '#';
		}
		outstring[c+1] = '\0';

		printf("%f:\t\t%s\n", (rad/(2*pi()))*360, outstring);
notthisround:
		c=c;	//Refuses to compile without action after label

//		putchar(outdata);
	}

	free(outstring);

	return 0;
}
Til syvende og sist er poenget at programmet skal sende ut sinusverdien konvertert til 1, 2 eller 4 bytes til stdout.
Output av programmet slik det er nå er ca. slik (1hz, tick på 20ms, debug info til venstre er antall grader):

Kode

4.320000:		############################################
15.120000:		###################################################
26.280000:		##########################################################
36.720000:		################################################################
47.520000:		######################################################################
58.320000:		###########################################################################
69.120000:		##############################################################################
79.920000:		###############################################################################
90.720000:		###############################################################################
101.520000:		###############################################################################
112.320000:		##############################################################################
123.120000:		##########################################################################
133.920000:		#####################################################################
144.720000:		################################################################
155.520000:		#########################################################
166.320000:		##################################################
177.120000:		###########################################
187.920000:		###################################
198.720000:		############################
209.520000:		#####################
220.320000:		###############
231.120000:		#########
241.920000:		#####
253.080000:		##
263.520000:		#
274.320000:		#
285.120000:		#
295.560000:		####
306.360000:		########
317.160000:		#############
327.960000:		###################
338.760000:		##########################
349.560000:		#################################
0.360000:		#########################################
11.160000:		################################################
22.320000:		########################################################
33.120000:		##############################################################
43.920000:		####################################################################
54.720000:		#########################################################################
65.520000:		#############################################################################
76.320000:		##############################################################################
87.120000:		###############################################################################
97.920000:		###############################################################################
108.720000:		##############################################################################
119.520000:		###########################################################################
130.320000:		#######################################################################
Så - er det noen kloke hoder som vet hvorfor bølgen ikke vil regnes ut ordentlig på de høyere frekvensene?
Det har lite hensikt å vise output av hva som skjer da, ettersom det omtrent bare er flate data (og gradene er 0, med unntak av 2-3 steder der de står på 360).
m0b
m0b's Avatar
DonorAdministrator
Artig at du får benyttet matematikkevner i programmet ditt, samtidig som du leker med C. Jeg vil dog fraråde deg å benytte goto statements, det ødelegger en del programflyt. Regelen sier vel at dersom du kommer i en posisjon hvor du føler at du må bruke en goto statement, så bør du heller omskrive rutinen og unngå dette. Er det noen spesiell grunn til at du velger å kalkulere pi feil enn å lage deg en variabel med korrekt verdi?

Hva problemet ditt angår, antar jeg at det bunner ned til disse linjene

Kode

		rad = ((now_time - base_time) / 1000.0) * freq;
		
		while (rad >= 1.0) 
			rad -= 1.0; //Make it within range 0-1
I et eksempel hvor jeg kjører på min maskin så ser jeg at now_time - base_time = 31 på første iterasjon. Jeg bytter ut ting med virkelige verdier, og tar utganspunkt i 999hz og gir deg sourcen på nytt.

Kode

		30.969= ((31) / 1000.0) * 999;
		
		while (30.969>= 1.0) 
			rad -= 1.0; //Make it within range 0-1
		
//		rad = 0.969
Men hva skjer når frekvensen når opp mot 1000?

Kode

		31 = ((31) / 1000.0) * 1000;
		
		while (31 >= 1.0) 
			rad -= 1.0; //Make it within range 0-1

//		rad = 0
rad blir i dette tilfellet alltid et heltall, og dermed alltid konstant ved rad *= 2.0 * pi();

Ellers, hva kalkuleringen på høyere frekvenser angår - jeg antar at dette har med samme effekten som skjer når du f.eks ser på et hjul som roterer. Som når hjulet roterer så fort at det virker som om det står i ro eller går baklengs fordi øyets oppdateringsfrekvens harmonerer med hvor langt en del av hjulet har rotert iløpet av oppdateringstiden.
Sist endret av m0b; 21. mars 2008 kl. 16:07.