Qu'est-ce qu'un algorithme pour rééchantillonner d'un taux variable vers un taux fixe?


27

J'ai un capteur qui rapporte ses lectures avec un horodatage et une valeur. Cependant, il ne génère pas de lectures à un taux fixe.

Je trouve que les données à taux variable sont difficiles à gérer. La plupart des filtres s'attendent à un taux d'échantillonnage fixe. Il est également plus facile de dessiner des graphiques avec un taux d'échantillonnage fixe.

Existe-t-il un algorithme pour rééchantillonner d'une fréquence d'échantillonnage variable à une fréquence d'échantillonnage fixe?


Ceci est une publication croisée de programmeurs. On m'a dit que c'était un meilleur endroit pour demander. programmers.stackexchange.com/questions/193795/…
FigBug

Qu'est-ce qui détermine quand le capteur signalera une lecture? Envoie-t-il une lecture uniquement lorsque la lecture change? Une approche simple serait de choisir un "intervalle d'échantillonnage virtuel" (T) qui est juste plus petit que le temps le plus court entre les lectures générées. À l'entrée de l'algorithme, stockez uniquement la dernière lecture signalée (CurrentReading). À la sortie de l'algorithme, signalez le CurrentReading comme un «nouvel échantillon» toutes les T secondes pour que le service de filtrage ou de graphique reçoive des lectures à un taux constant (toutes les T secondes). Je ne sais pas si cela est suffisant dans votre cas.
user2718

Il essaie d'échantillonner toutes les 5 ms ou 10 ms. Mais c'est une tâche de faible priorité, elle peut donc être manquée ou retardée. J'ai le timing précis à 1 ms. Le traitement se fait sur le PC, pas en temps réel, donc un algorithme lent est correct s'il est plus facile à implémenter.
FigBug

1
Avez-vous envisagé une reconstruction à Fourier? Il existe une transformée de Fourier basée sur des données inégalement échantillonnées. L'approche habituelle consiste à retransformer une image de Fourier en domaine temporel échantillonné de manière uniforme.
mbaitoff

3
Connaissez-vous des caractéristiques du signal sous-jacent que vous échantillonnez? Si les données espacées de manière irrégulière sont toujours à un taux d'échantillonnage raisonnablement élevé par rapport à la bande passante du signal mesuré, alors quelque chose de simple comme une interpolation polynomiale sur une grille temporelle régulièrement espacée pourrait fonctionner correctement.
Jason R

Réponses:


21

L'approche la plus simple consiste à effectuer une sorte d'interpolation spline comme le suggère Jim Clay (linéaire ou autre). Cependant, si vous avez le luxe du traitement par lots, et surtout si vous avez un ensemble surdéterminé d'échantillons non uniformes, il existe un algorithme de "reconstruction parfaite" qui est extrêmement élégant. Pour des raisons numériques, cela peut ne pas être pratique dans tous les cas, mais cela vaut au moins la peine d'être connu conceptuellement. J'ai d'abord lu à ce sujet dans cet article .

L'astuce consiste à considérer votre ensemble d'échantillons non uniformes comme ayant déjà été reconstruit à partir d'échantillons uniformes par interpolation sinc . En suivant la notation dans le papier:

y(t)=k=1Ny(kT)sin(π(tkT)/T)π(tkT)/T=k=1Ny(kT)sinc(tkTT).

Notez que cela fournit un ensemble d'équations linéaires, une pour chaque échantillon non uniforme , où les inconnues sont les échantillons équidistants , comme ceci:y ( k T )y(t)y(kT)

[y(t0)y(t1)y(tm)]=[sinc(t0TT)sinc(t02TT)sinc(t0nTT)sinc(t1TT)sinc(t12TT)sinc(t1nTT)sinc(tmTT)sinc(tm2TT)sinc(tmnTT)][y(T)y(2T)y(nT)].

Dans l'équation ci-dessus, est le nombre d'échantillons uniformes inconnus, est l'inverse de la fréquence d'échantillonnage uniforme et est le nombre d'échantillons non uniformes (qui peut être supérieur à ). En calculant la solution des moindres carrés de ce système, les échantillons uniformes peuvent être reconstruits. Techniquement, seuls échantillons non uniformes sont nécessaires, mais en fonction de leur «diffusion» dans le temps, la matrice d'interpolation peut être horriblement mal conditionnée . Lorsque c'est le cas, l'utilisation d'un plus grand nombre d'échantillons non uniformes est généralement utile.T m n nnTmnn

