10 type OTS_DataPoint struct {
15 type OTS_TimeSeries struct {
16 DataPoints []OTS_DataPoint
19 /* Functions for the sort interface. */
20 func (obj *OTS_TimeSeries) Len () int {
21 return (len (obj.DataPoints))
24 func (obj *OTS_TimeSeries) Less (i, j int) bool {
25 if obj.DataPoints[i].TimeStamp < obj.DataPoints[j].TimeStamp {
31 func (obj *OTS_TimeSeries) Swap (i, j int) {
32 tmp := obj.DataPoints[i]
33 obj.DataPoints[i] = obj.DataPoints[j]
34 obj.DataPoints[j] = tmp
37 func Fmod64 (a float64, b float64) float64 {
39 return b * float64 (tmp)
42 func (obj *OTS_TimeSeries) Write (name string) os.Error {
43 fd, err := os.OpenFile (name, os.O_WRONLY, 0666)
48 for i := 0; i < len (obj.DataPoints); i++ {
49 data_point := obj.DataPoints[i]
50 str := fmt.Sprintf ("%.3f,%g\n", data_point.TimeStamp, data_point.Rate)
59 func ReadFile (name string) (obj *OTS_TimeSeries, err os.Error) {
60 fd, err := os.Open (name)
65 /* dp_list := make ([]OTS_DataPoint, intervals_num */
66 obj = new (OTS_TimeSeries)
72 status, err := fmt.Fscanln (fd, "%f,%f", ×tamp, &rate)
75 } else if status != 2 {
79 fmt.Printf ("timestamp = %.3f; rate = %g;\n", timestamp, rate)
81 obj.DataPoints = append (obj.DataPoints, OTS_DataPoint{timestamp, rate})
88 func (obj *OTS_TimeSeries) ConsolidatePointAverage (ts_start, ts_end float64) OTS_DataPoint {
91 if ts_start > ts_end {
100 if len (obj.DataPoints) < 1 {
101 /* The object contains no data. */
103 } else if ts_start > obj.DataPoints[len (obj.DataPoints) - 1].TimeStamp {
104 /* The timespan is after all the data in the object. */
106 } else if ts_end < obj.DataPoints[0].TimeStamp {
107 /* The timespan is before all the data in the object. */
111 /* Find the first rate _after_ the start of the interval. */
112 idx_start := sort.Search (len (obj.DataPoints), func (i int) bool {
113 if obj.DataPoints[i].TimeStamp > ts_start {
119 /* The start is outside of the range of the timestamp. With the above checks
120 * this means that the start is _before_ the data in the object. We can thus
121 * use the first elements in the slice. */
122 if idx_start >= len (obj.DataPoints) {
126 /* There is no data points _between_ ts_start and ts_end. Return the first
127 * measured rate _after_ the desired timespan as the rate of the timespan. */
128 if obj.DataPoints[idx_start].TimeStamp >= ts_end {
129 dp.Rate = obj.DataPoints[idx_start].Rate
133 var timespan_len float64 = 0.0
134 var timespan_sum float64 = 0.0
135 for i := idx_start; i < len (obj.DataPoints); i++ {
136 dp_ts_start := ts_start
137 if (i > 0) && (dp_ts_start < obj.DataPoints[i - 1].TimeStamp) {
138 dp_ts_start = obj.DataPoints[i - 1].TimeStamp
141 dp_ts_end := obj.DataPoints[i].TimeStamp
142 if dp_ts_end > ts_end {
146 dp_ts_diff := dp_ts_end - dp_ts_start
147 /* assert dp_ts_diff > 0.0 */
148 timespan_len += dp_ts_diff
149 timespan_sum += dp_ts_diff * obj.DataPoints[i].Rate
151 if obj.DataPoints[i].TimeStamp >= ts_end {
156 dp.Rate = timespan_sum / timespan_len
158 } /* ConsolidatePointAverage */
160 func (obj *OTS_TimeSeries) ConsolidateAverage (interval float64) *OTS_TimeSeries {
165 ts_raw_first := obj.DataPoints[0].TimeStamp
166 ts_raw_last := obj.DataPoints[len (obj.DataPoints) - 1].TimeStamp
168 fmt.Printf ("ts_raw_first = %g; ts_raw_last = %g;\n",
169 ts_raw_first, ts_raw_last)
171 /* Determine the timespan the consolidated data will span. */
172 ts_csl_first := Fmod64 (ts_raw_first, interval)
173 ts_csl_last := Fmod64 (ts_raw_last, interval)
174 if ts_csl_first < ts_raw_first {
175 ts_csl_first += interval
178 fmt.Printf ("ts_csl_first = %g; ts_csl_last = %g;\n",
179 ts_csl_first, ts_csl_last)
181 intervals_num := int ((ts_csl_last - ts_csl_first) / interval)
182 fmt.Printf ("Got a %gs timespan (%d intervals).\n",
183 ts_csl_last - ts_csl_first, intervals_num)
185 /* Allocate return structure */
186 ret_data := new (OTS_TimeSeries)
187 ret_data.DataPoints = make ([]OTS_DataPoint, intervals_num)
189 /* FIXME: This is currently a O(n log(n)) algorithm. It should instead be a O(n)
190 * algorithm. This is possible since obj is sorted. The problem is that
191 * ConsolidatePointAverage() does a binary search when we actually know where
192 * to go in the array. */
193 for i := 0; i < intervals_num; i++ {
194 ts := ts_csl_first + (float64 (i + 1) * interval)
196 fmt.Printf ("Building data for interval ]%g-%g].\n", ts - interval, ts)
198 ret_data.DataPoints[i] = obj.ConsolidatePointAverage (ts - interval, ts)
202 } /* ConsolidateAverage */
204 func (obj *OTS_TimeSeries) Print () {
205 for i := 0; i < len (obj.DataPoints); i++ {
206 data_point := obj.DataPoints[i]
207 fmt.Printf ("[%g] %g\n", data_point.TimeStamp, data_point.Rate)
211 /* vim: set syntax=go sw=2 sts=2 et : */