尝试在c中扩大正弦波的问题

时间:2015-12-11 14:09:17

标签: c sin

希望有人可以指出为什么这不起作用或我可能出错的地方。我通过c中的for循环产生正弦波。最终目标是生成一个显示此文件的.ppm文件。我正在以1比1的像素比率工作。我的盒子是128H * 256W。正弦波正在显示,但由于以rad为单位产生的答案,结果是一个非常小的两像素高“波”。我认为这是由于rad值介于1和-1之间。这是我的代码。我试着简单地用一个更大的数字来计时,以增加y值的大小,希望它能正确地绘制,但是这样做很少或者更糟,导致应用程序停止运行。任何想法都非常受欢迎。

for (x = 0; x < H; x++)
    {

        y =(int) H/2+ sin(x*(2*PI));
        y = y * 50;
        image[y][x][1] = 0;
        image[y][x][2] = 255;
        image[y][x][3] = 0;
    }

编辑:这是通过infraview打开时在.ppm文件中生成的内容。另外我在#defining PI 3.141592653589793。这又可能是一个问题。

first sine wave .ppm

3 个答案:

答案 0 :(得分:1)

我认为yint

您的sin值将被截断为整数;大多数情况下为0,但偶尔为-1或+1。

修复很简单:对y使用浮点,并在想要将其用作数组索引时进行转换。

答案 1 :(得分:0)

y = y * 50,其中y = H/2(+或 - 1)为您提供25*H左右,超出范围。

更近似的是:

y = (int) ( H/2 + H/2 * sin(x*2*PI) )

给出了极值H/2 - H/2 = 0H/2 + H/2 = H,这是一个太高了。因此,我们不是按H/2而是按(H-1)/2进行扩展:

y = (int) ( H/2 + (H-1)/2 * sin(x*2*PI) )

为我们提供了y范围0H-1

为了更好地控制正弦波的周期,让我们这样写:

sin( x/W * 2*PI )

在此,我们将x除以W,以便x/W本身的范围为0到1。 然后由2*PI缩放以产生0到2π的范围。这将在整个宽度上绘制一个正弦波周期。如果我们引入频率因子f

sin( f * x/W * 2*PI )

我们现在可以说要绘制多少个时段,甚至是分数。对于f=1,它会绘制一个句点,f=2两个句点,f=1半个句点。

这是一个小型JS演示,显示f的三个值:0.5为红色,1为绿色,2为白色:

var c = document.getElementById('c'),
    W = c.width,
    H = c.height,
    ctx = c.getContext('2d'),
    image = ctx.getImageData(0,0,W,H);

for ( var i = 0; i < image.data.length; i +=4) {
 image.data[i+0]=0;
 image.data[i+1]=0;
 image.data[i+2]=0;
 image.data[i+3]=255;
}  



function render(image,colidx,f) {
  for ( var x = 0; x < W; x++ )
  {
    var y = H/2 - Math.round( H/2 * Math.sin(f*x/W*Math.PI*2) );
    if ( y >=0 && y < H ) {
      if ( colidx & 1 ) image.data[ 4*( W*y + x ) + 0] = 255;
      if ( colidx & 2 ) image.data[ 4*( W*y + x ) + 1] = 255;
      if ( colidx & 4 ) image.data[ 4*( W*y + x ) + 2] = 255;      
    }
  }
}
  
render(image,1,0.5);
render(image,2,1);
render(image,7,2);

ctx.putImageData(image, 0,0);
canvas{ border: 1px solid red;}
<canvas id='c' width='256' height='128'></canvas>

然后代码变为:

float f = 1;
for (x = 0; x < W; x++)
{
    y = (int) ( (H-1)/2 + (H-1)/2 * sin(f * x/W * 2*PI) );
    image[y][x][0] = 0;
    image[y][x][1] = 255;
    image[y][x][2] = 0;
}

答案 2 :(得分:0)

由于y commentedintH似乎是int常量,因此首先执行计算为double,然后转换为int

使用round可以避免简单地将double转换为int的截断效果。

y = (int) round(50*(sin(x*(2*PI)) + H/2.0));

原始代码也将H/2缩放了50.我认为代码可能只想缩放sin()而不是缩放。

#define XOffset 0
#define YOffset (H/2.0)
#define XScale (2*PI)
#define YScale 50
y = (int) round(YScale*sin(x*XScale + XOffset) + YOffset);

防御性编程提示:自y计算以来,确保它在使用它作为索引之前处于有效索引范围内。

// Assuming image` is a fixed sized array
#define Y_MAX (sizeof image/sizeof image[0] - 1)
if (y >= 0 && y <= Y_MAX) { 
  image[y][x][1] = 0;
  image[y][x][2] = 255;
  image[y][x][3] = 0;
}