Jump to content

Ben Johnson

Seeq Team
  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Ben Johnson

  1. In v51, the "Assigning a property based on another signal value during the capsule" became much easier: $condition.setProperty('Property Name', $signal, valueStat()) Where valueStat is one of the aggregation operations like average(), maxValue(), totalized(), etc. This form is also much faster.
  2. The formula above needs some tweaks for new version of Seeq to be compatible with upgrades to Seeq Formula For 0.48: $condition.transformToSamples($cap -> Sample($cap.getStart(),$cap.getStart().toString()), 1d) .replace('/(?<year>....)-(?<month>..)-(?<day>..)T(?<hour>..):(?<minute>..):(?<sec>..)(?<dec>.*)Z/' , '${month}/${day}/${year} ${hour}:${minute}') For 0.49 $condition.toSamples($cap -> Sample($cap.startKey(), $cap.startKey().toString()), 1d) .replace('/(?<year>....)-(?<month>..)-(?<day>..)T(?<hour>..):(?<minute>..):(?<sec>..)(?<dec>.*)Z/' , '${month}/${day}/${year} ${hour}:${minute}') All that said, even back in 0.47, the more succinct way to express this is $condition.toSignal('Start').toLinear(1d).toString() .replace('/(?<year>....)-(?<month>..)-(?<day>..)T(?<hour>..):(?<minute>..):(?<sec>..)(?<dec>.*)Z/' , '${month}/${day}/${year} ${hour}:${minute}')
  3. Comparing 2 signals in earlier versions requires a bit more slight of hand, comparing the difference between the two signals to 0. $s1 > $s2 is the same as ($s1-$s2).valueSearch(isGreaterThan(0)) This is
  4. I'm not able to reproduce that behavior in 0.45. The algorithm for suggesting formula variable names has had some refinements since its it was introduced in 0.43. Thanks for the feedback!
  5. In addition to the common math symbols, there are also some new concise ways to search for other signal states: $signal.isValid() - make a condition that enumerates when the signal has data $signal.isNotValid() - make a condition that enumerates the gaps in the signal $signal.isBetween(10, 20) - make a condition whenever the signal is between 10 and 20 $signal.isNotBetween(10, 20) - make a condition whenever the signal is outside the boundary of 10-20 Also for string signals, you can search for regular expressions or glob-like syntax: $signal ~= "*STAG*" - find whenever the state signal contains "STAG". $signal !~ "*STAG*" - find whenever the state signal does not contain "STAG". All of these things can be combined and given precedence with parenthesis. For example, to find "when is temp < 90 and either of humidity > 60 or compressor is off " $temp < 90 && ( $humidity > 60 || $compressor == 'OFF')
  6. There's one small shortcut hidden at the bottom of the tool. If you check that before you finish the first column import, it will return you to the tool with many of the same values preserved. At least you don't need to re-upload the file 9 more times; you just pick the other data column, customize the unit and repeat.
  7. The subtlety in the last option of filtering by sample values rather than capsule properties is that the maximum interpolation of the signal may span over the removed samples, resulting in extra time for the adjacent states.
  8. Solution 3 Pure Seeq Formula The desired condition can be expressed in one step with Seeq Formula: periods(5 months, 1 year, '2015-05-01') That function allows you to mix the durations of the capsules with a different period. The 3rd parameter is an example origin for the capsule. In this case you could pick any year, as long as it starts on May 1 and the engine will create capsules using various increments of the period. (There's also a 4th parameter that can be used to fine tune the timezone of the midnight origin)
  9. The worksheet timezone changes the display of the timestamps, but it doesn't change the actual timestamps of the capsules. By default, all the periodic conditions are generated according to the server timezone. This can be overridden in in the advanced section of the tool as shown below. Selecting the correct timezone is important because it affects edge cases like daylight savings. Selecting a timezone that honors DST will produce the 25 or 23h capsule on the proper adjustment day.
  10. Predicting into the future is a great use of now(), and it's uncertainty is a key part of keeping the predicted data from polluting the cache. I'm sure you're working toward your own use case, but here's a different approach that's a bit more concise (and uses some newer functions). I'm sure we agree that yesterday's temperature has no prediction value for future, but that's just the demo data. It seems you're just looking for a golden batch to repeat with some adjustment into the future // extract a single good day to repeat, then repeat it every day $repeatShape = referenceTable(5min) .addRow($temp, capsule("2019-05-15")) .repeatOver(days(), ReferenceTableStat.Average) // this is 5F/day rise since now $slopeLine = timeSince(now(), 1d).setUnits('F') * 5 // stitch known with future $temp.forecastSplice($repeatShape + $slopeLine )
  11. Yes. It may seem odd to call now() "uncertain" - don't we have accurate clocks? It really means that the value will change, and any computation using that value is likely to get get different results in the future so it shouldn't be cached. The reference series feature is really designed to create static profiles - the performance impact of having to recompute the profile every time that it is used was considered too great. So I don't think there's a workaround. Perhaps you could describe your use case where a dynamic profile has significant value over the static profile? Are the profiles expected to change significantly over time such that recent behavior is more relevant than a training window(s) that was identified as the "golden batch"? If there are interesting use cases, perhaps it's worth filing a feature request as a result.
  12. This is a creative solution, but I wouldn't depend on it. It's exposed a bug in the delay() function regarding uncertainty. The offset that is being passed to delay() is "uncertain". That means it's possible the value could change. But delay() is not reflecting the uncertainty of the offset in its output properly (the whole signal should be uncertain), which makes it possible to use the delayed signal in the reference profile. You'll see the negative effects of this after a few days - the portion of the signal that was cached using an older training window won't get updated to reflect the more recent training window.
  13. ConvertUnits requires a compatible units of its input and will do the scaling. Some examples 5m.convertUnits('cm') = 500cm. 5m.setUnits('cm') = 5cm 5m.setUnits('g') = 5g 5m.convertUnits('g') is an error I'm a bit surprised by the failure in your 2nd case. setUnits should never fail (almost - there are edge cases in converting string and numeric). I imagine the issue is that the underlying signals have incompatible units for the math prior to the setUnits. If you have the formulas you tried, we can see if there are precedence issues vs actual bugs.
  14. The alternative to setUnits is convertUnits. The former just adds overrides the current value with the new unit, the latter applies the math needed to the existing values. For your case you should probably use ($a/($b+$c)).convertUnits('%')
  15. You can create more specialized periodic conditions using the "periods()" function in the formula tool. For example "periods(1min)" will give you one capsule every minute. That condition can then be used in the signal from condition tool. The periods function can also create overlapping or gapped capsules. For example, if you wanted to compare your actual signal against 5 minutes of data but do it every minute, you'd use "periods(5min, 1min)". (Then you'd probably want to align your signal from condition on the middle of the capsules)
  16. In versions up through R21.0.40, you can use the the filter function, such as $condition.filter($capsule -> $capsule.duration() > 1min) Where the expression inside the filter is evaluated for which capsules to keep. This will be even easier in the upcoming release of R21.0.41 when you can do $condition.removeShorterThan(1min)
  17. The hover cursors are always subject to the resolution of the screen. You can see the precise start date of that capsule in the capsule detail pane in the lower right. It looks like your reference signal might be off an hour or two, probably due to timezone adjustments. You can adjust the capsule or the days() formula with a timezone parameter in order to get it to repeat over the right day boundaries.
  18. It's possible to do it with a reference profile. Reference profiles are usually for aggregating multiple training periods, but if you take the average of just one period, it's equivalent to capturing the slice of the signal you want. Here's a formula that gets the gist of it: referenceTable(5min) .addRow($inputSignal, capsule('Feb 13 2019')) .repeatOver(days(), ReferenceTableStat.Average)
  19. The min/max functions have been added to the latest general release, R21.0.40.05
  20. You've found a bug! It's a two-fold issue The histogram is localizing the "day of week" labels using your browser's settings (The rest of the app is in English, but I infer your browser is set to prefer German) That localization code is treating the "start of the week" differently. Much of the world starts their week on Monday, others start it on Sunday, so there's an off-by-one error in looking up the proper label. I've filed CRAB-14766 so that we can track this. You've identified a creative workaround that sidesteps the bug. If your analysis can be done in English (US), changing your browser settings would also resolve it. Thanks for the question!
  21. It's not just valid samples that are the problem, it's the gaps between samples that are longer than the "maximum interpolation" of the signal. validValues() doesn't change that. Setting a long maxInterpolation on the signal probably doesn't do what you want either, since then line between the first and last sample of the gap would now interpolate and contribute to the sum of the signals.
  22. I'll describe a similar solution, and maybe it's close enough to meet your needs. Let's call the all capsules $on Make a selection on screen that matches the ideal capsule. create a profile search against signal using a 90% similarity (or whatever value you find works well). (The tool in the UI doesn't allow a high fidelity match - you could do a better job by declaring the start/end of the profile search manually in formula). We'll call this $good use the composite condition tool to create a new condition $bad that is $on outside $good create a new periodic condition $periods for the intervals you want to get the percentage over. For example weeks() create a signal from condition for each $bad and $on, aggregating the total duration per week. Using a discrete interpolation is easiest because the samples from each signal will align according to $periods Create a formula that is ($bad/$on).convertUnits('%') Caveats This is really depending on the L2 norm to match the good periods. It's not doing any time warping, so it's not going to match +/- 10% on the x-axis very well. It's really not going to do well with varying durations of the on capsules. The profile search is going to compute the similarity for the entire width of the good capsule, regardless of the duration the $on capsule was. In fact, the profile is totally independent of the $on condition. $good could contain capsules that have nothing to do with $on. You may need to convert some of the tool items to raw formula so that you can adjust their parameters more. A completely different approach would be to use the reference profile tool to create boundaries of signal. The bad capsules could be identified based on the percentage of time the signal is outside the boundary. That would mitigate the effects of varying on durations
  23. This is an interesting challenge. I have some questions as I ponder some approaches. Are those capsules all the same duration? Or is there some expected time warping of the selected capsules in the result? What is the criteria for 90%? For example in the profile search tool, there is a "similarity" value that is L2 norm (aka euclidean norm) that has been normalized by the sample count. That would be a great value to compare against.
  24. Getting the value of a signal at the start of each capsule is even easier using the aggregate() function. For example: In R20 $signal.aggregate(Stat.ValueStart, $condition, PositionInCapsule.StartOfCapsule) In R21 $signal.aggregate(startValue(), $condition, startKey())
  25. This is a good way to show the use of splice() for replacing portions of signals. If folks are looking for actual min/max techniques, there's a KB page with a technique using zipWith() But my favorite way is with some math tricks. You have to try it to believe it. //min: ($a+$b-($a-$b).abs())/2 // max: ($a+$b+($a-$b).abs())/2 This has the downside that it can increase the sample density of the resulting signal. But it has the advantage of not needing to pick a maximum duration for the splicing.
  • Create New...