Allan 方差简介
Allan方差分析主要用于分析陀螺量化噪声,一般用于分析(以下内容针对于陀螺仪的allan方差分析,对于加速度计都是类似的)量化噪声(一般不一定能从allan上看出来)
角度随机游走
零偏不稳定性
角速率随机游走
速率斜坡(一般不一定能从allan上看出来)
Allan方差分析的一个用途是分析陀螺的性能或者对比不同陀螺的性能。若是将几个陀螺的Allan方差曲线同时绘制一个双对数图上,曲线在左下角的对应的陀螺性能一般比较好一些(激光陀螺),而右上差(MEMS)。
斜率意义:
matlab实践环境:(matlab2019, 安装sensor fusion toolbox),主要参考matlab自带的 AllanVarianceExample.m
其实allan方差计算并不复杂,下面的例子只针对陀螺,把陀螺建模为:
其中我们只关心:N: angle random walk(-1/2斜率)
K: rate random walk(1/2斜率)
B: bias instability(0斜率)
理由引严老师的原文:Allan方差可用于分析五种典型误差,但是某个陀螺中并不一定五种误差都有同时表现出来,不画Allan方差图/不肉眼看图,而盲目的采用最小二乘回归方法强行地就想求解五个系数的人是典型的教条主义者,往往得不到好的结果。比如如下Allan方差图中y曲线所示(摘自https://github.com/ethz-asl/kalibr/wiki/IMU-Noise-Model),采用“三段论”大概读图计算角度随机游走系数、零偏不稳定性和角速率随机游走(或速率斜坡)即可,完全可满足实际应用。过细分析想得出精确系数的人都是有洁癖的。
手撸一个allan曲线记录静态条件下陀螺数据,总长度为L, 采样周期为
,
为所有采样记录的样本, 这里
,采样率=100。 这个matlab自带的数据集的陀螺的单位为rad/s
% Load logged data from one axis of a three-axis gyroscope. This recording
% was done over a six hour period with a 100 Hz sampling rate.
load('LoggedSingleAxisGyroscope', 'omega', 'Fs')
t0 = 1/Fs;
2. 计算每一时刻下的累积角度:
theta = cumsum(omega, 1)*t0;
3. 计算allan方差
maxNumM = 100;
L = size(theta, 1);
maxM = 2.^floor(log2(L/2));
m = logspace(log10(1), log10(maxM), maxNumM).';
m = ceil(m); % m must be an integer.
m = unique(m); % Remove duplicates.
tau = m*t0;
avar = zeros(numel(m), 1);
for i = 1:numel(m)
mi = m(i);
avar(i,:) = sum( ...
(theta(1+2*mi:L) - 2*theta(1+mi:L-mi) + theta(1:L-2*mi)).^2, 1);
end
avar = avar ./ (2*tau.^2 .* (L - 2*m));
4. 最后计算
并作图:
adev = sqrt(avar);
figure
loglog(tau, adev)
title('Allan Deviation')
xlabel('\tau');
ylabel('\sigma(\tau)')
grid on
axis equal这样allan方差就画出来了,一定要注意Y轴的单位,1.是方差,还是标准差? 2.单位有的人用rad/s,有的人用deg/s, 更多的人用rad/h
使用matlab自带的allan函数
自己手撸太麻烦,用起来也心惊胆战的,不如拿来主义,直接用matlab自带的allan函数allanvar。
[avarFromFunc, tauFromFunc] = allanvar(omega, m, Fs);
adevFromFunc = sqrt(avarFromFunc);
figure
loglog(tau, adev, tauFromFunc, adevFromFunc);
title('Allan Deviations')
xlabel('\tau')
ylabel('\sigma(\tau)')
legend('Manual Calculation', 'allanvar Function')
grid on
axis equal这是自己撸和使用自带allanvar的曲线,一样得嘛!
使用allan曲线计算零篇稳定性,角度随机游走和角速率随机游走
这个地方就不展开了,我直接封装了一个matlab函数ch_allan, 其中调用allanvar 并且自动拟合直线计算N,K,B值, 注意输入单位必须是rad/s
%% ('NoiseDensity(角度随机游走)', N, 'RandomWalk(角速率随机游走)', K,'BiasInstability(零偏稳定性)', B);
% omega 必须为 rad/s
% see Freescale AN: Allan Variance: Noise Analysis for Gyroscopes
function[avar, tau, N, K, B] =ch_allan(omega, Fs, is_plot)[avar, tau] = allanvar(omega, 'octave', Fs);
adev = sqrt(avar);
%% Angle Random Walk
slope = -0.5;
logtau = log10(tau);
logadev = log10(adev);
dlogadev = diff(logadev) ./ diff(logtau);
[~, i] = min(abs(dlogadev - slope));
% Find the y-intercept of the line.
b = logadev(i) - slope*logtau(i);
% Determine the angle random walk coefficient from the line.
logN = slope*log(1) + b;
N = 10^logN;
% Plot the results.
tauN = 1;
lineN = N ./ sqrt(tau);
%% Rate Random Walk
slope = 0.5;
logtau = log10(tau);
logadev = log10(adev);
dlogadev = diff(logadev) ./ diff(logtau);
[~, i] = min(abs(dlogadev - slope));
% Find the y-intercept of the line.
b = logadev(i) - slope*logtau(i);
% Determine the rate random walk coefficient from the line.
logK = slope*log10(3) + b;
K = 10^logK;
% Plot the results.
tauK = 3;
lineK = K .* sqrt(tau/3);
%% Bias Instability
slope = 0;
logtau = log10(tau);
logadev = log10(adev);
dlogadev = diff(logadev) ./ diff(logtau);
[~, i] = min(abs(dlogadev - slope));
% Find the y-intercept of the line.
b = logadev(i) - slope*logtau(i);
% Determine the bias instability coefficient from the line.
scfB = sqrt(2*log(2)/pi);
logB = b - log10(scfB);
B = 10^logB;
% Plot the results.
tauB = tau(i);
lineB = B * scfB * ones(size(tau));
if is_plot == true
tauParams = [tauN, tauK, tauB];
params = [N, K, scfB*B];
figure
loglog(tau, adev, tau, [lineN, lineK, lineB], '--', tauParams, params, 'o');
title('Allan Deviation with Noise Parameters')
xlabel('\tau')
ylabel('\sigma(\tau)')
legend('\sigma', '\sigma_N', '\sigma_K', '\sigma_B')
text(tauParams, params, {'N', 'K', '0.664B'})
grid on
axis equal
end
end
使用实例,这里用gnss-ins-sim 这个仿真库产生静态陀螺数据,然后用ch_allan来分析,并对比allan出来的参数是否和生成仿真数据时设置的参数一致
clear;
clc;
close all;
%% https://github.com/Aceinna/gnss-ins-sim
% VRW 单位: m/s/sqrt(hr) 'accel_vrw': np.array([0.3119, 0.6009, 0.9779]) * 1.0,
% 加速度零偏不稳定性: m/s^(2) 'accel_b_stability': np.array([1e-3, 3e-3, 5e-3]) * 1.0,
% ARW 单位: deg/sqrt(hr) 'gyro_arw': np.array([0.25, 0.25, 0.25]) * 1.0,
% 角速度零偏稳定性: deg/h 'gyro_b_stability': np.array([3.5, 3.5, 3.5]) * 1.0,
M = csvread('gyro-0.csv',1 ,0);
gyroReading = M(:,1);
gyroReading = deg2rad(gyroReading);
M = csvread('accel-0.csv',1 ,0);
Fs = 100;
accelReading = M(:,1);
%% 运行陀螺 allan
[avar1, tau1 , N, K, B] = ch_allan(gyroReading , Fs, true);
fprintf('GYR: 零偏不稳定性 %frad/s 或 %fdeg/h \n', B, rad2deg(B)*3600);
fprintf('GYR: 噪声密度(角度随机游走, ARW, Noise density) %f(rad/s)/sqrt(Hz) 或 %f deg/sqrt(h)\n', N, rad2deg(N)*3600^(0.5));
fprintf('GYR: 角速率随机游走, bias variations ("random walks") %f(rad/s)sqrt(Hz) 或 %f deg/h/sqrt(h)\n', K, rad2deg(K) * (3600^(1.5)));
%% 运行加速度计 allan
[avar1, tau1 , N, K, B] = ch_allan(accelReading, Fs, true);
fprintf('ACC: 零偏不稳定性 %fm/s^(2) 或 %fmg 或 %fug\n', B, B / 9.80665 *1000, B / 9.80665 *1000*1000);
fprintf('ACC: 噪声密度(速率随机游走,VRW, Noise Density, Rate Noise Density) %f(m/s^(2))/sqrt(Hz) 或 %f m/s/sqrt(hr)\n', N, N * 3600^(0.5));
fprintf('ACC: 加速度随机游走,bias variations ("random walks") %f(m/s^(2)sqrt(Hz))\n', K);
运行结果:(和仿真时设置的参数基本相同)
参考