【问题标题】:Issues trying to scale up sine wave in c尝试在 c 中扩大正弦波的问题
【发布时间】:2015-12-11 14:09:17
【问题描述】:

希望有人能指出为什么这不起作用或我可能出错的地方。我通过 c 中的 for 循环产生正弦波。最终目标是生成一个显示此内容的 .ppm 文件。我正在研究 1 比 1 的像素比。我的盒子是128H*256W。正弦波正在显示,但由于答案是以弧度产生的,结果是一个非常小的两个像素高的“波”。我认为这是由于 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

【问题讨论】:

  • 在转换为 int 之前,您应该将 y 乘以 50,例如y = (int) (50 * (H / 2 + sin(x * 2 * PI)));.
  • 您好,这个不会影响秤吗? *50 以便将我的 wav 的大小从它现在填充的 2 个像素中增加。
  • 如果你想要更少的“波峰”,你需要将你的 x 除以一些东西。请记住,当输入弧度时,sin(x) 将从 0 变为 1,变为 0,变为 -1 并返回 0,因为 x 从 0 变为 2*PI。如果 x 从 0 到 H 时你想要一个完整的 sin,你需要将 x 除以 H*2*PI
  • 您好,谢谢!我想要产生更明确的一次谐波正弦波。只要我至少有两个,峰值的数量就不是一个大问题。正如您提到的 sin(x) 仅在 rads 中有效,我认为这是我的循环问题,我认为,将一个像素等于一个值。我需要对其进行缩放以使值介于 1 和 -1 之间,但也会绘制更多可用的 128*256 像素。
  • 使用来自&lt;math.h&gt;M_PI

标签: c trigonometry


【解决方案1】:

我推测yint

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

解决方法很简单:对y 使用浮点数,并在您想将其用作数组索引时进行转换。

【讨论】:

  • 嗨。感谢您及时的回复!我的 y 被全局声明为 int 。我可以在本地将其更改为浮点数,并且可能使用不同的命名约定,但我的数组需要 y 是一个 int 才能工作。我可以把它转换回来吗?
  • 确实如此。使用 double 直到您需要将其用作数组索引。然后投它。 (但请检查它的尺寸是否合适在进行演员表之前。)
  • @superstuck 注意:不要对全局变量使用单字母名称。更一般地说,尽可能避免使用全局变量。 y 应该是本地的。
  • @Olaf 谢谢你的提示,我只是按照我以前教过的那种命名约定。
  • @superstuck:那你应该找一个更好的导师。
【解决方案2】:

由于ycommentedintH 似乎是一个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;
}

【讨论】:

  • 您好,再次感谢您的帮助。我目前的主要问题是 y 没有被绘制得足够多。当我能够放大它并且看起来像一系列破折号而不是实际波浪时,它丢失了一些点,这可能是由于截断问题吗?
  • @superstuck XScale 可能很粗糙。试试#define XScale (2*PI/64.0)
  • 我试过了,它似乎确实产生了更宽的 x 值。如何实现一些类似来增加 y?
  • @superstuck 增加y 尝试为YScale 设置不同的值,例如#define YScale 75
【解决方案3】:

一个更接近的近似值是这样的:

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;}
&lt;canvas id='c' width='256' height='128'&gt;&lt;/canvas&gt;

然后代码变成:

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;
}

【讨论】:

  • 嗨 Kenney,我认为你需要从 H 中取一个是正确的,因为我的轴在右上角有一个额外的像素。我的 Y 轴在大约四分之一处有一个台阶,所以我不确定循环是否从正确的点运行。
  • 您的主要问题是y *= 50,正如我在第一行所说的,而不是y 是否是int。您的 y 大约从 25*H 开始,这是 25 倍的溢出,导致 x 偏移。试过我的代码了吗?否则,请尝试将 x 从 0 循环到 10,以查看您的图表从左侧开始大约 20-25% 进入图像。
  • 我做的第一件事是删除 y*=50,因为这只是在黑暗中拍摄。我试过你的代码,它给了我类似的结果,因为它不会产生一个完整的波。我再次认为问题在于 pi 的工作方式以及 rads 是如何转换为 .ppm 的。如果 rads 只在 1 和 -1 之间起作用,那么只有两个像素的差异。这是我无法解决的问题。我相信有些学生已经开始使用负分数等来开始工作,但我不太了解这种方法或如何应用它。
  • 您将 x 从 0 迭代到 W,其中 W 为 256 或 image 宽度? image 是如何定义的,比如unsigned char image[H][W][3]?此外,rads 是sin 输入,从 0 到 2PI,表示从 0 到 360 度;递增 x 应该为每个正弦波提供大约 6 个点,足以识别它。您可以使用sin( x * 2*PI / 10) 来获得更宽的波浪,但是,您应该首先让它在图像的整个宽度上绘制。图像现在看起来如何?
  • 图像被定义为一个整数图像[y][x][3]。 W 是图像宽度,应该是 .ppm 文件中显示的像素数。它正在绘制全宽的线条,我的原始代码也在这样做,它的高度我没有得到我想要的。我只需要它完成 2 个完整波。
猜你喜欢
  • 2020-07-28
  • 1970-01-01
  • 1970-01-01
  • 2010-09-17
  • 2018-10-26
  • 1970-01-01
  • 1970-01-01
  • 2020-02-24
  • 1970-01-01
相关资源
最近更新 更多