On Sun, Oct 20, 2019 at 4:36 PM Keith Medcalf <kmedc...@dessus.com> wrote:

>
> On Sunday, 20 October, 2019 06:58, Petr Jakeš <petr.jakes....@gmail.com>
> wrote:
>
> >On Sun, Oct 20, 2019 at 2:53 AM Keith Medcalf <kmedc...@dessus.com>
> wrote:
>
> >> On Saturday, 19 October, 2019 18:26, Petr Jakeš <
> petr.jakes....@gmail.com> wrote:
>
> >>> After long time I have set up development environment properly and I
> >>> am able to start to study your queries.
>
> >>> I am lost. I don't either understand the first bunch of subqueries...
> >>> (What is returned in the "ratetoprior"? I have been pulling my hair
> >>> over 3 hours trying to figure it out ... no clue what it means.
>
> >> RateToPrior is the linear slope of the line which joins the current
> >> value to the prior value.  Once you know the slope of that line, then
> for any
> >> point in time you merely need to find the next reading after that point
> >> in time and use the slope to calculate/interpolate what the value would
> >> have been at the time you are interested in (assuming that the value
> change
> >> is linear).
>
> >> Does this help?
>
> > If I understand it properly:
>
> >   - timestamps are considered as x values, readings as y values
> >   - *pwr* statement calculates slope of the line
> >   <https://en.wikipedia.org/wiki/Slope> (delta y / delta x) between all
> >   adjacent readings
> >   - *periods* statement calculates (fills in) the dates according to the
> >   requested granity
> >   - *readings* statement calculates readings from the next reading (next
> >   higher timestamp to the periods datestamp)
> >   - *used* statement calculates consumption (lag between two adjacent
> >   rows)
>
> > My confusion was I didn't expect all values are calculated, not just
> > returned directly from the database as I was almost doing.
> > Your approach is GENIAL! Thank you.
>
> You got it exactly.  It really does not matter if one of your requested
> points (x) happens to match an actual sample, as the calculated result from
> the next sample (y) should match that value because it is interpolating
> backwards -- it is also easier to always calculate the appropriate y for
> the given x, than it is to figure out where the x samples are and fill in
> the blanks.
>
> > Do you mind if I will mention you/your solution on my blog (in the time
> > when I write post about power/water metering)?
>
> Not at all.
>
> > What about if I want 1 hour granity? (to plot a graph of daily
> > consumption for example)
>
> This should work exactly the same way.  You just need to generate the
> *periods* so that they match the x values for which you want to calculate
> readings.  Since the *used* table reflects the lag between two adjacent
> rows, you need your *periods* to include the last hour of the previous day
> and perhaps the first hour of the next day (so 26 points, as it were), and
> then filter it afterwards when you plot your graph.  Note that this will be
> a "snapshot" based graph, not an "average" based graph.
>
> This scheme is generally how Process Historians work for continuous
> control.  Once each minute (the exact offset into the minute does not
> really matter nor does it need to be the same, it is just frequent
> readings) the instantaneous value is collected and stored together with the
> computed slope to the previous value.  From this you can interpolate what
> the instantaneous value was at exactly each minute boundary.  This gives
> you a series of polygons which are basically estimates of the shape of the
> curve.  The historian will generate the one minute "snapshot" values and
> average those to get each hourly average.  It can also compute the
> "confidence" in the accuracy of that value based on the number of actual
> samples in the interval (vs the number there ought to be).  Industry
> standard values are called "raw" which is the actual recorded data with no
> interpolation, "snapshot" (point in time interpolated values), one minute
> average (which is different from the snapshot since the value usually
> changed sometime during the minute and the average is computed assuming
> that the prior value was in effect up until the change, and the new value
> afterwards, ie, that the readings are discrete -- or it may average the
> start of minute and the end of minute snapshots depending on
> configuration), six minute average on every 6 minute boundary (the average
> of the 6 one minute snapshot values (at minute offset 0, 6, 12 ... in the
> hour), and hourly average on every hour (the average of the 60 one minute
> snapshot values).  Intervals less than a day the y (timestamp) is the at
> the end of the interval, and for intervals greater than a day the y
> (timestamp) is the beginning of the interval.  Sometimes the sample
> frequency is increased beyond 1 minute, in which case the calculations are
> all based on that sample frequency giving you a better approximation of the
> curve.  (It is all really nothing more than just using Eulers method to
> collect samples which will allow an integral to be approximated).
>

Thank you for nice lesson. I was briefly googling about Process Historians.
Thanks to your help I know, SQLite is powerful enough for my purposes (to
store 9 water meters  and 9 power meters readings). All depends, of course,
about the time granularity of stored readings. In my case, one reading a
day (water) and 144 readings a day (energy) per spot will be enough.



> >
> >
> >> >with pwr (timestamp, reading, ratetoprior) as
> >> >     (
> >> >        select julianday(timestamp),
> >> >               total_kwh,
> >> >               (
> >> >  select  (c.total_kwh - p.total_kwh) / (julianday(c.timestamp)-
> >> >julianday(p.timestamp))
> >> >                  from power as p
> >> >                 where julianday(p.timestamp) < julianday(c.timestamp)
> >> >              order by julianday(p.timestamp) desc
> >> >                 limit 1
> >> >)
> >> >          from power as c
> >> >      order by julianday(timestamp)
> >> >     )
> >> >select * from pwr
> >> >
> >> >On Tue, Sep 3, 2019 at 1:11 AM Keith Medcalf <kmedc...@dessus.com>
> >wrote:
> >> >
> >> >>
> >> >> On Monday, 2 September, 2019 12:26, Petr Jakeš
> >> ><petr.jakes....@gmail.com>
> >> >> wrote:
> >> >>
> >> >> >Yes, you are right. The error is connected with the version  of
> >> >> >SQLite. Now I am trying to build DB Browser using SQLite version
> >> >3.29.0.
> >> >> >Than I have to study your code. Your knowledge and SQL Windows
> >> >> >functions are over my scope. Thank for the study material for next
> >> >> weekend :D
> >> >>
> >> >> Here is another example for you to ponder that uses your original
> >table
> >> >> and requires one index.  It builds the "pwr" view dynamically but
> >uses
> >> >the
> >> >> ratetoprior to compute the instant readings and only needs one
> >window
> >> >query
> >> >> to compute the usage from two readings.  Performance is half way
> >> >between
> >> >> the other two examples:
> >> >>
> >> >> create index if not exists power_jd on power (julianday(timestamp),
> >> >> total_kwh);
> >> >>
> >> >> with pwr (timestamp, reading, ratetoprior) as
> >> >>      (
> >> >>         select julianday(timestamp),
> >> >>                total_kwh,
> >> >>                (select (c.total_kwh - p.total_kwh) /
> >> >> (julianday(c.timestamp) - julianday(p.timestamp))
> >> >>                   from power as p
> >> >>                  where julianday(p.timestamp) <
> >julianday(c.timestamp)
> >> >>               order by julianday(p.timestamp) desc
> >> >>                  limit 1)
> >> >>           from power as c
> >> >>       order by julianday(timestamp)
> >> >>      ),
> >> >>      periods (timestamp) as
> >> >>      (
> >> >>          select julianday(date(min(timestamp), '-1 day') || '
> >> >> 23:59:59.999')
> >> >>            from pwr
> >> >>       union all
> >> >>          select julianday(datetime(timestamp, '+1 day'))
> >> >>            from periods
> >> >>           where timestamp < (select max(timestamp) from pwr)
> >> >>      ),
> >> >>      readings (timestamp, reading) as
> >> >>      (
> >> >>       select timestamp,
> >> >>              (select reading - (b.timestamp - p.timestamp) *
> >> >ratetoprior
> >> >>                from pwr as b
> >> >>               where b.timestamp >= p.timestamp
> >> >>               limit 1) as reading
> >> >>         from periods as p
> >> >>        where timestamp between (select min(timestamp) from pwr)
> >> >>                            and (select max(timestamp) from pwr)
> >> >>     ),
> >> >>     used (timestamp, kwh) as
> >> >>     (
> >> >>       select timestamp,
> >> >>              reading - lag(reading) over ()
> >> >>         from readings
> >> >>     )
> >> >>   select datetime(timestamp),
> >> >>          kwh
> >> >>     from used
> >> >>    where kwh is not null;
> >> >>
>
> --
> The fact that there's a Highway to Hell but only a Stairway to Heaven says
> a lot about anticipated traffic volume.
>
>
>
> _______________________________________________
> sqlite-users mailing list
> sqlite-users@mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to