{"id":286,"date":"2012-05-06T00:24:16","date_gmt":"2012-05-06T05:24:16","guid":{"rendered":"http:\/\/factormystic.net\/blog\/?p=286"},"modified":"2020-06-22T21:58:29","modified_gmt":"2020-06-23T02:58:29","slug":"using-reactive-extensions-to-smooth-compass-data-in-windows-phone","status":"publish","type":"post","link":"https:\/\/factormystic.net\/blog\/using-reactive-extensions-to-smooth-compass-data-in-windows-phone","title":{"rendered":"Using Reactive Extensions to smooth compass data in Windows Phone"},"content":{"rendered":"<h2>Getting Started<\/h2>\n<p>The challenge is to take the raw compass heading data, and smooth it out over time so the UI element this data is bound to (such as an arrow) won&#8217;t be jittery. You can see this jitter in the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/ff431744%28v=vs.92%29.aspx#BKMK_Sensors\">SDK example<\/a> for the Compass: the\u00a0<code>CurrentValueChanged<\/code> event handler is fired every 20ms and jitters within the error margin for the hardware. Our task is to smooth out these data readings for a more pleasant user interface. And to make it fun, we&#8217;ll be using Reactive Extensions.<\/p>\n<p>It&#8217;s quite easy to calculate a periodic average of a data stream with Reactive Extensions, and we&#8217;ll tackle it in three stages:<\/p>\n<ol>\n<li>Create the <code>Observable<\/code><\/li>\n<li>Segment the compass readings into chunks, and get an average<\/li>\n<li>Capture the result and make something happen<\/li>\n<\/ol>\n<h2>Step 1: Create the <code>Observable<\/code><\/h2>\n<p>Starting with the Compass&#8217;s <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/hh239103.aspx\">CurrentValueChanging<\/a> event, we need to convert it into an Observable. After creating a new Compass object (hereafter simply called &#8220;<code>compass<\/code>&#8220;), we can write this with any overload of <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/hh697809.aspx\">Observable.FromEvent<\/a>, either by manually providing delegates to add\/remove event subscriptions (as commonly listed on <a href=\"https:\/\/rxwiki.wikidot.com\/101samples#toc6\">RxWiki<\/a>), or by providing the event name as a string:<\/p>\n<p>[embedGist source=&#8221;https:\/\/gist.github.com\/2607208&#8243;]<\/p>\n<p>For succinctness, I&#8217;ll use the latter in this post.<\/p>\n<p>If we stop right here for a moment, we can confirm that our compass is working and that we can get readings by subscribing to the <code>Observable<\/code>&#8216;s stream of <code>SensorReadingEventArgs<\/code> events by tapping in with the <code>Subscribe<\/code> method and printing out the raw heading readings:<\/p>\n<p>[embedGist source=&#8221;https:\/\/gist.github.com\/2607213&#8243;]<\/p>\n<p>Running this sample will spit out an endless series of raw readings in the debug output window:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" title=\"Raw Compass Headings\" src=\"https:\/\/i.imgur.com\/TQ2zM.png\" alt=\"\" width=\"668\" height=\"396\" \/><\/p>\n<p>So far, so good. But, we could&#8217;ve done this all with a standard event handler, so let&#8217;s kick it up an notch&#8230;<\/p>\n<h2>Step 2: Break into chunks and average<\/h2>\n<p>We want to avoid jitter in our compass readings, and a simple way to do that is to average all the individual readings over a small time period, of say, two seconds. Without Rx, you&#8217;d need to declare a period reset timer, and then keep track of a running average over the two second period, then clear it when the timer fires and so forth.<\/p>\n<p>With Rx, it&#8217;s chillingly simple; we can do it by chaining just two methods: <code>BufferWithTime<\/code> followed by a standard Linq <code>SelectMany<\/code> (well, and a <code>Select<\/code>). And it&#8217;s all in a single statement.<\/p>\n<p>[embedGist source=&#8221;https:\/\/gist.github.com\/2608813&#8243;]<\/p>\n<p>Running this will spit out readings just like before, except now, they&#8217;re clumped every two seconds, with a pause in between.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" title=\"Buffered compass headings\" src=\"https:\/\/i.imgur.com\/v2dnZ.png\" alt=\"\" width=\"668\" height=\"398\" \/><\/p>\n<p>Let&#8217;s break it down:<\/p>\n<p>Picking up after creating the <code>Observable<\/code>, we chain a call to <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/hh697736.aspx\"><code>BufferWithTime<\/code><\/a>. For the specified period (two seconds, passed in with <code>TimeSpan.FromSeconds(2)<\/code>, <code>BufferWithTime<\/code> takes events and stuffs them into an <code>IList<\/code> of events. Then, we use <code>Select<\/code> to project that list of events into a list of compass headings (pulled out of the event args, <code>e.EventArgs.SensorReading.TrueHeading<\/code>). The <code>Subscribe<\/code> method, as before, allows us to debug print the compass headings to confirm.<\/p>\n<p>Here&#8217;s the full application so far:<\/p>\n<p>[embedGist source=&#8221;https:\/\/gist.github.com\/2608127&#8243;]<\/p>\n<p>Our raw compass readings are broken into two-second lists, but they&#8217;re still individually jittery. However, we can instead take each list and aggregate it into a single heading value. By replacing the <code>SelectMany<\/code>, which gave us a list of headings, with a <code>Select<\/code>, we can do the averaging right inline:<\/p>\n<p>[embedGist source=&#8221;https:\/\/gist.github.com\/2609744&#8243;]<\/p>\n<p>And this gives us one average compass heading every two seconds, minus the jitter, just like we wanted:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" title=\"Average compass headings\" src=\"https:\/\/i.imgur.com\/cUa70.png\" alt=\"\" width=\"670\" height=\"399\" \/><\/p>\n<p>Complete program listing so far:<\/p>\n<p>[embedGist source=&#8221;https:\/\/gist.github.com\/2609858&#8243;]<\/p>\n<h2>Step 3: Making something happen<\/h2>\n<p>We now have de-jittered compass readings coming in every two seconds. Let&#8217;s hook this data up to the UI and build an actual application.<\/p>\n<p>Taking this empty Windows Phone project, I&#8217;ve added the following <code>Image<\/code> into the default content <code>Grid<\/code>:<\/p>\n<p>[embedGist source=&#8221;https:\/\/gist.github.com\/2613124&#8243;]<\/p>\n<p>There&#8217;s nothing special here, it&#8217;s just an image with a default <code>RenderTransform<\/code> that sets the rotational center of the image element to the middle.<\/p>\n<p><a href=\"https:\/\/factormystic.net\/blog\/wp-content\/uploads\/2012\/05\/screenshot.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-300\" title=\"running compass application screenshot\" src=\"https:\/\/factormystic.net\/blog\/wp-content\/uploads\/2012\/05\/screenshot-180x300.png\" alt=\"\" width=\"180\" height=\"300\" srcset=\"https:\/\/factormystic.net\/blog\/wp-content\/uploads\/2012\/05\/screenshot-180x300.png 180w, https:\/\/factormystic.net\/blog\/wp-content\/uploads\/2012\/05\/screenshot.png 480w\" sizes=\"auto, (max-width: 180px) 100vw, 180px\" \/><\/a><\/p>\n<p>Pasting in the Rx code we developed above, we can swap out the debug call and instead update the <code>RenderTransform<\/code>&#8216;s angle property to the compass heading (actually, 360 minus the heading&#8230; we want the arrow image to rotate opposite the phone device. If we didn&#8217;t do this subtraction, it&#8217;d rotate the header angle, but in the same direction we turn the phone.)<\/p>\n<p>[embedGist source=&#8221;https:\/\/gist.github.com\/2613466&#8243;]<\/p>\n<p>(Oh, and there&#8217;s one other change: adding in a call to <code>ObserveOnDispatcher<\/code> allows us to execute the <code>Subscribe<\/code> delegate (eg, update the arrow rotation) on the UI thread. We didn&#8217;t need to worry about that before because we were just debug printing, and not accessing any resources created on the UI thread.)<\/p>\n<p>Running the whole program now shows the compass arrow updating once every two seconds, correctly pointing to the device&#8217;s compass heading. Feel free to adjust the period from two seconds to something more useful&#8230; I found 0.5 seconds to be a good balance between update frequency and heading jitter.<\/p>\n<p>I&#8217;ve posted the complete example application on github, so feel free to check it out: <a href=\"https:\/\/github.com\/factormystic\/rx-compass-smoothing\">https:\/\/github.com\/factormystic\/rx-compass-smoothing<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Getting Started The challenge is to take the raw compass heading data, and smooth it out over time so the UI element this data is bound to (such as an arrow) won&#8217;t be jittery. You can see this jitter in the SDK example for the Compass: the\u00a0CurrentValueChanged event handler is fired every 20ms and jitters [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30,28,29],"tags":[],"class_list":["post-286","post","type-post","status-publish","format-standard","hentry","category-c-sharp","category-reactive-extensions","category-windows-phone"],"_links":{"self":[{"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/posts\/286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/comments?post=286"}],"version-history":[{"count":16,"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/posts\/286\/revisions"}],"predecessor-version":[{"id":420,"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/posts\/286\/revisions\/420"}],"wp:attachment":[{"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/media?parent=286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/categories?post=286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/factormystic.net\/blog\/wp-json\/wp\/v2\/tags?post=286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}