2
votes

moyenne mobile arbitrairement pondérée (filtres passe-bas et passe-haut)

Étant donné le signal d'entrée x (par exemple une tension, échantillonnée mille fois par seconde pendant quelques minutes), j'aimerais calculer par exemple

/ this is not q
y[3] = -3*x[0] - x[1] + x[2] + 3*x[3]
y[4] = -3*x[1] - x[2] + x[3] + 3*x[4]
. . .

I ' m visant une longueur de fenêtre variable et des coefficients de poids. Comment puis-je le faire en q? Je connais mavg et traitement du signal en q et qidiom de somme mobile

Dans le monde DSP, cela s'appelle appliquer un noyau de filtre en faisant une convolution. Les coefficients de pondération définissent le noyau, qui crée un filtre passe-haut ou passe-bas. L'exemple ci-dessus calcule la pente à partir des quatre derniers points, en plaçant la ligne droite via la méthode des moindres carrés.


0 commentaires

3 Réponses :


3
votes

Quelque chose comme ça fonctionnerait pour les coefficients paramétrables:

q)g:{prev[deltas x]+3*x-3 xprev x}
q)g[x]~f[3 1 -1 -3]x
1b
q)\t:100000 f[3 1 1 -3] x
4612
q)\t:100000 g x
1791

Des cas spécifiques peuvent être rendus un peu plus rapides (exécuter 0 xprev n'est pas la meilleure chose)

q)x:10+sums -1+1000?2f
q)f:{sum x*til[count x]xprev\:y}
q)f[3 1 -1 -3] x
0n 0n 0n -2.385585 1.423811 2.771659 2.065391 -0.951051 -1.323334 -0.8614857 ..


0 commentaires

0
votes

Si votre liste d'entrée n'est pas grande, vous pouvez utiliser la technique mentionnée ici: https://code.kx.com/q/cookbook/programming-idioms/#how-do-i-apply-a-function-to-a-sequence-sliding-window

Cela utilise l'adverbe «scan». Comme ce processus crée plusieurs listes qui pourraient être inefficaces pour les grandes listes.

Une autre solution utilisant scan est:

 q) f:{[l;w;i]sum w*l i+til 4} / w- weight, l- input list, i-current index
 q) f[x;-3 -1 1 3]@'til count x

Cette fonction crée également plusieurs listes donc encore peut ne pas être très efficace pour les grandes listes.

Une autre option consiste à utiliser des index pour récupérer les éléments cibles de la liste d'entrée et effectuer le calcul. Cela ne fonctionnera que sur la liste d'entrée.

 q)f:{sum y*next\[z;x]} / x-input list, y-weights, z-window size-1
 q)f[x;-3 -1 1 3;3]

C'est une fonction très basique. Vous pouvez y ajouter plus de variables selon vos besoins.


0 commentaires

1
votes

C'est peut-être un peu vieux, mais j'ai pensé que j'y reviendrais. Il y a un article que j'ai écrit l'année dernière sur le traitement du signal qui peut avoir une certaine valeur. En travaillant uniquement dans KDB, en fonction des tailles de signal que vous utilisez, vous verrez de bien meilleures performances avec une convolution basée sur FFT entre le noyau / la fenêtre et le signal.

Cependant, je n'ai écrit qu'une simple FFT radix-2, bien que dans mon repo github, je dispose du travail non testé pour un algorithme Bluestein plus flexible qui permettra une longueur de signal plus variable. https://github.com/callumjbiggs/q-signals/blob/ master / signal.q

Si vous souhaitez effectuer une convolution manuelle complète par une somme mobile, alors la meilleure méthode serait de la diviser en blocs égaux au taille du noyau / de la fenêtre (basée sur un travail qu'Arthur W a fait il y a de nombreuses années)

q)vec:10000?100.0
q)weights:30?1.0
q)wsize:count weights
q)(weights$(((wsize-1)#0.0),vec)til[wsize]+) each til count v
32.5931 75.54583 100.4159 124.0514 105.3138 117.532 179.2236 200.5387 232.168.


0 commentaires