추천 게시물
FFT 예제: 윈도우 적용 시 Normalized Wegith Value, SNR 계산, Sinusoidal + Noise Signal Generation, Prime Cycle Frequency 등 포함
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
목차
측정한 신호를 FFT로 변환하기 위해서는 다양한 방법들을 고려 해야 한다. 단순히 인터넷에 있는 ideal sinewave를 바탕으로 깔끔하게 나온 FFT 결과는 현실적으로 적용하기 어렵기 때문이다.
아래 항목들이 측정 및 FFT 코드 작성 시 고민해야할 사항이다.
1. Normalize
2. Sine wave cycle
3. Signal and Noise power, rms calculation
4. Window selection and weight
각각의 항목에 관해서는 나중에 별도의 글로 다시 정리할 예정이다.
아래는 위의 사항을 고려하여 작성한 FFT 코드이다.
OCTAVE를 기준으로 작성되었다.
FFT 코드
clc;
pkg load signal;
pkg load io;
% Functions
function weight_result = fft_weight2(window, NFFT)
%weight_result=1/sum(abs(fft(window,NFFT)./NFFT.*2));
window_fft=abs(fft(window,NFFT)./NFFT);
weight_result=1/sqrt(sum(window_fft.^2))
%window2=window.^2;
%weight_result=sqrt(sum(abs(fft(window2,NFFT)./NFFT)));
return;
end
function adjusted_frequency = closest_prime_frequency(sampling_time, target_frequency)
% Calculate the number of cycles for the target frequency
num_cycles = sampling_time * target_frequency;
% Define the search range around num_cycles
search_range = 1000;
% Calculate the lower and upper bounds for prime search
lower_bound = max(2, floor(num_cycles - search_range));
upper_bound = ceil(num_cycles + search_range);
% Generate the list of prime numbers within the search range
primes_list = primes(upper_bound);
primes_list = primes_list(primes_list >= lower_bound);
% Find the prime number closest to the calculated number of cycles
[~, idx] = min(abs(primes_list - num_cycles));
closest_prime = primes_list(idx);
% Calculate the adjusted frequency
adjusted_frequency = closest_prime / sampling_time;
% Display the results
%{
fprintf('Original Frequency: %.8f Hz\n', target_frequency);
fprintf('Sampling Time: %.8f seconds\n', sampling_time);
fprintf('Closest Prime Number of Cycles: %d\n', closest_prime);
fprintf('Adjusted Frequency: %.8f Hz\n', adjusted_frequency);
%}
% Return the adjusted frequency
return;
end
# Functions Ends
% Parameters
Fs = 256; % 샘플링 주파수
T = 1/Fs; % 샘플링 주기
NFFT = 2^14; % 신호 길이 (NFFT)
t = (0:NFFT-1)*T; % 시간 벡터
hanning_window = hann(NFFT)'; % weight 1.633
hamming_window = hamming(NFFT)'; % weight 1.58635
flattop_window = flattopwin(NFFT)'; % weight 2.3898
blackman_window = blackman(NFFT)'; % wieght 1.812
%time domain window weight calculation
hanning_weight=1/((sum(hanning_window.^2)./NFFT)^0.5)
hamming_weight=1/((sum(hamming_window.^2)./NFFT)^0.5)
flattop_weight=1/((sum(flattop_window.^2)./NFFT)^0.5)
blackman_weight=1/((sum(blackman_window.^2)./NFFT)^0.5)
%frequency domain window wieght calculation
hanning_weight2=fft_weight2(hanning_window,NFFT)
hamming_weight2=fft_weight2(hamming_window,NFFT)
flattop_weight2=fft_weight2(flattop_window,NFFT)
blackman_weight2=fft_weight2(blackman_window,NFFT)
sig_rms_arr=zeros(2,100);
noise_rms_arr=zeros(2,100);
for i=1:1 % Freq.에 따라 window 적용 후 power 일정함 확인
% Signal A V @ f0 Hz sinewave
f0 = i; % 신호 주파수
A = 10; % 10V peak 진폭
fsig=closest_prime_frequency(T*NFFT, f0);
signal = (A) * sin(2*pi*fsig*t);
% Noise B: noise_rms Vrms 랜덤 노이즈
noise_rms = 1; % 1Vrms
noise = noise_rms * randn(size(t));
noise_std = std(noise);
% Combined signal
combined_signal = signal + noise;
combined_signal_win = combined_signal .* hanning_window.*1.633;
%combined_signal_win = combined_signal .* hamming_window.*1.5859;
%combined_signal_win = combined_signal .* flattop_window.*2.387;
%combined_signal_win = combined_signal .* blackman_window.*1.81;
% FFT
%Y = fft(combined_signal, NFFT);
Y = fft(combined_signal_win, NFFT);
P2 = abs(Y/NFFT); % 양면 스펙트럼
P1 = P2(1:NFFT/2); % 단일면 스펙트럼
P1(2:end-1) = P1(2:end-1).*sqrt(2);
% 주파수 벡터
f = Fs*(0:(NFFT/2)-1)/NFFT;
% 신호 파워 계산
signal_fbin = 1; % FBIN = ±20
signal_power = sum(P1((f >= fsig-signal_fbin) & (f <= fsig+signal_fbin)).^2);
% 노이즈 파워 계산을 위해 신호 영역을 0으로 설정
P1_no_signal = P1;
P1_no_signal((f >= fsig-(signal_fbin*Fs/NFFT )) & (f <= fsig+(signal_fbin*Fs/NFFT))) = 0;
% 노이즈 파워 계산
noise_power = sum(P1_no_signal.^2);
% SNR 계산
SNR = 10 * log10(signal_power / noise_power);
sig_rms_arr(1,i)=fsig;
sig_rms_arr(2,i)=sqrt(signal_power);
noise_rms_arr(1,i)=fsig;
noise_rms_arr(2,i)=sqrt(noise_power);
if i==1
% 결과 출력
fprintf('Signal Power: %.4e W\n', signal_power);
fprintf('Signal Rms: %.4e W\n', sqrt(signal_power));
fprintf('Noise Power: %.4e W\n', noise_power);
fprintf('Noise Rms: %.4e W / STDEV(time domain): %.4e W\n', sqrt(noise_power), noise_std);
fprintf('SNR: %.2f dB\n', SNR);
% 신호의 시간축 그래프
figure(1);
plot(t, combined_signal_win);
title('Time-Domain Signal');
xlabel('Time (s)');
ylabel('Amplitude (V)');
% FFT 그래프 (로그 스케일)
figure(2);
semilogx(f(2:(NFFT/2)), 20*log10(P1(2:(NFFT/2))),'o-');
title('Frequency-Domain Signal (Log Scale)');
xlabel('Frequency (Hz)');
ylabel('Amplitude (dB)');
xlim([0, Fs/2]);
% 그래프 표시
figure(gcf);
end
end
코드 간략 설명
0~2pi까지 적분한 뒤 2pi 로 나누면 평균 값이 된다.
100 * t/2 - 100/4 * sine(2t) + C
t에 0과 2pi를 넣고 빼준다. sine과 C는 사라진다.
100 * pi
적분 구간으로 나눠 평균값을 구한다.
100 * pi / (2 pi) = 50
power는 50이 되며, RMS는 7.07이 된다. 즉 rms는 amplitude / sqrt(2) 와 같다.
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기