À titre d'exemple de jouet, voici une comparaison (en utilisant numpy ) entre la méthode ci-dessus et l'interpolation de spline cubique sur une grille légèrement instable:

Reconstruction Sinc vs Cubic Spline d'échantillons non uniformes

(Le code pour reproduire le graphique ci-dessus est inclus à la fin de cette réponse)

Tout cela étant dit, pour des méthodes robustes de haute qualité, commencer par quelque chose dans l'un des articles suivants serait probablement plus approprié:

A. Aldroubi et Karlheinz Grochenig, Échantillonnage non uniforme et reconstruction dans les espaces invariables par décalage , SIAM Rev., 2001, no. 4, 585-620. ( lien pdf ).

K. Grochenig et H. Schwab, Méthodes de reconstruction locale rapide pour l'échantillonnage non uniforme dans les espaces invariants par décalage , SIAM J. Matrix Anal. Appl., 24 (2003), 899- 913.

-

import numpy as np
import pylab as py

import scipy.interpolate as spi
import numpy.random as npr
import numpy.linalg as npl

npr.seed(0)

class Signal(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def plot(self, title):
        self._plot(title)
        py.plot(self.x, self.y ,'bo-')
        py.ylim([-1.8,1.8])
        py.plot(hires.x,hires.y, 'k-', alpha=.5)

    def _plot(self, title):
        py.grid()
        py.title(title)
        py.xlim([0.0,1.0])

    def sinc_resample(self, xnew):
        m,n = (len(self.x), len(xnew))
        T = 1./n
        A = np.zeros((m,n))

        for i in range(0,m):
            A[i,:] = np.sinc((self.x[i] - xnew)/T)

        return Signal(xnew, npl.lstsq(A,self.y)[0])

    def spline_resample(self, xnew):
        s = spi.splrep(self.x, self.y)
        return Signal(xnew, spi.splev(xnew, s))

class Error(Signal):

    def __init__(self, a, b):
        self.x = a.x
        self.y = np.abs(a.y - b.y)

    def plot(self, title):
        self._plot(title)
        py.plot(self.x, self.y, 'bo-')
        py.ylim([0.0,.5])

def grid(n): return np.linspace(0.0,1.0,n)
def sample(f, x): return Signal(x, f(x))

def random_offsets(n, amt=.5):
    return (amt/n) * (npr.random(n) - .5)

def jittered_grid(n, amt=.5):
    return np.sort(grid(n) + random_offsets(n,amt))

def f(x):
    t = np.pi * 2.0 * x
    return np.sin(t) + .5 * np.sin(14.0*t)

n = 30
m = n + 1

# Signals
even   = sample(f, np.r_[1:n+1] / float(n))
uneven = sample(f, jittered_grid(m))
hires  = sample(f, grid(10*n))

sinc   = uneven.sinc_resample(even.x)
spline = uneven.spline_resample(even.x)

sinc_err   = Error(sinc, even)
spline_err = Error(spline, even)

# Plot Labels
sn = lambda x,n: "%sly Sampled (%s points)" % (x,n)
r  = lambda x: "%s Reconstruction" % x
re = lambda x: "%s Error" % r(x)

plots = [
    [even,       sn("Even", n)],
    [uneven,     sn("Uneven", m)],
    [sinc,       r("Sinc")],
    [sinc_err,   re("Sinc")],
    [spline,     r("Cubic Spline")],
    [spline_err, re("Cubic Spline")]
]

for i in range(0,len(plots)):
    py.subplot(3, 2, i+1)
    p = plots[i]
    p[0].plot(p[1])

py.show()

Belle méthode et code. Mais pour avec quelques abandons (par exemple [0 1 - 3 4 5 - 7 8] T), ce qui, je pense, est la question des OP, les sinc dans la matrice ne sont-ils pas tous 0? Bien sûr, il existe des moyens de résoudre ce problème, mais. tj=jT
denis

Si je comprends bien, la question du PO concerne les échantillons qui sont abandonnés et / ou retardés. Cette méthode n'est fondamentalement qu'un système d'équations surdéterminé, de sorte que les échantillons déposés n'apparaissent que comme des inconnus (pas comme des points de données avec une valeur de 0). Ou peut-être que ce n'est pas ce que vous demandez?
datageist

Que se passe-t-il si les sont tous des entiers (T = 1)? Supposons que nous ayons des points de données [ ] pour , un ensemble d'entiers non nuls, par exemple {-1 1} ou {-2 -1 1 2}; n'est-ce pas le interpolé , quel que soit le - ou ai-je raté quelque chose? j , y j j Jtjj,yjjJy jy0=0yj
denis

Si les taux d'échantillonnage sont exactement identiques (avec des points manquants), la matrice d'interpolation sera clairsemée (car chaque sortie dépend d'une seule entrée). En général, le taux d'échantillonnage moyen des échantillons non uniformes doit être supérieur au taux de reconstruction uniforme. En d'autres termes, vous auriez besoin de reconstruire à un taux inférieur pour "combler les lacunes" (T> 1 pour votre exemple). Je vois votre point cependant.
datageist

2
De telles réponses sont en or pur.
Ahmed Fasih

6

Cela ressemble à un problème de conversion de fréquence d'échantillonnage asynchrone. Pour convertir d'un taux d'échantillonnage à un autre, nous pouvons calculer la représentation temporelle continue du signal en effectuant une interpolation sinc, puis rééchantillonner à notre nouveau taux d'échantillonnage. Ce que vous faites n'est pas très différent. Vous devez rééchantillonner votre signal pour avoir des temps d'échantillonnage fixes.

Le signal temporel continu peut être calculé en convoluant chaque échantillon avec une fonction sinc. Puisque la fonction sinc continue indéfiniment, nous utilisons quelque chose de plus pratique comme un sinc fenêtré d'une longueur finie pratique. La partie délicate est que parce que vos échantillons se déplacent dans le temps, un sinc avec un décalage de phase différent peut devoir être utilisé pour chaque échantillon lors du rééchantillonnage.

Signal temporel continu à partir du signal échantillonné:

x(t)=n=x[n]sinc(tnTsTs)

où est votre temps d'échantillonnage. Dans votre cas, cependant, votre temps d'échantillonnage n'est pas fixe. Je pense donc que vous devez le remplacer par le temps d'échantillonnage de cet échantillon.Ts

x(t)=n=x[n]sinc(tnTs[n]Ts[n])

De là, vous pouvez rééchantillonner le signal:

y[n]=x(nTns )

où est le temps d'échantillonnage souhaité.Tns

En mettant tout cela ensemble, vous obtenez:

y[m]=n=x[n]sinc(mTnsnTs[n]Ts[n])

Comme cela n'est pas causal ou traitable, la fonction sinc peut être remplacée par une fonction de support fini et les limites de sommation ajustées en conséquence.

Soit kernel (t) une fonction fen ou autre fonction similaire de longueur 2k alors:

y[m]=n=kkx[n]kernel(mTnsnTs[n]Ts[n])

J'espère que cela aide ..., mais j'ai peut-être fait une erreur en cours de route et cela pourrait être un peu intensif en mathématiques. Je recommanderais de rechercher la conversion de taux d'échantillonnage pour plus d'informations. Peut-être que quelqu'un d'autre ici pourrait également fournir une meilleure explication ou solution.


L'utilisation d'une fonction sinc pour reconstruire une version continue d'un signal nécessite que les échantillons soient également espacés, de sorte que la fonction sinc devra s'adapter à l'espacement des échantillons arbitraires. Pourrait être assez difficile à mettre en œuvre.
user2718

oui, ce ne serait pas très efficace de faire exactement comme on le voit ici. Cela nécessiterait de calculer de nouveaux coefficients de noyau pour chaque temps d'échantillonnage différent. Une collection de plusieurs noyaux pourrait cependant être calculée et le temps quantifié à l'un d'eux. Il y aurait un impact sur les performances par rapport à l'erreur de quantification.
Jacob

Vous pouvez également pré-calculer une seule table de recherche sinc et interpoler entre les points de cette table de recherche.
jms

5

Je pense que la réponse de Jacob est très réalisable.

Une méthode plus simple qui n'est probablement pas aussi bonne en termes d'introduction de distorsion consiste à effectuer une interpolation polynomiale. J'utiliserais soit une interpolation linéaire (facile, pas aussi bon en termes de performances de signal) ou des splines cubiques (toujours pas trop difficiles, de meilleures performances de signal) pour produire des échantillons à tout moment à partir de vos échantillons de temps arbitraires.


1
Votre réponse semble beaucoup plus facile à mettre en œuvre que celle de Jacob, donc je l'ai d'abord utilisé. Cela semble fonctionner, mais je n'ai pas encore exécuté un ensemble complet de tests.
FigBug

1
@FigBug -Si vous avez le temps, ajoutez un commentaire avec votre solution finale.
user2718

2

(Un mois plus tard), il existe deux choix principaux pour toute méthode d'interpolation:
1) le nombre de points de données le plus proche du point manquant à utiliser, 2 4 6 ... 2) la classe des fonctions de base à utiliser: linéaire, polynomiale, sinus-cosinus (Fourier), cubique par morceaux (spline B ou spline interpolante), de type sinc ... (Le choix 0 consiste à utiliser la méthode et le code de quelqu'un d'autre ou à faire soi-même.)Nnear

