From: Gerhard Sittig Date: Fri, 12 Oct 2018 10:35:50 +0000 (+0200) Subject: output/vcd: support smaller timescales with higher resolution X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=17c30d0593ae8db4cd8b185e8bc45a15e4beed5d;p=libsigrok.git output/vcd: support smaller timescales with higher resolution The previous implementation inspected the input stream's samplerate, and simply used the next 1kHz/1MHz/1GHz timescale for VCD export. Re-import of the exported file might suffer from rather high an overhead, where users might have to downsample the input stream. Also exported data might use an "odd" timescale which doesn't represent the input stream's timing well. Rephrase the samplerate to VCD timescale conversion such that the lowest frequency is used which satisfies the file format's constraints as well as provides high enough a resolution to communicate the input stream's timing with minimal loss. Do limit this scaling support to at most three orders above the input samplerate, to most appropriately cope with odd rates. As a byproduct the rephrased implementation transparently supports rates above 1GHz. Input streams with no samplerate now result in 1s timescale instead of the 1ms timescale of the previous implementation. --- diff --git a/src/output/vcd.c b/src/output/vcd.c index 80b2c34a..3de3dcde 100644 --- a/src/output/vcd.c +++ b/src/output/vcd.c @@ -78,6 +78,38 @@ static int init(struct sr_output *o, GHashTable *options) return SR_OK; } +/* + * VCD can only handle 1/10/100 factors in the s to fs range. Find a + * suitable timescale which satisfies this resolution constraint, yet + * won't result in excessive overhead. + */ +static uint64_t get_timescale_freq(uint64_t samplerate) +{ + uint64_t timescale; + int max_up_scale; + + /* Go to the next full decade. */ + timescale = 1; + while (timescale < samplerate) { + timescale *= 10; + } + + /* + * Avoid loss of precision, go up a few more decades when needed. + * For example switch to 10GHz timescale when samplerate is 400MHz. + * Stop after at most factor 100 to not loop endlessly for odd + * samplerates, yet provide good enough accuracy. + */ + max_up_scale = 2; + while (max_up_scale--) { + if (timescale / samplerate * samplerate == timescale) + break; + timescale *= 10; + } + + return timescale; +} + static GString *gen_header(const struct sr_output *o) { struct context *ctx; @@ -121,13 +153,7 @@ static GString *gen_header(const struct sr_output *o) g_string_append_printf(header, "\n$end\n"); /* timescale */ - /* VCD can only handle 1/10/100 (s - fs), so scale up first */ - if (ctx->samplerate > SR_MHZ(1)) - ctx->period = SR_GHZ(1); - else if (ctx->samplerate > SR_KHZ(1)) - ctx->period = SR_MHZ(1); - else - ctx->period = SR_KHZ(1); + ctx->period = get_timescale_freq(ctx->samplerate); frequency_s = sr_period_string(1, ctx->period); g_string_append_printf(header, "$timescale %s $end\n", frequency_s); g_free(frequency_s);