Node.js 卡尔曼滤波器一维

Node.js kalman filter 1D

首先,您好,我正在 node.js javascript 使用 Ibeacon 进行内部定位。作为我工作中的帮手:我使用 Evothings Studio。我正在将我的代码传输到 Evothings 工作室,并通过我的 android 和 ios 手机 phone 查看我的作品。现在我想告诉你我遇到的问题。根据RSSI Signal level,我发现计算的距离不是很准确。我想用卡尔曼滤波器来清除这个信号电平(RSSI)的噪声。本文介绍Javascript中卡尔曼滤波器的使用。据说很容易实现,但我无法开始练习。 “” 卡尔曼滤波器库:“https://github.com/wouterbulten/kalmanjs”。如何使用此卡尔曼滤波器清除 RSSI 信号中的噪声?如何将卡尔曼滤波器应用于这些代码?

var app = (function()
{
 // Application object.
 var app = {};

 // History of enter/exit events.
 var mRegionEvents = [];

 // Nearest ranged beacon.
 var mNearestBeacon = null;

 // Timer that displays nearby beacons.
 var mNearestBeaconDisplayTimer = null;

 // Background flag.
 var mAppInBackground = false;

 // Background notification id counter.
 var mNotificationId = 0;

 // Mapping of region event state names.
 // These are used in the event display string.
 var mRegionStateNames =
 {
  'CLRegionStateInside': 'Enter',
  'CLRegionStateOutside': 'Exit'
 };

 // Here monitored regions are defined.
 // TODO: Update with uuid/major/minor for your beacons.
 // You can add as many beacons as you want to use.
 var mRegions =
 [
  {
   id: 'BEACON1',
   uuid: 'fda50693-a4e2-4fb1-afcf-c6eb07647825',
   major: 10035,
   minor: 56498
  },
  {
   id: 'region2',
   uuid: 'f7826da6-4fa2-4e98-8024-bc5b71e0893e',
   major: 60378,
   minor: 22122
  }
 ];

 // Region data is defined here. Mapping used is from
 // region id to a string. You can adapt this to your
 // own needs, and add other data to be displayed.
 // TODO: Update with major/minor for your own beacons.
 var mRegionData =
 {
  'BEACON1': 'WGX_BEACON1',
  'region2': 'Region Two'
 };

 app.initialize = function()
 {
  document.addEventListener('deviceready', onDeviceReady, false);
  document.addEventListener('pause', onAppToBackground, false);
  document.addEventListener('resume', onAppToForeground, false);
 };

 function onDeviceReady()
 {
  startMonitoringAndRanging();
  startNearestBeaconDisplayTimer();
  displayRegionEvents();
 }

 function onAppToBackground()
 {
  mAppInBackground = true;
  stopNearestBeaconDisplayTimer();
 }

 function onAppToForeground()
 {
  mAppInBackground = false;
  startNearestBeaconDisplayTimer();
  displayRegionEvents();
 }

 function startNearestBeaconDisplayTimer()
 {
  mNearestBeaconDisplayTimer = setInterval(displayNearestBeacon, 1000);
 }

 function stopNearestBeaconDisplayTimer()
 {
  clearInterval(mNearestBeaconDisplayTimer);
  mNearestBeaconDisplayTimer = null;
 }

 function startMonitoringAndRanging()
 {
  function onDidDetermineStateForRegion(result)
  {
   saveRegionEvent(result.state, result.region.identifier);
   displayRecentRegionEvent();
  }

  function onDidRangeBeaconsInRegion(result)
  {
   updateNearestBeacon(result.beacons);
  }

  function onError(errorMessage)
  {
   console.log('Monitoring beacons did fail: ' + errorMessage);
  }

  // Request permission from user to access location info.
  cordova.plugins.locationManager.requestAlwaysAuthorization();

  // Create delegate object that holds beacon callback functions.
  var delegate = new cordova.plugins.locationManager.Delegate();
  cordova.plugins.locationManager.setDelegate(delegate);

  // Set delegate functions.
  delegate.didDetermineStateForRegion = onDidDetermineStateForRegion;
  delegate.didRangeBeaconsInRegion = onDidRangeBeaconsInRegion;

  // Start monitoring and ranging beacons.
  startMonitoringAndRangingRegions(mRegions, onError);
 }

 function startMonitoringAndRangingRegions(regions, errorCallback)
 {
  // Start monitoring and ranging regions.
  for (var i in regions)
  {
   startMonitoringAndRangingRegion(regions[i], errorCallback);
  }
 }

 function startMonitoringAndRangingRegion(region, errorCallback)
 {
  // Create a region object.
  var beaconRegion = new cordova.plugins.locationManager.BeaconRegion(
   region.id,
   region.uuid,
   region.major,
   region.minor);

  // Start ranging.
  cordova.plugins.locationManager.startRangingBeaconsInRegion(beaconRegion)
   .fail(errorCallback)
   .done();

  // Start monitoring.
  cordova.plugins.locationManager.startMonitoringForRegion(beaconRegion)
   .fail(errorCallback)
   .done();
 }

 function saveRegionEvent(eventType, regionId)
 {
  // Save event.
  mRegionEvents.push(
  {
   type: eventType,
   time: getTimeNow(),
   regionId: regionId
  });

  // Truncate if more than ten entries.
  if (mRegionEvents.length > 10)
  {
   mRegionEvents.shift();
  }
 }

 function getBeaconId(beacon)
 {
  return beacon.uuid + ':' + beacon.major + ':' + beacon.minor;
 }

 function isSameBeacon(beacon1, beacon2)
 {
  return getBeaconId(beacon1) == getBeaconId(beacon2);
 }

 function isNearerThan(beacon1, beacon2)
 {
  return beacon1.accuracy > 0
   && beacon2.accuracy > 0
   && beacon1.accuracy < beacon2.accuracy;
 }

 function updateNearestBeacon(beacons)
 {
  for (var i = 0; i < beacons.length; ++i)
  {
   var beacon = beacons[i];
   if (!mNearestBeacon)
   {
    mNearestBeacon = beacon;
   }
   else
   {
    if (isSameBeacon(beacon, mNearestBeacon) ||
     isNearerThan(beacon, mNearestBeacon))
    {
     mNearestBeacon = beacon;
    }
   }
  }
 }

 function displayNearestBeacon()
 {
  if (!mNearestBeacon) { return; }

  // Clear element.
  $('#beacon').empty();

  // Update element.
  var element = $(
   '<li>'
   + '<strong>BEACON1</strong><br />'
   + 'UUID: ' + mNearestBeacon.uuid + '<br />'
   + 'Major: ' + mNearestBeacon.major + '<br />'
   + 'Minor: ' + mNearestBeacon.minor + '<br />'
   + 'Distance: ' + mNearestBeacon.accuracy + '<br />'
   + 'RSSI: ' + mNearestBeacon.rssi + '<br />'
   + '</li>'
   );
  $('#beacon').append(element);
 }

 function displayRecentRegionEvent()
 {
  if (mAppInBackground)
  {
   // Set notification title.
   var event = mRegionEvents[mRegionEvents.length - 1];
   if (!event) { return; }
   var title = getEventDisplayString(event);

   // Create notification.
   cordova.plugins.notification.local.schedule({
       id: ++mNotificationId,
       title: title });
  }
  else
  {
   displayRegionEvents();
  }
 }

 function displayRegionEvents()
 {
  // Clear list.
  $('#events').empty();

  // Update list.
  for (var i = mRegionEvents.length - 1; i >= 0; --i)
  {
   var event = mRegionEvents[i];
   var title = getEventDisplayString(event);
   var element = $(
    '<li>'
    + '<strong>' + title + '</strong>'
    + '</li>'
    );
   $('#events').append(element);
  }

  // If the list is empty display a help text.
  if (mRegionEvents.length <= 0)
  {
   var element = $(
    '<li>'
    + '<strong>'
    + 'İbeacon Taramasi Yapiliyor.'
    + '</strong>'
    + '</li>'
    );
   $('#events').append(element);
  }
 }

 function getEventDisplayString(event)
 {
  return event.time + ': '
   + mRegionStateNames[event.type] + ' '
   + mRegionData[event.regionId];
 }

 function getTimeNow()
 {
  function pad(n)
  {
   return (n < 10) ? '0' + n : n;
  }

  function format(h, m, s)
  {
   return pad(h) + ':' + pad(m)  + ':' + pad(s);
  }

  var d = new Date();
  return format(d.getHours(), d.getMinutes(), d.getSeconds());
 }

 return app;

})();

app.initialize();

完成卡尔曼滤波器试验后,您可能会发现距离估计的误差仍然过高。这是因为 RSSI 测量中除了随机噪声之外还有其他误差源,其中许多误差源可能是影响接收器测量的无线电信号电平的其他变量(例如反射、障碍物、天线方向图变化)的函数。

一般来说,使用基于 RSSI 的直接距离计算最多只能在 1 米的真实距离处估计 0.5-2 米的准确度,而在更远的距离处准确度要低得多。即使在使用卡尔曼滤波器或 运行 平均值滤除噪声后也是如此。 (注意 iOS 距离估计在 RSSI 上使用 20 秒 运行 平均值,CLBeacon 上的 RSSI 字段值在一秒内取平均值。)

如果使用三边测量或类似的方法来计算位置,您会发现您只能在不超过 1-2 米的非常短的距离内获得可行的结果。