est facile d' une ligne droite à points : 2 points [-1, ], [1, ]: estimation points avec une moyenne : moyenne générale : voir par exemple Recettes numériques p. 781: ajuster une droite et estimer . On peut adapter les quadratiques, les cubiques, les sinus-cosinus ... de la même manière.y - 1 an 1Nnear
y1y1
[ x i , y i ] x i = 0y0(y1+y1)/2
[xi,yi]xi=0
y i [ x i , y i ]y0yi
[xi,yi]
y 0aa+bxy0a

Je comprends que vous avez des données uniformément espacées avec quelques points manquants, n'est-ce pas?
Dans quelle mesure l'interpolation linéaire fonctionne-t-elle dans ce cas?
Eh bien, essayons cos avec = 0,25: 1 0 -1 0 1 0 -1 0 ... 2 voisins de toute moyenne à 0, terrible. 4 voisins: moyenne de [1 0 (manque -1) 0 1] = 1/2, terrible. (Essayez le filtre à 4 voisins [-1 3 3 -1] / 4 à ce sujet.)f2πftf


L'interplation linéaire avec 4 ou 6 ou 8 voisins peut fonctionner assez bien pour vos données.
Je suggérerais de commencer par une méthode que vous comprenez bien avant de plonger dans les splines, de manière sincère ... bien que celles-ci puissent aussi être amusantes.


