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:
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):
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).
* 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; }
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: #######################################################################
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).