2015-09-29 4 views
0

Допустим, у меня есть файл с 44100 образцами, сэмплированный при fs = 44100 Гц. Так что мой файл длится 1 секунда.Даунсэмпл путем вычисления среднего значения в MATLAB

Я хочу уменьшить эту частоту до 8 Гц, но я хочу сделать это НЕ, взяв каждый образец 44100/8 = 5512,5 и сохранить в новом массиве. Но, взяв среднее значение первых 5512 выборок, сохраните на месте 1 нового массива. Затем возьмите образец 5513-11024, среднее значение этого и сохраните на месте 2 нового массива. И так далее ... И возьмите образец 11025 до 11025 + 5512 и поставьте среднее значение этого на место 3 массива.

Я знаю, что это должен быть какой-то двойной цикл, но я просто не могу понять, как ... Любая помощь?

EDIT:

Код, который в очень ручном способе делает то, что я ищу.

`fs = 44100;
fo = 8;
A = randn (44100,1); % Массива проб при фс = 44100 со случайными данными

A_resampled = zeros(numel(A)/5512);  

first_block = zeros(5512,1); 

for i = 1:length(first_block) 
    first_block(i) = A(i); 
end 

first_mean_value = mean(first_block); 

A_resampled(1) = first_mean_value; 

second_block = zeros(5512,1); 

for k = 5513:5512+length(second_block) 
    second_block(k) = A(k); 
end 

second_mean_value = mean(second_block); 

A_resampled(2) = second_mean_value;` 

и так далее ...

+0

Одиночный цикл достаточно. попробуй, и мы поможем, когда увидим какой-то код. –

ответ

2

Как насчет использования accumarray?Пусть x обозначает ваш входной вектор. Тогда

n = ceil((1:numel(x))/5512.5); %// blocks of 5512, 5513, 5512, 5513... samples 
result = accumarray(n(:), x (:), [], @mean); 

Обратите внимание, что n автоматически определяет неодинаковых размеров блоков, отличающийся по одному образцу в большинстве, чтобы они соответствовали вашему дробно целевого размера блока. В вашем примере размеры блоков: 5512, 5513, 5512, 5513 ...

+0

Ну, это, безусловно, умный! Проголосовать. +1. – rayryeng

+0

Спасибо за ответ. Но это не делает то, что мне нужно. Возможно, я недостаточно хорошо объяснил себе. Я постараюсь опубликовать какой-то код (в главном сообщении), который делает то, что им после очень ручным способом, возможно, это облегчит понимание. Но спасибо вам большое. – ELEFAAANT

+0

Боже, извините, ребята, мой тест был не прав, и оба @rayryeng и Luis Mendo дали правильные результаты. Переход с Mendo, поскольку это более правильный результат при переключении между кусками 5512 и 5513. – ELEFAAANT

2
sampling = 1:5512:length(sample); 
resampled = zeros(numel(sampling),1); 
for ii = 1:length(sampling)-1 
    resampled(ii,1) = mean(sampling(ii:ii+1)); 
end 

sampling представляет собой массив с индексами, чтобы начать отбор проб, а затем цикл просто принимает среднее значение всех тех, биты.

+0

Ты знаешь, что сказал бы Дивакар о твоих циклах, rigtht? : -P Но ОП попросил об этом, так что +1 –

+0

Whoopsy @rayryeng просто добавил, что, спасибо! – Adriaan

+0

Спасибо за ответ. Но это не делает то, что мне нужно. Возможно, я недостаточно хорошо объяснил себе. Я постараюсь опубликовать какой-то код (в главном сообщении), который делает то, что им после очень ручным способом, возможно, это облегчит понимание. Но спасибо вам большое. – ELEFAAANT

2

reshape массив в 2D-матрицу, затем найдите mean вдоль столбцов. Чтобы убедиться, что мы можем сделать это правильно, мы собираемся заполнить конец массива, чтобы убедиться, что ваш сигнал является целым числом, кратным fs/fo, где fs - частота выборки, а fo - желаемая частота. так что это будет 44.1 kHz и 8 Hz соответственно.

Таким образом, предполагается, что ваш сигнал сохраняется в A, сделайте следующее:

%// Defines 
A = ....; %// Define your array here 
fs = 44100; %// Sampling frequency 
fo = 8; %// Desired frequency 

%// Determine how many samples there are per chunk 
samples_per_chunk = floor(fs/fo); 

%// Determine how many total chunks there are 
num_chunks = ceil(numel(A)/samples_per_chunk); 

%// Create a padded array where it is an integer multiple 
%// of the chunk size and insert the original array into this padded 
%// array 
Apad = zeros(samples_per_chunk*num_chunks,1); 
Apad(1:numel(A)) = A; 

%// Reshape into 2D matrix 
M = reshape(Apad, [], num_chunks); 

%// Find average per chunk 
out = mean(M, 1); 

Однако следствие с этим, что если ваш массив не может быть целым числом, кратным fs/fo, вы будете без необходимости усредняя кучу нулей, которые добавляются в конец массива. Если вы не хотите, чтобы это произошло, одним из способов было бы создать матрицу, первоначально заполненную NaN, и вместо этого использовать nanmean, так что ни одно из значений, которое равно NaN, не включено в среднее значение ... таким образом, фактически игнорируя добавленные значения ,

Что-то, как это будет работать вместо того, чтобы:

%// Code as before.. 
%// ... 
%// ... 

%// New 
Apad = nan(samples_per_chunk*num_chunks,1); 
Apad(1:numel(A)) = A; 

M = reshape(Apad, [], num_chunks); 
out = nanmean(M, 1); 

Однако nanmean требует Statistics Toolbox. Если у вас этого нет, вы можете сами реализовать nanmean. После того, как вы измените размер массива на матрицу M, подсчитайте количество NaN элементов, имеющихся за столбец, и вычислите средний результат, суммируя все столбцы и деля на общее количество записей, которые не являются NaN.

%// Code as before... 
%//.... 
%//.... 

%// New 
M = reshape(Apad, [], num_chunks); 

%// Count how total number of NaN values 
counts = sum(isnan(M), 1); 

%// Set NaN values to zero to not affect mean 
M(isnan(M)) = 0; 

%// Calculate new average 
out = sum(M,2) ./ (size(M,1) - counts); 
+0

Красиво сделано! Полностью векторизованный –

+0

@ LuisMendo - Спасибо :) Обратите внимание на явное использование '1' в' mean';) – rayryeng

+0

Oooh ... Я этого не заметил. Не могли бы вы добавить «.» Где-нибудь, чтобы сделать его красивее? :-D –

Смежные вопросы