使用正弦和余弦函数生成DMX数值。从8位(1个通道)到16位(两个通道)。

huangapple go评论59阅读模式
英文:

DMX-values using sine and cosine. From 8bit (1 channel) to 16bit (two channels)

问题

我目前正在开发一个小型项目,用于控制DMX灯光(使用Art-Net)。目前,我正在开发“运动生成器”,基本上是使用正弦和余弦来计算用于泛光和俯仰通道的DMX值(0-255),就像这个方法一样:

public void runSineMovement() {

    double degrees = x;
    double radians = Math.toRadians(degrees);
    double sine = Math.sin(radians);

    double dmxValue = (int) ((sine * 127) + 127);

    dmxValuesOBJ.setDmxValuesInArray(1, (int) dmxValue);

    SendArtnet.SendArtnetNow();

    x = x + 1;

    if (x > 360) {

        x = 1;

    }

}

x = 1

然后,我有一个ScheduledExecutorService,它将以固定的时间间隔调用该方法,就像这样:

int speed = 100;
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(SineMovement::runSineMovement, 0, 100000 * speed, TimeUnit.NANOSECONDS);

上述代码工作得很好,移动头(在这个示例中是俯仰通道)可以完美移动。现在,我想使用“fine通道”,即从8位到16位(从1个通道到2个通道控制俯仰通道),以便在非常慢的速度下也可以获得平滑的运动。请记住,“fine通道”必须首先从0到255,然后“coarse通道”可以从1开始,然后“fine通道”从0到255,然后“coarse通道”为2,依此类推。

以前,我使用“三角形效应”构建了一个运动生成器,其中我循环从0到65.536,然后再次从0开始,如此循环,每次运行时我计算了“coarse通道”(counter/256)和“fine通道”(counter % 256),这种方法运作良好。

在使用正弦和余弦生成效果时,有什么方法可以尝试吗?我是否可以使用三角形生成器的方法来计算“coarse”和“fine”通道,使用除法和模运算?

编辑:仔细考虑后,我认为“fine通道”不应该采用正弦波形式,我的意思是,如果使用正弦,那么“fine通道”将(如果使用正弦)非常非常快速,即向上和向下,如果“coarse通道”仍在向上,则会破坏事情。我想正确的方法是“fine通道”将始终具有锯齿形状 -> 当粗通道向上时,锯齿从零到最大,当粗通道向下时,锯齿从最大到零。这有道理吗?

谢谢 😊

英文:

I’m (still) working on a small project controlling DMX-lights (using Art-Net).
At the moment I’m working on the “Movement-generator” and what I basically do is to use sine and cosine to calculate the DMX values (0-255) for the pan- and tilt-channel, like with this method:

public void runSineMovement() {

    double degrees = x;
    double radians = Math.toRadians(degrees);
    double sine = Math.sin(radians);

    double dmxValue = (int) ((sine * 127) + 127);

    dmxValuesOBJ.setDmxValuesInArray(1, (int) dmxValue);

    SendArtnet.SendArtnetNow();

    x = x + 1;

    if (x > 360) {

        x = 1;

    }

}

x = 1

I then have a ScheduledExecutorService that will call that method on a regular interval, like this:

int speed = 100;
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(SineMovement::runSineMovement, 0, 100000 * speed, TimeUnit.NANOSECONDS);

Above is working just fine, moving head (tilt-channel in this example) is moving perfectly. Now I want to use the “fine-channel”, that is, go from 8bit to 16bit (from 1 channel to 2 channels controlling the tilt-channel) so I can get smooth movement even at very slow speed. Remember, "fine-channel" have to go from 0 to 255 first and then "coarse-channel" can go to 1, then "fine-channel" from 0 to 255 and then "coarse-channel" to 2, and so on.

Earlier I build a movement-generator with “triangle-effect” where I looped from 0 to 65.536 and back to 0 and so on, and on every run I calculated the “coarse-channel” (counter/256) and the “fine-channel” (counter % 256) and that approach is working just fine.

Any ideas on how to approach this when using sine and cosine when generating the effect? Can I use the approach from the triangle-generator calculating “coarse” and “fine” using division and modulus?