Une autre méthode, assez différente, est la pondération de distance inverse . Il est facile à implémenter (voir idw-interpolation-with-python sur SO), fonctionne aussi en 2D 3d et plus, mais est afaik difficile à analyser théoriquement.

(Évidemment, AUCUNE méthode d'interpolation unique ne peut correspondre aux millions de combinaisons de
[signal, bruit, mesure d'erreur, fonction de test] qui se produisent dans la réalité.
Il existe plus de méthodes dans le monde, avec plus de boutons, que de fonctions de test.
Néanmoins, une galerie des méthodes et des fonctions de test peuvent être utiles.)


1

Si vous travaillez avec matlab, vous pouvez le faire en travaillant avec la série temporelle.

time  % is your starting vector of time

data % vector of data you want to resample 

data_TS = timeseries(data,time); % define the data as a timeseries 

new_time = time(0):dt:time(end); % new vector of time with fixed dt=1/fs

data_res = resample(data_TS,new_time); % data resampled at constant fs

0

Avant de vous lancer dans un traitement exotique, vous pouvez essayer quelque chose de simple comme ça (pseudo-code - pas d'interpolation, mais qui pourrait être ajouté)

TimeStamp[]  //Array of Sensor TimeStamps -NULL terminated – TimeStamp[i] corresponds to Reading[i]
Reading[]      //Array of Sensor Readings       -NULL terminated

AlgorithmOut   //Delimited file of of readings in fixed sample time (5ms) 
CurrentSavedReading = Reading[0]

SampleTime=TimeStamp[0] //ms virtual sample time, 5ms fixed samples

i = 0 // loop index
While(TimeStamp[i] != NULL)
{
   FileWrite (CurrentSavedReading, AlgorithmOut)//write value to file
   SampleTime = SampleTime + 5//ms
   if(SampleTime > TimeStamp[i])
   {
      i++
      CurrentSavedReading = Reading[i]
   }
}

0

La réponse de IMHO Datageist est correcte, la réponse de Jacob ne l'est pas. Un moyen facile de vérifier cela est que l'algorithme suggéré par le datageist est garanti pour interpoler à travers les échantillons originaux (en supposant une précision numérique infinie), contrairement à la réponse de Jacob.

  • Pour le cas d'échantillonnage uniforme, l'ensemble des fonctions sinc est orthogonal: si chaque fonction sinc décalée est discrétisée sur les échantillons d'entrée, elles forment une matrice d'identité infinie. En effet, sin (n pi) / (n pi) est nul pour tout n sauf n = 0.
  • Cependant, cette propriété ne peut pas simplement être extrapolée au cas non uniforme: un ensemble similaire de fonctions sinc, discrétisées sur les échantillons d'entrée, produira une matrice non triviale. Par conséquent, les contributions des échantillons environnants ne seront pas nulles et la reconstruction ne sera plus interpolée à travers les échantillons d'entrée.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.