[英]Convert IEnumerable to IObservable with variable Period
我正在使用Rx消耗3軸加速度計數據。 我需要設置一些單元測試。 數據幀輸入速度很快,幀之間的中值時間跨度為80毫秒,但有時為120毫秒。 另外,它永遠不會精確到80ms,而是徘徊在該范圍內。
因此,我創建了一個預訂IObservable的類,並將數據幀順序記錄在.csv文件中。 .csv文件中的一個字段是幀的開始時間,而第一幀的開始時間= 0.0。
現在,我想讀取該文件並再次對其進行流傳輸,以進行測試和開發。 我想使用StartTime字段作為時間表,以進行測試時何時觸發任何給定的加速度計框架。
我仔細查看了這個問題的答案, 使用.NET反應性擴展定期計划IEnumerable,但這似乎只能解決恆定的時間跨度。
問題:在Rx框架中是否已經有規范且首選的方式以不規則(但已知)的時間間隔安排幀推送,還是應該以某種方式滾動自己?
編輯2:我對可能很簡單的事情感興趣:
IObservable<T> AsObservable(
IEnumerable<T> source, Func<T, TimeSpan> getTimeDelta)
{
var retVal = ColdObservableVaryingTime();
foreach(var frame in source)
{
retVal.AddScheduled(getTimeDelta, frame);
}
return retVal;
}
編輯1:在這個問題中我稱之為“框架”,Rx文檔稱為TState。
這是您的另一個選擇。 Observable.Generate
方法非常強大,可用於生成非常復雜的值序列。
這是您的方法。
因此,從這樣的CSV文件開始:
var csvLines = new []
{
"A,0",
"B,3",
"C,4",
"D,6",
};
(可以像var csvLines = File.ReadAllLines(@"...");
。)
然后,您可以解析以下行:
var parsed =
(
from line in csvLines
let parts = line.Split(',')
select new
{
item = parts[0],
seconds = int.Parse(parts[1])
}
).ToArray();
然后確定CSV中每行之間的秒數offset
:
var data =
parsed
.Zip(parsed.Skip(1), (p0, p1) => new
{
p1.item,
offset = p1.seconds - p0.seconds,
})
.ToArray();
現在您可以創建可觀察的:
var observable =
Observable
.Generate(
0,
n => n < data.Length,
n => n + 1,
n => data[n].item,
n => TimeSpan.FromSeconds(data[n].offset))
.StartWith(parsed[0].item);
當我運行這段代碼時,我從源文件中獲得了正確的時間。
在下面的注釋中,根據您的類定義,我已經更新了代碼:
IEnumerable<AccelerometerFrame_raw> frames = ...;
var data =
frames
.Zip(frames.Skip(1), (f0, f1) => new
{
f1,
offset = f1.TimeStampSeconds - f0.TimeStampSeconds,
})
.ToArray();
IObservable<AccelerometerFrame_raw> observable =
Observable
.Generate(
0,
n => n < data.Length,
n => n + 1,
n => data[n].f1,
n => TimeSpan.FromSeconds(data[n].offset))
.StartWith(frames.First());
為此,您可以使用TestScheduler(獲取Rx-Testing Nuget包)。 使用該類作為測試中的IScheduler實現,將允許您調度序列,因為測試調度器允許您通過聲明何時應推送每個項目來創建可觀察的序列。 然后,您可以“播放”調度程序或前進到某個時間等,看看發生了什么。 請注意,在此設置中,時間是虛擬化的,為簡單起見,TestScheduler將Ticks作為其時間單位進行處理。
RX簡介網站上有一個很好的關於RX測試的部分: http : //www.introtorx.com/content/v1.0.10621.0/16_TestingRx.html
詹姆斯·盧卡斯(James Lucas)提供的答案是正確方向的良好指針,但成功的答案則涉及更多。
在我用CSV文件中的值填充IEnumerable之后,我必須填充一個
Recorded<Notification<AccelerometerFrame_raw>>
然后,將數組作為參數傳遞給調度程序CreateColdAbservable。 完成此操作后,可觀察到的寒冷坐在那里等待啟動。 在我的特定情況下,代碼如下所示:
private TestScheduler sched {get; set;}
public IObservable<AccelerometerFrame_raw> DataStream { get; protected set; }
ctor()
{
DataStream = SetupDeviceStream();
}
private IObservable<AccelerometerFrame_raw> SetupDeviceStream()
{
var framesArray =
new Recorded<Notification<AccelerometerFrame_raw>>[allFrames.Count+1];
int i = 0;
long timeStamp = 0;
foreach(var item in allFrames)
{
timeStamp += (long) (item.TimeStampSeconds * 1000.0);
framesArray[i] = new Recorded<Notification<AccelerometerFrame_raw>>(
timeStamp,
Notification.CreateOnNext(item));
i++;
}
framesArray[i] = new Recorded<Notification<AccelerometerFrame_raw>>(
timeStamp + 10,
Notification.CreateOnCompleted<AccelerometerFrame_raw>());
sched = new TestScheduler();
var stream =sched.CreateColdObservable(framesArray);
return stream;
}
////當我准備開始冷觀測時,我打電話
sched.Start();
將所有內容組合在一起的幫助來自
(菲爾·哈克(Phil Haak)) http://haacked.com/archive/2014/03/10/master-time-with-reactive-extensions/
和https://msdn.microsoft.com/zh-CN/library/hh229343(v=vs.103).aspx
還必須安裝另一個Nuget軟件包:
http://www.nuget.org/packages/reactiveui-testing/
正如Phil Haak在鏈接的博客文章中所說的:“不幸的是,[TestScheduler]不能按原樣使用,這就是Paul Betts親自編寫一些有用的TestScheduler擴展方法的原因”
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.