如何在 C 中正确实现数字示波器的零交叉触发?
How can I properly implement zero cross triggering for digital oscilloscope in C?
所以我正在用 C 语言做一个简单的示波器。它从输出缓冲区读取音频数据(并在调用时删除缓冲区写入计数器,以便刷新缓冲区)。我尝试制作简单的零交叉触发,因为大多数时候用户会看到简单的(正弦波、脉冲波、锯齿波、三角波),但我使用下面的代码得到的最好结果是一个在其周期的一半时间来回跳跃的波.怎么了?
输入的信号从 -32768 变为 32767,因此应该为零。
如果你不明白我的意思可以看视频:click
更新:删除了与触发无关的代码,以便更容易理解所有功能。
extern Mused mused;
void update_oscillscope_view(GfxDomain *dest, const SDL_Rect* area)
{
if (mused.output_buffer_counter >= OSC_SIZE * 12) {
mused.output_buffer_counter = 0;
}
for (int x = 0; x < area->h * 0.5; x++) {
//drawing a black rect so bevel is hidden when it is under oscilloscope
gfx_line(domain,
area->x, area->y + 2 * x,
area->x + area->w - 1, area->y + 2 * x,
colors[COLOR_WAVETABLE_BACKGROUND]);
}
Sint32 sample, last_sample, scaled_sample;
for (int i = 0; i < 2048; i++) {
if (mused.output_buffer[i] < 0 && mused.output_buffer[i - 1] > 0) {
//here comes the part with triggering
if (i < OSC_SIZE * 2) {
for (int x = i; x < area->w + i; ++x) {
last_sample = scaled_sample;
sample = (mused.output_buffer[2 * x] + mused.output_buffer[2 * x + 1]) / 2;
if (sample > OSC_MAX_CLAMP) { sample = OSC_MAX_CLAMP; }
if (sample < -OSC_MAX_CLAMP) { sample = -OSC_MAX_CLAMP; }
if (last_sample > OSC_MAX_CLAMP) { last_sample = OSC_MAX_CLAMP; }
if (last_sample < -OSC_MAX_CLAMP) { last_sample = -OSC_MAX_CLAMP; }
scaled_sample = (sample * OSC_SIZE) / 32768;
if(x != i) {
gfx_line(domain,
area->x + x - i - 1, area->h / 2 + area->y + last_sample,
area->x + x - i, area->h / 2 + area->y + scaled_sample,
colors[COLOR_WAVETABLE_SAMPLE]);
}
}
}
return;
}
}
}
在调试期间,我简化了代码,直到它开始工作。谢谢克利福德。
我找到了一个触发器索引 i
(假设它是数组索引 300)。修改为示波器画线从[(2 * i) + offset]
到[(2 * i + 1) + offset]
,因此形成了错误的画面。
我用了(2 * i)
,因为我想让长波适合示波器。我将其替换为从 [i + offset]
到 [i + 1 + offset]
的绘图,这解决了一个问题。
后来,我正确实现了“水平比例尺0.5x
。
输出波形仍然有一点跳动,但总体上保持不变。
所以我正在用 C 语言做一个简单的示波器。它从输出缓冲区读取音频数据(并在调用时删除缓冲区写入计数器,以便刷新缓冲区)。我尝试制作简单的零交叉触发,因为大多数时候用户会看到简单的(正弦波、脉冲波、锯齿波、三角波),但我使用下面的代码得到的最好结果是一个在其周期的一半时间来回跳跃的波.怎么了?
输入的信号从 -32768 变为 32767,因此应该为零。
如果你不明白我的意思可以看视频:click
更新:删除了与触发无关的代码,以便更容易理解所有功能。
extern Mused mused;
void update_oscillscope_view(GfxDomain *dest, const SDL_Rect* area)
{
if (mused.output_buffer_counter >= OSC_SIZE * 12) {
mused.output_buffer_counter = 0;
}
for (int x = 0; x < area->h * 0.5; x++) {
//drawing a black rect so bevel is hidden when it is under oscilloscope
gfx_line(domain,
area->x, area->y + 2 * x,
area->x + area->w - 1, area->y + 2 * x,
colors[COLOR_WAVETABLE_BACKGROUND]);
}
Sint32 sample, last_sample, scaled_sample;
for (int i = 0; i < 2048; i++) {
if (mused.output_buffer[i] < 0 && mused.output_buffer[i - 1] > 0) {
//here comes the part with triggering
if (i < OSC_SIZE * 2) {
for (int x = i; x < area->w + i; ++x) {
last_sample = scaled_sample;
sample = (mused.output_buffer[2 * x] + mused.output_buffer[2 * x + 1]) / 2;
if (sample > OSC_MAX_CLAMP) { sample = OSC_MAX_CLAMP; }
if (sample < -OSC_MAX_CLAMP) { sample = -OSC_MAX_CLAMP; }
if (last_sample > OSC_MAX_CLAMP) { last_sample = OSC_MAX_CLAMP; }
if (last_sample < -OSC_MAX_CLAMP) { last_sample = -OSC_MAX_CLAMP; }
scaled_sample = (sample * OSC_SIZE) / 32768;
if(x != i) {
gfx_line(domain,
area->x + x - i - 1, area->h / 2 + area->y + last_sample,
area->x + x - i, area->h / 2 + area->y + scaled_sample,
colors[COLOR_WAVETABLE_SAMPLE]);
}
}
}
return;
}
}
}
在调试期间,我简化了代码,直到它开始工作。谢谢克利福德。
我找到了一个触发器索引 i
(假设它是数组索引 300)。修改为示波器画线从[(2 * i) + offset]
到[(2 * i + 1) + offset]
,因此形成了错误的画面。
我用了(2 * i)
,因为我想让长波适合示波器。我将其替换为从 [i + offset]
到 [i + 1 + offset]
的绘图,这解决了一个问题。
后来,我正确实现了“水平比例尺0.5x
。
输出波形仍然有一点跳动,但总体上保持不变。