EDIT: When thinking about it, I don't think the "fine" should have the form as a sine-wave, I mean, the "fine" will (if using sine) go very, very, fast, both up and down, and that will mess things up if the "coarse" is still going "up". I guess the correct is that the "fine" will always have the sawtooth-shape -> sawtooth from zero to max when coarse is going up, and sawtooth from max to zero when coarse is going down. Does that makes sense?

Thanks 😊

答案1

得分: 3

以下是已翻译的内容:

public void runSineMovement() {

    x = (x + 1) % 360; // 这会增加 x 并在 0 到 359 之间“循环”

    double radians = Math.toRadians(x);
    double sine = Math.sin(radians);

    int dmxValue = (int) (sine * 32767.0 + 32767.0);

    int fineDmxValue = dmxValue & 255; // “低字节”
    int coarseDmxValue = (dmxValue >> 8) & 255; // “高字节”

    // TODO: 在这里设置您的 DMX 值并发送它们
}

在这段代码中,我进行了一些改进:

  1. 我用增量和模数计算替换了您的 x 值的增量和 if 语句。

  2. 我使用了改进的类型定义:

    • 在可能的情况下使用 double 常量(32767.0 而不是 32767),以便程序不在每次运行中将 int 强制转换为 double
    • 使用 int dmxValue 而不是多次强制转换为 int
  3. 对于您的粗略和精细值,我使用了更快的位移右>>)和二进制与&)运算符,而不是除法和模数运算。

精细值由您的数字的最低有效位组成,因此您可以使用二进制与运算符“掩码”掉所有其他位。

粗略值由数字的“其他” 8 位组成(您有效使用的 16 位值的最高有效位),因此您可以将它们右移 8 位(等于除以 2 的 8 次幂),然后 - 为了确保,再次掩码掉所有其他位。

不要混淆逻辑 AND&&)与此处使用的二进制 AND &,前者只能用于 boolean 值。

为什么会有效:精细值不会在粗略值更改时在 0 到 255 之间振荡(以正弦形式!),因为代码只计算一个正弦波,并将值“拆分”为精细和粗略。因此,如果 dmxValue 的值为 255,则将给您 fineDmxValue 为 255 和 coarseDmxValue 为 0。但对于 dmxValue 值为 256,fineDmxValue 将为 0,而 coarseDmxValue 将为 1。

精细和粗略的计算与您在 dmxValue 中生成波形的方式无关。

英文:

You should calculate the sine-wave just for the values 0 - 65535 and then use the splitting method you used for the triangle waveform to part it to the two channels like this:

public void runSineMovement() {

    x = (x + 1) % 360; // this increments x and "wraps around" between 0-359

    double radians = Math.toRadians(x);
    double sine = Math.sin(radians);

    int dmxValue = (int) (sine * 32767.0 + 32767.0);

    int fineDmxValue = dmxValue & 255; // "lowByte"
    int coarseDmxValue = (dmxValue >> 8) & 255; // "hiByte"

    // TODO: set your DMX values here and send them
}

In this code I used several improvements:

  1. I replaced your increment + if for the x value with an increment and a modulus calculation.

  2. I used improved typing:

    • double constants wherever possible (32767.0 instead of 32767) so the program doesn't cast the int to a double in each run.
    • have int dmxValue instead of casting to int multiple times.
  3. Instead of division and modulus for your coarse and fine values I used the faster bit shift right (>>) and binary and (&) operators.

The fine value consists of the 8 least significant bits of your number, so you can simply "mask out" all the others with a binary and operation.

The coarse value consist of the "other" 8 bits (most significant bits of a 16-bit value, that you are effectively using), so you can bring them 8 bits ot the right (equals a division by 2 to the power of 8), and then - just to make sure, again mask out all other bits.

Don't mix up the logical AND (&&) with the binary AND & used here, the former one can only be used with boolean values.

Why will this work: the fine value will not oscillate between 0 and 255 (in a sine form!) for each change of the coarse value, because the code calculates just one sine wave and "splits" the values into fine and coarse. So if you have e.g. a value of 255 for dmxValue, this will give you fineDmxValue as 255 and coarseDmxValue as 0. But for a value of 256 for dmxValue, the fineDmxValue will be 0 while the coarseDmxValue will be 1.

The calculation of fine and coarse is independent of the way you generate your waveform in dmxValue.

huangapple
  • 本文由 发表于 2023年2月16日 03:35:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定