From 1b951faae02d0ea595a6e1f37f4a180294576239 Mon Sep 17 00:00:00 2001 From: Marek Blok <Marek.Blok@pg.edu.pl> Date: Tue, 29 Jun 2021 13:06:58 +0200 Subject: [PATCH] Added Ex4 --- .gitignore | 11 + Ex4/.vscode/c_cpp_properties.json | 65 ++ Ex4/.vscode/launch.json | 29 + Ex4/.vscode/tasks.json | 33 + Ex4/Ex4_task2.cbp | 38 + Ex4/Ex4_task2.cpp | 128 +++ Ex4/Makefile | 85 ++ Ex4/Makefile.main | 60 ++ Ex4/matlab/FSDfilter.m | 142 +++ Ex4/matlab/SPECgraf.m | 1436 +++++++++++++++++++++++++++ Ex4/matlab/ex4_task1.m | 44 + Ex4/matlab/ex4_task1_test.m | 39 + Ex4/matlab/ex4_task2_h_FSD_all.coef | Bin 0 -> 280 bytes Ex4/matlab/getFSD_new.m | 468 +++++++++ Ex4/matlab/readaudiofile.m | 215 ++++ Ex4/matlab/save_filter_coef.m | 226 +++++ Ex4/matlab/test1_11025.wav | Bin 0 -> 22094 bytes Ex4/matlab/test2_11025.wav | Bin 0 -> 22094 bytes Ex4/matlab/test_signal.wav | Bin 0 -> 16044 bytes Ex4/rundot.bat | 4 + 20 files changed, 3023 insertions(+) create mode 100644 Ex4/.vscode/c_cpp_properties.json create mode 100644 Ex4/.vscode/launch.json create mode 100644 Ex4/.vscode/tasks.json create mode 100644 Ex4/Ex4_task2.cbp create mode 100644 Ex4/Ex4_task2.cpp create mode 100644 Ex4/Makefile create mode 100644 Ex4/Makefile.main create mode 100644 Ex4/matlab/FSDfilter.m create mode 100644 Ex4/matlab/SPECgraf.m create mode 100644 Ex4/matlab/ex4_task1.m create mode 100644 Ex4/matlab/ex4_task1_test.m create mode 100644 Ex4/matlab/ex4_task2_h_FSD_all.coef create mode 100644 Ex4/matlab/getFSD_new.m create mode 100644 Ex4/matlab/readaudiofile.m create mode 100644 Ex4/matlab/save_filter_coef.m create mode 100644 Ex4/matlab/test1_11025.wav create mode 100644 Ex4/matlab/test2_11025.wav create mode 100644 Ex4/matlab/test_signal.wav create mode 100644 Ex4/rundot.bat diff --git a/.gitignore b/.gitignore index 869ff7b..5187057 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,14 @@ Ex3/ex3_task3a.flt Ex3/ex3_task3b.flt Ex3/ex3_task3b.wav Ex3/log_file.txt + +Ex3-solution + +Ex4/out_win_dbg +Ex4/out_win_rls +Ex4/out_linux_dbg +Ex4/out_linux_rls + +Ex4/Ex4_task2_dbg.exe +Ex4/Ex4_task2.dot +Ex4/log_file.txt diff --git a/Ex4/.vscode/c_cpp_properties.json b/Ex4/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..11c576f --- /dev/null +++ b/Ex4/.vscode/c_cpp_properties.json @@ -0,0 +1,65 @@ +{ + "configurations": [ + { + "name": "Windows-Release", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../DSPE_lib_minGW/MinGW-W64_8.1.0/include/**" + ], + "defines": [ + "WIN32", + "__DEBUG__=0" + ], + //"compilerPath": "gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x64" + }, + { + "name": "Linux-Release", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../DSPE_lib_minGW/MinGW-W64_8.1.0/include/**" + ], + "defines": [ + "WIN32", + "__DEBUG__=0" + ], + "compilerPath": "gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x64" + }, + { + "name": "Windows-Debug", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../DSPE_lib_minGW/MinGW-W64_8.1.0/include/**" + ], + "defines": [ + "WIN32", + "__DEBUG__=1" + ], + //"compilerPath": "gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x64" + }, + { + "name": "Linux-Debug", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../DSPE_lib_minGW/MinGW-W64_8.1.0/include/**" + ], + "defines": [ + "WIN32", + "__DEBUG__=1" + ], + "compilerPath": "gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x64" + } +], + "version": 4 +} \ No newline at end of file diff --git a/Ex4/.vscode/launch.json b/Ex4/.vscode/launch.json new file mode 100644 index 0000000..1a11b37 --- /dev/null +++ b/Ex4/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Ex3 â widnows debug run ", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/Ex4_task2_dbg.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", +// "miDebuggerPath": "d:/CodeBlocks_20_03/MinGW/bin/gdb.exe", + "setupCommands": [ + { + "description": "WĹÄ cz formatowanie kodu dla gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "Build Ex4_task2.cpp" + } + ] +} \ No newline at end of file diff --git a/Ex4/.vscode/tasks.json b/Ex4/.vscode/tasks.json new file mode 100644 index 0000000..90f99ae --- /dev/null +++ b/Ex4/.vscode/tasks.json @@ -0,0 +1,33 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + // https://code.visualstudio.com/docs/editor/tasks + // ${command:cpptools.activeConfigName} + "tasks": [ + { + "label": "Build Ex4_task2.cpp", + "type": "shell", + "command": "make build -f Makefile.main FILE=Ex4_task2 VS_CFG=${command:cpptools.activeConfigName}", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "echo": true + }, + "problemMatcher": "$gcc" + }, + { + "label": "Clean Ex4_task2.cpp", + "type": "shell", + "command": "make clean -f Makefile.main VS_CFG=${command:cpptools.activeConfigName}", + "group": "build", + "presentation": { + "echo": true + }, + "problemMatcher": "$gcc" + } + + ] +} \ No newline at end of file diff --git a/Ex4/Ex4_task2.cbp b/Ex4/Ex4_task2.cbp new file mode 100644 index 0000000..2ee317b --- /dev/null +++ b/Ex4/Ex4_task2.cbp @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_project_file> + <FileVersion major="1" minor="6" /> + <Project> + <Option title="Ex4_task2" /> + <Option pch_mode="2" /> + <Option compiler="gcc" /> + <Build> + <Target title="default"> + <Option output="Ex4_task2" prefix_auto="1" extension_auto="1" /> + <Option type="1" /> + <Option compiler="gcc" /> + </Target> + </Build> + <Compiler> + <Add option="-std=c++0x" /> + <Add option="-m32" /> + <Add option="-g" /> + <Add option="-DWIN32" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/include" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/include/dbg" /> + </Compiler> + <Linker> + <Add option="-static-libgcc" /> + <Add option="-m32" /> + <Add library="DSPE" /> + <Add library="winmm" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/dbg" /> + </Linker> + <Unit filename="Ex4_task2.cpp" /> + <Extensions> + <code_completion /> + <envvars /> + <debugger /> + <lib_finder disable_auto="1" /> + </Extensions> + </Project> +</CodeBlocks_project_file> diff --git a/Ex4/Ex4_task2.cpp b/Ex4/Ex4_task2.cpp new file mode 100644 index 0000000..d47708a --- /dev/null +++ b/Ex4/Ex4_task2.cpp @@ -0,0 +1,128 @@ +/*! Laboratory: Advanced signal processing of digital telecommunications + * (Zaawansowane przetwarzanie sygnaĹĂłw telekomunikacji cyfrowej) + * Ex. 4. task 2. + * Sampling rate conversion with fractional delay filters + * + * \author Marek Blok + * \date 2021.06.29 + */ +#include <DSP_lib.h> + +int main(int argn, char *args[]) +{ + /*************************************************************/ + // Log file setup + DSP::log.SetLogFileName("log_file.txt"); + DSP::log.SetLogState(DSP::e::LogState::file | DSP::e::LogState::console); + + DSP::log << DSP::lib_version_string() << endl << endl; + /*************************************************************/ + +/* + Idea: + - set of filters is read from a file - L filters designed in MATLAB + - tests with bandlimited or fullband signals - chirps + spectrograph + + 1. Load table of impulse responses of FSD filters + + 2. Input -> output buffer with callback + + DSP::u::OutputBuffer (unsigned int BufferSize_in, unsigned int NoOfInputs_in, DSPe_buffer_type cyclic, DSP_clock_ptr ParentClock, DSP_clock_ptr NotificationsClock, unsigned int NoOfOutputs_in, DSP::u::buffer_callback_ptr func_ptr, unsigned int CallbackIdentifier=0) + If NoOfOutputs_in > 0 NotificationsClock has also the meaning of OutputClock. + + 3. Synchronous clocks >> although itmight be better if the asynchronous clocks were used + +*/ + + + DSP::LoadCoef coef_info; + long int Fp1, Fp2; + unsigned int L, M; + unsigned int N_all; + DSP::Float_vector h_all; + + if (coef_info.Open("ex4_task2_h_FSD_all.coef", "matlab") == false) + { + return -1; + } + Fp1 = coef_info.Fp; + + // verify L and calculate M + DSP::Float_vector tmp; + coef_info.Load(tmp, 1); + L = (unsigned int)tmp[0]; M = (unsigned int)tmp[1]; + Fp2 = (Fp1*L)/M; + + // ********************************** + N_all = coef_info.GetSize(0); + coef_info.Load(h_all, 0); + + /*************************************************************/ + + DSP::Clock_ptr InputClock; + InputClock=DSP::Clock::CreateMasterClock(); + + + DSP::u::FileInput InputSignal(InputClock, "matlab/test_signal.wav", 1U, DSP::e::SampleType::ST_short, DSP::e::FileType::FT_wav); + int Fp1_tmp = InputSignal.GetSamplingRate(); + if (Fp1_tmp != Fp1) + { + DSP::log << DSP::e::LogMode::Error + << "Sampling rate of the input signal is different from sampling rate from fitler coefficients file (ex4_task2_h_FSD_all.coef)" << endl; + } + + DSP::u::SamplingRateConversion FSDresampler(InputClock, L, M, h_all); + + DSP::u::AudioOutput SoundOut(Fp2, 1, 16); + DSP::u::FileOutput FileOut_a("ex4_task2.wav", DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_wav, Fp2); + DSP::u::FileOutput FileOut_b("ex4_task2.flt", DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_flt, Fp2); + + DSP::log << "Fp1 = " << Fp1 << ", Fp2 = " << Fp2 << ", L = " << L << ", M = " << M << endl; + + /*************************************************************/ + // Connections definitions + InputSignal.Output("out") >> FSDresampler.Input("in"); + FSDresampler.Output("out") >> SoundOut.Input("in"); + FSDresampler.Output("out") >> FileOut_a.Input("in"); + FSDresampler.Output("out") >> FileOut_b.Input("in"); + + + ///////////////////////////////// + // check if there are signals + // connected to all inputs + DSP::Component::CheckInputsOfAllComponents(); + + // *********************************** // + DSP::Clock::SchemeToDOTfile(InputClock, "Ex4_task2.dot"); + + // *********************************** // + int SamplesInSegment = 512; + __int64 NoOfSamplesProcessed = 0; + // 10 seconds + #define MAX_SAMPLES_TO_PROCESS 10*Fp1 + while(NoOfSamplesProcessed < MAX_SAMPLES_TO_PROCESS) + { + + // ********************************************************** // + DSP::Clock::Execute(InputClock, SamplesInSegment); + // ********************************************************** // + + if (InputSignal.GetBytesRead() > 0) + { + NoOfSamplesProcessed = 0; // Play the whole file + } + else // Play 200ms more + { + if (NoOfSamplesProcessed < MAX_SAMPLES_TO_PROCESS - Fp1/5) + NoOfSamplesProcessed = MAX_SAMPLES_TO_PROCESS - Fp1/5; + } + + NoOfSamplesProcessed += SamplesInSegment; + // ********************************************************** // + } + + /*************************************************************/ + DSP::Clock::FreeClocks(); + + return 0; +} diff --git a/Ex4/Makefile b/Ex4/Makefile new file mode 100644 index 0000000..c94c79f --- /dev/null +++ b/Ex4/Makefile @@ -0,0 +1,85 @@ +# Run: make Release +# Run: make Debug +CC=g++ +# comflag = -m32 +# comflag = -m64 +comflag = $(COMFLAG) + +DSPElib_DIR = ../../_DSPE_lib_minGW_/$(DSPElib_SUBDIR) + +SRC_DIR = . +SRC_CPP_SUBDIR = . + +#DFLAGS = -DWIN32 -DDEVCPP + +# -D INCLUDE_DSPE_EXAMPLES # TODO: uĹźycie w ramach kompilacji Main.cpp w trybie DEBUG +ifeq ($(MODE),Release) + CFLAGS = $(comflag) -std=c++0x -O3 -Wall -c -fmessage-length=0 -fno-strict-aliasing + LINKER_FLAGS = $(comflag) -s -static-libgcc -static-libstdc++ $(MISC_LINKER_FLAGS) + INCLUDES := -I"$(DSPElib_DIR)/include" -I"$(DSPElib_DIR)/include/rls" + DSPElib_FULLDIR = $(DSPElib_DIR)/rls + EXE_FILENAME = $(CPP_FILENAME)_rls.exe +else + CFLAGS = $(comflag) -std=c++0x -O0 -g3 -Wall -c -fmessage-length=0 -W -Wshadow -Wconversion -fstrict-aliasing -fmax-errors=5 + LINKER_FLAGS = $(comflag) -static-libgcc -static-libstdc++ $(MISC_LINKER_FLAGS) + INCLUDES := -I"$(DSPElib_DIR)/include" -I"$(DSPElib_DIR)/include/dbg" + DSPElib_FULLDIR = $(DSPElib_DIR)/dbg + EXE_FILENAME = $(CPP_FILENAME)_dbg.exe +endif +# -U__STRICT_ANSI__ jest potrzebne do kompilacji debug_new.cpp, jezeli pominac ten plik to mozna rowniez wyrzucic te opcje +#CFLAGS_debug = $(comflag) -std=c++0x -O0 -g3 -Wall -c -fmessage-length=0 -W -Wshadow -Wco#nversion -fstrict-aliasing -U__STRICT_ANSI__ + +SOURCES_NAMES = +SOURCES_NAMES += $(CPP_FILENAME).cpp +SOURCES = $(addprefix $(SRC_CPP_SUBDIR)/,$(SOURCES_NAMES)) + +SOURCES_DBG = +# SOURCES_DBG += $(SRC_DIR)/Main.cpp + +# ################################################# # +# DEBUG +OBJECTS := $(SOURCES:%.cpp=$(OUT_DIR)/%.o) +DEPENDS := $(SOURCES:%.cpp=$(OUT_DIR)/%.d) + +# ################################################# # +-include $(DEPENDS) + +all: build + + +# ########################################################################################### # +# ########################################################################################### # +build: $(SRC_DIR)/$(EXE_FILENAME) + +$(SRC_DIR)/$(EXE_FILENAME): $(OBJECTS) + @echo $(EXE_FILENAME) + $(CC) -L$(DSPElib_FULLDIR) $(OBJECTS) -o"$(SRC_DIR)/$(EXE_FILENAME)" $(LINKER_FLAGS) -lDSPE $(LIBS) + +# ########################################################################################### # +# ########################################################################################### # +# Z podanej listy usuwany $(OUT_DIR_WIN_RLS)/ oraz '.o' zamieniamy na '.cpp' +$(OBJECTS): $(OUT_DIR)/%.o : %.cpp + @echo $(@D) $< $@ + + #mkdir -p $(OUT_DIR)/$(SRC_CPP_SUBDIR) + mkdir -p $(@D) + $(CC) $(DFLAGS) $(CFLAGS) $(INCLUDES) -MMD $< -o $@ + + +clean: + @echo MODE: $(MODE) + + @if [ -d "$(OUT_DIR)" ]; then \ + echo "cleaning $(OUT_DIR_DBG) ..."; \ + #find $(OUT_DIR)/ -name "*.o" -type f -delete; \ + rm -rf $(OUT_DIR)/*.d; \ + rm -rf $(OUT_DIR)/*.o; \ + rm -rf $(OUT_DIR); \ + echo "cleaned $(OUT_DIR)"; \ + fi + rm -rf "$(SRC_DIR)/$(EXE_FILENAME)"; \ + #rm -rf "$(SRC_DIR)/*.gif"; \ + #rm -rf "$(SRC_DIR)/*.dot"; \ + +.PHONY: all build clean + diff --git a/Ex4/Makefile.main b/Ex4/Makefile.main new file mode 100644 index 0000000..cf6c368 --- /dev/null +++ b/Ex4/Makefile.main @@ -0,0 +1,60 @@ +# (View > Command Palette) => "Convert Indentation to Tabs" + +ifeq ($(VS_CFG),Windows-Debug) + MAKEFILE = "Makefile" + MODE = Debug + COMFLAG = -m64 + + OUT_DIR = ./out_win_dbg + DSPElib_SUBDIR = MinGW-W64_8.1.0 + MISC_LINKER_FLAGS = -static + LIBS = -lwinmm -lws2_32 + DFLAGS = -DWIN32 -DDEVCPP +endif +ifeq ($(VS_CFG),Windows-Release) + MAKEFILE = "Makefile" + MODE = Release + COMFLAG = -m64 + + OUT_DIR = ./out_win_rls + DSPElib_SUBDIR = MinGW-W64_8.1.0 + MISC_LINKER_FLAGS = -static + LIBS = -lwinmm -lws2_32 + DFLAGS = -DWIN32 -DDEVCPP +endif +ifeq ($(VS_CFG),Linux-Debug) + MAKEFILE = "Makefile" + MODE = Debug + COMFLAG = + + OUT_DIR = ./out_linux_dbg + DSPElib_SUBDIR = $(shell gcc -dumpmachine)-gcc_$(shell gcc -dumpversion) + MISC_LINKER_FLAGS = + LIBS := -lasound + DFLAGS = +endif +ifeq ($(VS_CFG),Linux-Release) + MAKEFILE = "Makefile" + MODE = Release + COMFLAG = + + OUT_DIR = ./out_linux_rls + DSPElib_SUBDIR = $(shell gcc -dumpmachine)-gcc_$(shell gcc -dumpversion) + MISC_LINKER_FLAGS = + LIBS := -lasound + DFLAGS = +endif + + + +build: + @echo "Building $(VS_CFG)" + @echo $(VS_CFG): $(MODE) // $(MAKEFILE) + make build CPP_FILENAME=$(FILE) MODE=$(MODE) COMFLAG=$(COMFLAG) DFLAGS="$(DFLAGS)" LIBS="$(LIBS)" OUT_DIR=$(OUT_DIR) DSPElib_SUBDIR=$(DSPElib_SUBDIR) MISC_LINKER_FLAGS="$(MISC_LINKER_FLAGS)" -f $(MAKEFILE) + +clean: + @echo "Cleaning $(VS_CFG)" + @echo $(VS_CFG): $(MODE) // $(MAKEFILE) + make clean MODE=$(MODE) OUT_DIR=$(OUT_DIR) -f $(MAKEFILE) + + diff --git a/Ex4/matlab/FSDfilter.m b/Ex4/matlab/FSDfilter.m new file mode 100644 index 0000000..7b941ff --- /dev/null +++ b/Ex4/matlab/FSDfilter.m @@ -0,0 +1,142 @@ +function [h, PE_FSD] = FSDfilter(method, N, delay, voff_typ) +% delay - total filter delay + +switch method + case 'LSE' + h=LSE(N,delay); + case 'LSE2' + h=LSE(N,delay,voff_typ); + case 'Lagr' + h=Lagr(N,delay); + case 'window' + h=window(N,delay,voff_typ); + case 'chebwin' + h=window(N,delay,3,voff_typ); + case 'offset' + h=offset(N,delay,voff_typ); + case 'optimal' + eval('h=getFSD(N,voff_typ,delay-(N-1)/2);','h=NaN;'); + + if isnan(h) + Krok=0; + Factor=4; + + while isnan(h) + Krok=Krok+1; + krok=Krok; voff=voff_typ; + while krok + voff=voff+(1/2-voff)/Factor; + krok=krok-1; + end; + eval('[h, PE_FSD, ekst]=getFSD(N,voff,delay-(N-1)/2);','h=NaN;'); + h=h.'; + end; + + while Krok>=0 + krok=Krok; voff=voff_typ; + while krok + voff=voff+(1/2-voff)/Factor; + krok=krok-1; + end; + ekst=ekst/ekst(end)*voff; + [h, PE_FSD, ekst]=getFSD(N,voff,delay-(N-1)/2, ekst); + h=h.'; + Krok=Krok-1; + end; + end; + + case 'optimal2' + % rasterless implementation + [h, PE_FSD] =getFSD_new(N,voff_typ,delay-(N-1)/2); +% eval('h=getFSD_new(N,voff_typ,delay-(N-1)/2);','h=NaN;'); + + if isnan(h) + Krok=0; + Factor=4; + + while isnan(h) + Krok=Krok+1; + krok=Krok; voff=voff_typ; + while krok + voff=voff+(1/2-voff)/Factor; + krok=krok-1; + end; + eval('[h, PE_FSD, ekst]=getFSD_new(N,voff,delay-(N-1)/2);','h=NaN;'); + h=h.'; + end; + + while Krok>=0 + krok=Krok; voff=voff_typ; + while krok + voff=voff+(1/2-voff)/Factor; + krok=krok-1; + end; + ekst=ekst/ekst(end)*voff; + [h, PE_FSD, ekst]=getFSD_new(N,voff,delay-(N-1)/2, ekst); + h=h.'; + Krok=Krok-1; + end; + end; +end; + +function h=Lagr(N,delay) + +for n=0:N-1 + m=0:N-1; + m(n+1)=[]; + h(n+1)=prod((delay-m)./(n-m)); +end; + +function h=LSE(N,delay, voff) + +n=0:N-1; +if nargin ==2, + h=sinc(n-delay); +elseif nargin==3 + alfa=2*voff; + for k=0:N-1 + l=0:N-1; + P(k+1,l+1)=alfa*sinc(alfa*(k-l)); + p(k+1,1)=alfa*sinc(alfa*(k-delay)); + end; + h=inv(P)*p; + h = h(:).'; +end; + +function h=window(N,delay,typ, Rp) +n=0:N-1; +hsinc=sinc(n-delay); + +if typ==3 + wsym=chebwin(N,Rp).'; +else + switch typ + case 2 + C=[0.43 -0.5 0.08]; %Blackman + case 1 + C=[0.54 -0.46 0]; %Hamming + case 0 + C=[0.5 -0.5 0]; %Hann + end; + wsym=C(1)+C(2)*cos(2*pi*n/(N-1))+C(3)*cos(4*pi*n/(N-1)); +end; + +h=hsinc.*wsym; + +function h=offset(N,delay,typ) +n=0:N-1; +hsinc=sinc(n-delay); +switch typ + case 2 + C=[0.43 -0.5 0.08]; %Blackman + case 1 + C=[0.54 -0.46 0]; %Hamming + case 0 + C=[0.5 -0.5 0]; %Hann +end; + +epsilon=delay-(N-1)/2; +%wsym=C(1)+C(2)*cos(2*pi*n/(N-1))+C(3)*cos(4*pi*n/(N-1)); +woffset=C(1)+C(2)*cos(2*pi*(n-epsilon)/(N-1))+C(3)*cos(4*pi*(n-epsilon)/(N-1)); +h=hsinc.*woffset; + diff --git a/Ex4/matlab/SPECgraf.m b/Ex4/matlab/SPECgraf.m new file mode 100644 index 0000000..d892ec7 --- /dev/null +++ b/Ex4/matlab/SPECgraf.m @@ -0,0 +1,1436 @@ +function varargout = SPECgraf(Akcja, param) +%cos(cumsum(n/1000)) + +% \fixed 2017.03.22 psd ==> pwelch +% \fixed 2012.03.05 finite ==> isfinite +% \fixed 2006.10.11 dealt with LineStyle/Marker warning +% \fixed 2005.11.20 dealt with "Warning: Log of zero." in ylim evaluation +% \fixed 2005.11.20 Placed all in single file +% \fixed 2005.11.20 Fixed problems with zoom out + +if nargin == 0 % LAUNCH GUI + +% fig = openfig(mfilename,'reuse'); return; %ZapiszFig(1,'specGUI.m') + if isempty(findobj(0, 'tag', 'Specgraf_DrawFig')) + + fig = Specgraf_DrawFig; + set(fig,'tag', 'Specgraf_DrawFig', 'Units', 'pixels'); + set(fig,'name', 'Spektrogram sygnałów niestacjonarnych (2017.03.22) dr inż. Marek Blok)',... + 'KeyPressFcn','1;'); + + SPECgraf('Init'); + SPECgraf('signal'); + set(fig,'Visible','on'); +% SPECgraf('per'); + else + SPECgraf('Exit'); + end + return; +end; + +if ~isstr(Akcja) % INVOKE NAMED SUBFUNCTION OR CALLBACK + disp('Something''s wrong'); + return; +end; + +% Generate a structure of handles to pass to callbacks, and store it. +fig=findobj(0, 'tag', 'Specgraf_DrawFig'); +hEditN=findobj(fig,'tag', 'N_edit'); +hEditM=findobj(fig,'tag', 'M_edit'); +hEditL=findobj(fig,'tag', 'L_edit'); +hEditK=findobj(fig,'tag', 'K_edit'); +hEditO=findobj(fig,'tag', 'O_edit'); +hEditW=findobj(fig,'tag', 'w_edit'); +hEditX=findobj(fig,'tag', 'x_edit'); +h_real=findobj(fig,'tag', 'real_checkbox'); +h_dB=findobj(fig,'tag', 'dB_checkbox'); +hEditNoise=findobj(fig,'tag', 'Noise_edit'); +hEditName=findobj(fig,'tag', 'Name_edit'); +hMenu=findobj(fig,'tag', 'choose_popupmenu'); +h_det=findobj(fig,'tag', 'detrend_checkbox'); +ha=get(fig, 'UserData'); +Ktory=get(hMenu,'Value'); +hEdit_dY=findobj(fig,'tag', 'dY_edit'); + +if strcmp(Akcja, 'Exit') + close(fig); + return; +elseif strcmp(Akcja, 'Init') + set(hEditX,'UserData','randn(1,L)'); + set(hEditX,'String','randn(1,L)'); + set(hEditX,'Max', 2); + + set(hEditW,'UserData','boxcar(M)'); + set(hEditW,'String','boxcar(M)'); + + set(hEditL,'UserData','1000'); + set(hEditL,'String','1000'); + set(hEditM,'UserData','100'); + set(hEditM,'String','100'); + set(hEditNoise,'UserData','-100'); + set(hEditNoise,'String','-100'); + +% set(hEditN,'UserData','1'); +% set(hEditN,'String','1'); + set(hEditO,'UserData','0'); + set(hEditO,'String','0'); + + set(hEditK,'UserData','256'); + set(hEditK,'String','256'); + + set(hEditName,'String','new'); + set(hMenu,'String','new'); + + set(h_real,'UserData',1); + set(h_real,'Value',1); + + set(h_dB,'UserData',0); + set(h_dB,'Value',0); + + set(h_det,'UserData',1); + set(h_det,'Value',1); + + ha(1)=findobj(fig,'tag', 'Signal_re_axes'); + ha(2)=findobj(fig,'tag', 'Signal_im_axes'); + ha(3)=findobj(fig,'tag', 'spec_axes'); + ha(4)=findobj(fig,'tag', 'per_axes'); +% for ind=[1 2 4], axes(ha(ind)); zoom on; end; +% axes(ha(3)); zoom off; + + set(fig, 'UserData', ha); + + set(hMenu,'UserData', [NaN, NaN, NaN, NaN, NaN, NaN, NaN, 1, -100, 5, -100, 5]); %handles & maximal values + set(hEdit_dY,'String','120'); + return; +elseif strcmp(Akcja, 'change_name') + pom=get(hMenu,'String'); + pom2=get(hEditName,'String'); + pom(Ktory,1:length(pom2)+1)=[pom2 0]; + set(hMenu,'String',pom); + set(hMenu, 'Value', Ktory); + return; +elseif strcmp(Akcja, 'new') + pom=get(hMenu,'String'); + Ktory=size(pom,1)+1; + pom(Ktory,1:4)=['new' 0]; + set(hMenu,'String',pom); + + + pom=get(hEditX,'UserData'); + pom(Ktory,1:11)=['randn(1,L)' 0]; + set(hEditX,'UserData',pom); + pom=get(hEditW,'UserData'); + pom(Ktory,1:10)=['boxcar(M)' 0]; + set(hEditW,'UserData',pom); + + pom=get(hEditL,'UserData'); + pom(Ktory,1:4)=['100' 0]; + set(hEditL,'UserData',pom); + pom=get(hEditM,'UserData'); + pom(Ktory,1:4)=['100' 0]; + set(hEditM,'UserData',pom); + pom=get(hEditNoise,'UserData'); + pom(Ktory,1:5)=['-100' 0]; + set(hEditNoise,'UserData',pom); + +% pom=get(hEditN,'UserData'); +% pom(Ktory,1:2)=['1' 0]; +% set(hEditN,'UserData',pom); + pom=get(hEditO,'UserData'); + pom(Ktory,1:2)=['0' 0]; + set(hEditO,'UserData',pom); + + pom=get(hEditK,'UserData'); + pom(Ktory,1:5)=['256' 0]; + set(hEditK,'UserData',pom); + + pom=get(hMenu,'UserData'); + pom(Ktory,1:size(pom,2))=ones(1,size(pom,2))*NaN; + set(hMenu,'UserData',pom); + + pom=get(h_real,'UserData'); + pom(Ktory,1)=1; + set(h_real,'Value', pom(Ktory,1)); + set(h_real,'UserData',pom); + + pom=get(h_det,'UserData'); + pom(Ktory,1)=1; + set(h_det,'Value', pom(Ktory,1)); + set(h_det,'UserData',pom); + + set(hMenu,'Value', Ktory); + + SPECgraf('Choose'); + SPECgraf('signal', Ktory); + return; +elseif strcmp(Akcja, 'delete') + pom=get(hMenu,'String'); + if size(pom,1)==1, + %SPECgraf('Reset'); + return; + end; + pom(Ktory,:)=[]; + set(hMenu,'String',pom); + + + pom=get(hEditX,'UserData'); + pom(Ktory,:)=[]; + set(hEditX,'UserData',pom); + pom=get(hEditW,'UserData'); + pom(Ktory,:)=[]; + set(hEditW,'UserData',pom); + + pom=get(hEditL,'UserData'); + pom(Ktory,:)=[]; + set(hEditL,'UserData',pom); + pom=get(hEditM,'UserData'); + pom(Ktory,:)=[]; + set(hEditM,'UserData',pom); + pom=get(hEditNoise,'UserData'); + pom(Ktory,:)=[]; + set(hEditNoise,'UserData',pom); + +% pom=get(hEditN,'UserData'); +% pom(Ktory,:)=[]; +% set(hEditN,'UserData',pom); + pom=get(hEditO,'UserData'); + pom(Ktory,:)=[]; + set(hEditO,'UserData',pom); + + pom=get(hEditK,'UserData'); + pom(Ktory,:)=[]; + set(hEditK,'UserData',pom); + + pom=get(hMenu,'UserData'); + for ind=1:3, + if isfinite(pom(Ktory,ind)) + delete(pom(Ktory,ind)); + end + end + pom(Ktory,:)=[]; + set(hMenu,'UserData',pom); + + pom=get(h_real,'UserData'); + pom(Ktory,:)=[]; + set(h_real,'UserData',pom); + + pom=get(h_det,'UserData'); + pom(Ktory,:)=[]; + set(h_det,'UserData',pom); + + set(hMenu,'Value', 1); + +% SPECgraf('signal', Ktory); + SPECgraf('Choose'); + return; + + +elseif strcmp(Akcja, 'Choose') + %selected new filter response + pom=get(hMenu,'String'); + ind=find(pom(Ktory,:)==0); + if isempty(ind) + ind=size(pom,2); + else + ind=ind(1)-1; + end + set(hEditName,'String',pom(Ktory,1:ind)); + + pom=get(hEditX,'UserData'); + set(hEditX, 'String', pom(Ktory,:)); + pom=get(hEditW,'UserData'); + set(hEditW, 'String', pom(Ktory,:)); + + pom=get(hEditL,'UserData'); + set(hEditL, 'String', pom(Ktory,:)); + pom=get(hEditM,'UserData'); + set(hEditM, 'String', pom(Ktory,:)); + pom=get(hEditNoise,'UserData'); + set(hEditNoise, 'String', pom(Ktory,:)); + +% pom=get(hEditN,'UserData'); +% set(hEditN, 'String', pom(Ktory,:)); + pom=get(hEditO,'UserData'); + set(hEditO, 'String', pom(Ktory,:)); + + pom=get(hEditK,'UserData'); + set(hEditK, 'String', pom(Ktory,:)); + + pom=get(h_real,'UserData'); + set(h_real,'Value', pom(Ktory,1)); + + pom=get(h_det,'UserData'); + set(h_det,'Value', pom(Ktory,1)); + +% SPECgraf('signal', Ktory); + return; + +elseif strcmp(Akcja, 'signal') + if nargin==2, + Ktory=param; + else + %save strings + tekst=[get(hEditL, 'String') 0]; + pom=get(hEditL,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditL,'UserData', setstr(pom)); + + tekst=[get(hEditNoise, 'String') 0]; + pom=get(hEditNoise,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditNoise,'UserData', setstr(pom)); + + tekst=get(hEditX, 'String').'; + tekst=[tekst(:); 0].'; + pom=get(hEditX,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditX,'UserData', setstr(pom)); + + tekst=get(h_real, 'Value'); + pom=get(h_real,'UserData'); + pom(Ktory,1)=tekst; + set(h_real,'UserData', pom); + end; + + pom=get(hMenu,'UserData'); + hp_re=pom(:,1); + hp_im=pom(:,2); + hp_spec_t=pom(:,3); + hp_spec_t2=pom(:,4); + hp_spec=pom(:,5); + hp_per=pom(:,6); + hp_per2=pom(:,7); + max_x=pom(:,8); + min_spec=pom(:,9); + max_spec=pom(:,10); + min_per=pom(:,11); + max_per=pom(:,12); + + %generate signal + tekstL=get(hEditL,'UserData'); tekstL=tekstL(Ktory,:); + ind=find(tekstL==0); + if ~isempty(ind) + tekstL=tekstL(1:ind(1)-1); + end; + eval(['L=' tekstL ';'], 'L=1;') + + n=0:L-1; + tekstX=get(hEditX,'UserData'); tekstX=tekstX(Ktory,:); + ind=find(tekstX==0); + if ~isempty(ind) + tekstX=tekstX(1:ind(1)-1); + end; + eval(['x=' tekstX ';'], 'x=zeros(1,L);') + + Re=get(h_real,'UserData'); Re=Re(Ktory,1); + + tekstNoise=get(hEditNoise,'UserData'); tekstNoise=tekstNoise(Ktory,:); + ind=find(tekstNoise==0); + if ~isempty(ind) + tekstNoise=tekstNoise(1:ind(1)-1); + end; + eval(['Noise=' tekstNoise ';'], 'Noise=-300;') + + x=x(:); + if length(x)<L; + x(L)=0; + else + x=x(1:L); + end; + + N_lin=10.^(Noise/20); + if Re==1 + x=real(x)+N_lin*randn(size(x)); + else + x=x+N_lin*(randn(size(x))+j*randn(size(x)))/sqrt(2); + end; + max_x(Ktory)=max(abs([real(x); imag(x)])); + + %draw signal + + %real part of the signal + axes(ha(1)); + if isnan(hp_re(Ktory)) + hold on; + hp_re(Ktory)=plot(n,real(x), 'Color', 'b'); + hold off; + else + set(hp_re(Ktory),'Xdata', n, 'Ydata', real(x)); + end +% set(ha(1), 'Xlim', [-0.5, L-0.5], 'Ylim', [-1.1 1.1]*max(max_x)); +% eval('zoom reset', 'set(get(ha(1),''ZLabel''),''UserData'',[]);'); +% reset(get(ha(1),'ZLabel')); + + %imaginary part of the signal +% axes(ha(2)); + if isnan(hp_im(Ktory)) + hold on; + hp_im(Ktory)=plot(n,imag(x), 'Color', 'r'); + hold off; + else + set(hp_im(Ktory),'Xdata', n, 'Ydata', imag(x)); + end + set(ha(1), 'Xlim', [-0.5, L-0.5], 'Ylim', [-1.1 1.1]*max(max_x)); +% set(get(ha(2),'ZLabel'),'UserData',[]); +% reset(get(ha(2),'ZLabel')); +% eval('zoom reset', 'set(get(ha(1),''ZLabel''),''UserData'',[]);'); + if L>512 + set([hp_re, hp_im], 'Marker', '.', 'MarkerSize', 4); + else + set([hp_re, hp_im], 'LineStyle', '-'); + end; + eval('rmappdata(get(ha(1),''Zlabel''),''ZOOMAxesData'')','set(get(ha(1),''ZLabel''),''UserData'',[])'); + + set(hMenu,'UserData', [hp_re, hp_im, hp_spec_t, hp_spec_t2, hp_spec, hp_per, hp_per2, max_x, min_spec, max_spec, min_per, max_per]); + + %compute and draw periodogram + SPECgraf('spec', Ktory) +% SPECgraf zoom_on; + return; + +elseif strcmp(Akcja, 'spec') + if nargin==2, + Ktory=param; + else + %save strings + tekst=[get(hEditK, 'String') 0]; + pom=get(hEditK,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditK,'UserData', setstr(pom)); + + tekst=[get(hEditM, 'String') 0]; + pom=get(hEditM,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditM,'UserData', setstr(pom)); + +% tekst=[get(hEditN, 'String') 0]; +% pom=get(hEditN,'UserData'); +% pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... +% zeros(1, max([1; size(pom,2); length(tekst)])); +% pom(Ktory,1:length(tekst))=tekst; +% set(hEditN,'UserData', setstr(pom)); + + tekst=[get(hEditO, 'String') 0]; + pom=get(hEditO,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditO,'UserData', setstr(pom)); + + tekst=[get(hEditW, 'String') 0]; + pom=get(hEditW,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditW,'UserData', setstr(pom)); + + tekst=get(h_det, 'Value'); + pom=get(h_det,'UserData'); + pom(Ktory,1)=tekst; + set(h_det,'UserData', pom); + end; + + pom=get(hMenu,'UserData'); + hp_re=pom(:,1); + hp_im=pom(:,2); + hp_spec_t=pom(:,3); + hp_spec_t2=pom(:,4); + hp_spec=pom(:,5); + hp_per=pom(:,6); + hp_per2=pom(:,7); + max_x=pom(:,8); + min_spec=pom(:,9); + max_spec=pom(:,10); + min_per=pom(:,11); + max_per=pom(:,12); + + %generate signal + tekstK=get(hEditK,'UserData'); tekstK=tekstK(Ktory,:); + ind=find(tekstK==0); + if ~isempty(ind) + tekstK=tekstK(1:ind(1)-1); + end; + eval(['K=' tekstK ';'], 'K=16;') + + tekstM=get(hEditM,'UserData'); tekstM=tekstM(Ktory,:); + ind=find(tekstM==0); + if ~isempty(ind) + tekstM=tekstM(1:ind(1)-1); + end; + eval(['M=' tekstM ';'], 'M=16;') + if M>K + M=K; + set(hEditM,'String', num2str(M)); + end; + +% tekstN=get(hEditN,'UserData'); tekstN=tekstN(Ktory,:); +% ind=find(tekstN==0); +% if ~isempty(ind) +% tekstN=tekstN(1:ind(1)-1); +% end; +% eval(['N=' tekstN ';'], 'N=16;') + + tekstO=get(hEditO,'UserData'); tekstO=tekstO(Ktory,:); + ind=find(tekstO==0); + if ~isempty(ind) + tekstO=tekstO(1:ind(1)-1); + end; +% eval(['O=' tekstO ';'], 'O=0;') + O=eval(tekstO, '0'); % \Fixed 2005.11.03 + O=round(O/100*M); % \Fixed 2005.11.03 nakładkowanie podawane w procentach !!! + + + tekstW=get(hEditW,'UserData'); tekstW=tekstW(Ktory,:); + ind=find(tekstW==0); + if ~isempty(ind) + tekstW=tekstW(1:ind(1)-1); + end; + eval(['w=' tekstW ';'], 'w=ones(1,M);') + + w=w(:); + if length(w)<M; + w(M)=0; + else + w=w(1:M); + end; + + x=get(hp_re(Ktory), 'Ydata')+j*get(hp_im(Ktory), 'Ydata'); + +% O=floor(O/100*M); % \Fixed 2005.11.03 + if O>=M + O=M-1; + set(hEditO,'String', num2str(O/M*100)); + end; + N = fix((length(x)-O)/(M-O)); + set(hEditN, 'String', sprintf('%i', N)); + +% det_=get(h_det,'UserData'); det_=det_(Ktory,1); +% if det_==0, +% det='none'; +% else +% det_='linear'; +% end; + + [Spec, f, t]=specgram(x, K, 1, w, O); + Spec=(abs(Spec).^2)/norm(w)^2; +% [Per, f2]=psd(x, K, 1, w, O); + [Per, f2]=pwelch(x, w, O, K, 1); + Spec=abs(Spec); + + Re=get(h_real,'UserData'); + if ~Re(Ktory,1) + f=fftshift(f); + f(1:floor(K/2))=f(1:floor(K/2))-1; + f2=fftshift(f2); + f2(1:floor(K/2))=f2(1:floor(K/2))-1; + Spec=[Spec(ceil(K/2):K,:); Spec(1:floor(K/2),:)]; + Per=fftshift(Per); + end + + min_spec(Ktory)=min([min(Spec(isfinite(Spec))); 0]); + max_spec(Ktory)=max([max(Spec(isfinite(Spec))); 0.001]); + min_per(Ktory)=min([min(Per(isfinite(Per))); 0]); + max_per(Ktory)=max([max(Per(isfinite(Per))); 0.001]); + if get(h_dB, 'UserData') %dB + Spec=10*log10(Spec); + Per=10*log10(Per); + end + set(get(ha(2),'Ylabel'),'UserData', f); + set(get(ha(3),'Ylabel'),'UserData', Spec); + set(get(ha(4),'Ylabel'),'UserData', Per); + + %draw signal + axes(ha(2)); + if length(t)>1 + t2=t+(t(2)-t(1))/2; + else + t2=M/2; + end; + + if isnan(hp_spec_t(Ktory)) + hold on; +% hp_spec_t(Ktory)=plot(t2,max(Spec), 'Color', 'k'); + pomoc=abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata')); + hp_spec_t(Ktory)=plot(get(hp_re(Ktory),'Xdata'), pomoc, 'Color', 'k'); + if length(pomoc)>512 + set(hp_spec_t(Ktory), 'Marker', '.', 'MarkerSize', 4); + else + set(hp_spec_t(Ktory), 'LineStyle', '-'); + end; + hold off; + else +% set(hp_spec_t(Ktory),'Xdata', t2, 'Ydata', max(Spec), 'Color', 'k'); + set(hp_spec_t(Ktory),'Xdata', get(hp_re(Ktory),'Xdata'),... + 'Ydata', abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata')), 'Color', 'k'); + end + if length(t)==1, + set(ha(2), 'Xlim', [t(1)-0.5 t(1)+0.5], 'Ylim', [-1.1 1.1]*max(max_x)); + else + set(ha(2), 'Xlim', [t(1) t(length(t))+(t(2)-t(1))], 'Ylim', [-1.1 1.1]*max(max_x)); + end; +% set(get(ha(2),'ZLabel'),'UserData',[]); +% reset(get(ha(2),'ZLabel')); + eval('rmappdata(get(ha(2),''Zlabel''),''ZOOMAxesData'')','set(get(ha(2),''ZLabel''),''UserData'',[])'); + + %spektrogram + axes(ha(3)); + if isnan(hp_spec(Ktory)) + hold on; + hp_spec(Ktory)=image(t2, f, Spec); + colormap(hot); + hold off; + else + set(hp_spec(Ktory),'Xdata', t2, 'Ydata', f, 'Cdata', Spec); + end + if length(t)==1, + tlim_=[t(1)-0.5 t(1)+0.5]; + else + tlim_=[t(1) t(length(t))+t(2)-t(1)]; + end; + if all(Re) + set(ha(3), 'Ylim', [0 0.5], 'Xlim', tlim_); + else + set(ha(3), 'Ylim', [-0.5 0.5], 'Xlim', tlim_); + end +% set(get(ha(3),'ZLabel'),'UserData',[]); +% reset(get(ha(3),'ZLabel')); + eval('zoom reset', 'set(get(ha(3),''ZLabel''),''UserData'',[]);'); + + axes(ha(4)); + if isnan(hp_per(Ktory)) + hold on; + hp_per(Ktory)=plot(Per, f2, 'Color', 'k'); + hold off; + else + set(hp_per(Ktory),'Ydata', f2, 'Xdata', Per, 'Color', 'k'); + end + set(ha(4), 'Xdir', 'reverse', 'YTick', []); %, 'Xlim', [t(1) t(length(t))], 'Ylim', [-1.1 1.1]*max(max_x)); + if all(Re) + set(ha(4), 'Ylim', [0 0.5]); + else + set(ha(4), 'Ylim', [-0.5 0.5]); + end + eval('rmappdata(get(ha(4),''Zlabel''),''ZOOMAxesData'')','set(get(ha(4),''ZLabel''),''UserData'',[])'); + + set(hMenu,'UserData', [hp_re, hp_im, hp_spec_t, hp_spec_t2, hp_spec, hp_per, hp_per2, max_x, min_spec, max_spec, min_per, max_per]); + + % delete + if 1 + pom=get(hMenu,'UserData'); + hp_=pom(:,[4,7]); + hp_=hp_(isfinite(hp_)); + if length(hp_)>0 + delete(hp_) + pom(:,4)=NaN; + pom(:,7)=NaN; + set(hMenu,'UserData',pom); + end; + end + + SPECgraf('spec_ylim'); + SPECgraf zoom_on; + SPECgraf zoom_off; + return; + +elseif strcmp(Akcja, 'dB') + pom=get(h_dB, 'UserData'); + if pom~=get(h_dB, 'Value') + pom=get(hMenu,'UserData'); + hp_spec=pom(:,3); + for ind=1:length(hp_spec) + sygn=get(get(ha(3),'Ylabel'),'UserData'); + per=get(get(ha(4),'Ylabel'),'UserData'); + if get(h_dB, 'Value') %dB + sygn=10*log10(sygn); + per=10*log10(per); + else %lin + sygn=10.^(sygn/10); + per=10.^(per/10); + end; + set(get(ha(3),'Ylabel'),'UserData', sygn); + set(get(ha(4),'Ylabel'),'UserData', per); +% set(hp_spec(ind),'Cdata', sygn); + end; + set(h_dB, 'UserData', get(h_dB, 'Value')); + + hp_=pom(:,[4 7]); + hp_=hp_(isfinite(hp_)); + if length(hp_)>0 + delete(hp_) + pom(:,4)=NaN; + pom(:,7)=NaN; + set(hMenu,'UserData',pom); + end; + SPECgraf('spec_ylim'); + end + return + +elseif strcmp(Akcja, 'spec_ylim') + pom=get(hMenu,'UserData'); + hp_re=pom(:,1); + hp_im=pom(:,2); + hp_spec_t=pom(:,3); + hp_spec=pom(:,5); + hp_per=pom(:,6); + min_spec=pom(:,9); + max_spec=pom(:,10); + min_per=pom(:,11); + max_per=pom(:,12); + if get(h_dB, 'UserData') %dB + tekst=get(hEdit_dY,'String'); + eval(['dY=' tekst ';'], 'dY=120;'); + if dY<=0, dY=10; end; + params_=[min(min_spec) max(max_spec)]; + ind_params = find(abs(params_) <= eps); + if length(ind_params) > 0, + params_(ind_params) = NaN*ones(size(ind_params)); + end + ylim_=10*log10(params_); + if ~isfinite(ylim_(2)) + ylim_(2)=0; + end + ylim_(1)=ylim_(2)-dY; + params_=[min(min_per) max(max_per)]; + ind_params = find(abs(params_) <= eps); + if length(ind_params) > 0, + params_(ind_params) = NaN*ones(size(ind_params)); + end + ylim_per=10*log10(params_); + if ~isfinite(ylim_per(2)) + ylim_per(2)=0; + end + ylim_per(1)=ylim_per(2)-dY; + else + ylim_=[0 max(max_spec)]; + ylim_per=[0 max(max_per)]; + end + ylim_per(2)=max([ylim_per(2) ylim_(2)]); + f=get(get(ha(2),'Ylabel'),'UserData'); + Spec=get(get(ha(3),'Ylabel'),'UserData'); + Per=get(get(ha(4),'Ylabel'),'UserData'); + set(hp_spec_t(Ktory),'Ydata', abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata'))); + set(ha(2),'Ylim', ylim_+(ylim_(2)-ylim_(1))*[-0.1 0.1]); + Spec=64*(Spec-ylim_(1))/(ylim_(2)-ylim_(1)); + + set(hp_spec(Ktory),'Cdata', Spec); + set(hp_per(Ktory),'Xdata', Per, 'Ydata', f); + set(ha(4),'Xlim', ylim_per); + + if get(h_dB, 'UserData') %dB + set(hp_spec_t(Ktory),'Ydata', 20*log10(abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata')))); + else + set(hp_spec_t(Ktory),'Ydata', abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata'))); + end + + SPECgraf zoom_on; + eval('zoom reset', 'set(get(ha(3),''ZLabel''),''UserData'',[]);'); + SPECgraf zoom_off; + return +elseif strcmp(Akcja, 'zoom_on') + zoom on; +% pom=get(fig, 'WindowButtonDownFcn'); +% set(fig, 'WindowButtonDownFcn', 'SPECgraf zoom'); +% set(get(ha(3),'Xlabel'), 'UserData', pom); + return; +elseif strcmp(Akcja, 'zoom_off') + if get(findobj(fig,'tag','checkbox_zoom'),'Value') == 0, +% pom = get(get(ha(3),'Xlabel'), 'UserData'); +% set(fig, 'WindowButtonDownFcn', pom); + zoom off; + set(fig, 'WindowButtonDownFcn', 'SPECgraf zoom'); + set(get(ha(3),'Xlabel'), 'UserData', '1;'); + end + return; +elseif strcmp(Akcja, 'zoom_spec') + if get(findobj(fig,'tag','checkbox_zoom'),'Value') ~= 0, + Specgraf zoom_on; + else + Specgraf zoom_off; + end +elseif strcmp(Akcja, 'zoom') +% if strcmp(get(fig,'SelectionType'),'normal') | (gca~=ha(3)) + pause(0); + if (get(gco,'Parent')~=ha(3)) | get(findobj(fig,'tag','checkbox_zoom'),'Value') + eval(get(get(ha(3),'Xlabel'), 'UserData')); + elseif get(gco,'Parent')==ha(3) + pom=get(ha(3), 'CurrentPoint'); + f_=pom(1,2); t_=pom(1,1); + + pom_=get(hMenu,'UserData'); + hp_spec_t2=pom_(:,4); + hp_spec=pom_(:,5); + hp_per2=pom_(:,7); + f=get(hp_spec(Ktory), 'Ydata'); + ind_f=find(abs(f-f_)==min(abs(f-f_))); ind_f=ind_f(1); + t=get(hp_spec(Ktory), 'Xdata'); +% if length(t)>1, +% t=t+(t(2)-t(1))/2; +% end; + ind_t=find(abs(t-t_)==min(abs(t-t_))); + ind_t=ind_t(1); + set(findobj(fig,'tag', 'text_t_f'),... + 'ForegroundColor', 'r', 'String', sprintf('n=%i, f=%6.3f', t(ind_t),f(ind_f))); + + Spec=get(get(ha(3),'Ylabel'),'UserData'); + axes(ha(4)); + if length(Spec(:,ind_t))>length(f) + ind=find(f==0); + Spec(ind(1),:)=[]; + end; + if isnan(hp_per2(Ktory)) + hold on; + hp_per2(Ktory)=plot(Spec(:,ind_t),f, 'Color', 'r', 'LineWidth', 2); + hold off; + else + set(hp_per2(Ktory),'Xdata', Spec(:,ind_t), 'Ydata', f); + end +% pom=get(ha(4), 'Xlim'); +% pom(2)=max([pom(2) max(Spec(:,ind_t))]); +% set(ha(4),'Xlim', pom); + + axes(ha(2)); + if isnan(hp_spec_t2(Ktory)) + hold on; + hp_spec_t2(Ktory)=plot(t,Spec(ind_f,:), 'Color', 'r', 'LineWidth', 2); + hold off; + SPECgraf zoom_on; + SPECgraf zoom_off; + else + set(hp_spec_t2(Ktory),'Xdata', t, 'Ydata', Spec(ind_f,:)); + end + + pom_(Ktory,7)=hp_per2; + pom_(Ktory,4)=hp_spec_t2; + set(hMenu,'UserData',pom_); + end; + return; +end; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function fig_h=Specgraf_DrawFig +fig_h=figure; +set(fig_h, ... + 'Units', 'Normalized',... + 'Position', [0.1125 0.1188 0.7813 0.7448],... + 'Color', [1.0000 1.0000 1.0000],... + 'Name', 'Untitled',... + 'NumberTitle', 'off',... + 'Menu', 'none',... + 'Tag', 'figure1'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.0330 0.0881 0.2150 0.4867],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'per_axes'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.2900 0.6350 0.6990 0.1538],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'Signal_im_axes'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.2880 0.0867 0.7030 0.4867],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'spec_axes'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.2920 0.8266 0.6980 0.1580],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'Signal_re_axes'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'frame',... + 'Units', 'Normalized',... + 'Position', [0.0050 0.7972 0.2400 0.1930],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'frame2'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'frame',... + 'Units', 'Normalized',... + 'Position', [0.0050 0.5916 0.2400 0.2028],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'frame4'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1190 0.6364 0.0280 0.0350],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', '[%]',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text23'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.8720 0.0126 0.0660 0.0196],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'zoom',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'Specgraf zoom_spec',... + 'Tag', 'checkbox_zoom'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.0140 0.0098 0.0660 0.0378],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Exit',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf Exit',... + 'Tag', 'pushbutton5'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.4640 0.0028 0.3540 0.0350],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text_t_f'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.1750 0.0126 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec_ylim'')',... + 'Tag', 'dY_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1110 0.0154 0.0620 0.0308],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'dY [dB] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text21'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.9270 0.5748 0.0500 0.0322],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'dB',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''dB'')',... + 'Tag', 'dB_checkbox'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.0660 0.4909 0.0600 0.0420],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Delete',... + 'Value', 0,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''delete'')',... + 'Tag', 'pushbutton4'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.0120 0.4909 0.0480 0.0420],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'New',... + 'Value', 0,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''new'')',... + 'Tag', 'pushbutton3'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1580 0.6769 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'N_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1280 0.6825 0.0300 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'N =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text18'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0390 0.8014 0.0720 0.0378],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''signal'')',... + 'Tag', 'L_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0090 0.8028 0.0290 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'L =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text17'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.1290 0.7301 0.1100 0.0252],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'detrend',... + 'Value', 0,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'detrend_checkbox'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0400 0.6378 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'O_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0110 0.6378 0.0280 0.0294],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'O =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text16'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0520 0.6000 0.1870 0.0336],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'w_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0130 0.5986 0.0400 0.0294],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'w[n] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text15'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.1670 0.8042 0.0720 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''signal'')',... + 'Tag', 'Noise_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1190 0.8042 0.0470 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Noise=',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text14'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0410 0.6769 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'M_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0110 0.6825 0.0300 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'M =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text13'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.1340 0.4909 0.1030 0.0392],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''change_name'')',... + 'Tag', 'Name_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'popupmenu',... + 'Units', 'Normalized',... + 'Position', [0.0120 0.5413 0.2260 0.0294],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Popup Menu',... + 'Value', 1,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''Choose'')',... + 'Tag', 'choose_popupmenu'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.1160 0.9580 0.1110 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'real signal',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''signal'')',... + 'Tag', 'real_checkbox'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0100 0.7622 0.1470 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Spectrograf parameters',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text10'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0400 0.7259 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'K_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0140 0.7329 0.0240 0.0252],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'K =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text9'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0390 0.8462 0.2010 0.1077],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''signal'')',... + 'Tag', 'x_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0130 0.9245 0.0240 0.0252],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'x =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text4'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0120 0.9636 0.1010 0.0238],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Testing signal',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text2'... + ); diff --git a/Ex4/matlab/ex4_task1.m b/Ex4/matlab/ex4_task1.m new file mode 100644 index 0000000..a38fbca --- /dev/null +++ b/Ex4/matlab/ex4_task1.m @@ -0,0 +1,44 @@ +function ex4_task1 + + +N_FSD = 13; +tau_N = (N_FSD-1)/2; + +Fp1 = 8000; Fp2 = 10000; + +M = Fp1 / gcd(Fp1,Fp2) +L = Fp2 / gcd(Fp1,Fp2) + +eps_all = -linspace(-0.5+0.5/L, 0.5-0.5/L, L); + +figure(1) +ha1 = subplot(2,1,1); +h_all = zeros(1, N_FSD*L); +n_all = 0:length(h_all)-1; n_all = n_all - (length(n_all)-1)/2; +for ind = 1:L, + epsilon = eps_all(ind); + h = FSDfilter('Lagr', N_FSD, tau_N+epsilon); +% h = FSDfilter('optimal2', N_FSD, tau_N+epsilon, 0.4); + h_all(ind:L:end) = h; + set(stem(ha1, n_all, h_all), 'Marker', 'none'); + pause(0.1) + drawnow +end + +K = 16*8192; +F = linspace(0, L*Fp1, K); + +H_all = abs(fft(h_all/L, K)); +figure(11) +subplot(2,1,1) +plot(h_all); +subplot(2,1,2) +plot(F, 20*log10(H_all)); +set(gca, 'Xlim', [0, L*Fp1/2], 'Ylim', [-100, 3]) + + +dane.h{1} = h_all; +dane.h{2} = [L, M]; +dane.Fp = Fp1; +save_filter_coef('ex4_task2_h_FSD_all', dane, 1); + diff --git a/Ex4/matlab/ex4_task1_test.m b/Ex4/matlab/ex4_task1_test.m new file mode 100644 index 0000000..ec655b8 --- /dev/null +++ b/Ex4/matlab/ex4_task1_test.m @@ -0,0 +1,39 @@ +function ex4_task1_test + + +N_FSD = 63; +tau_N = (N_FSD-1)/2; + +% Fp1 = 8000; Fp2 = 10000; +Fp1 = 16000; Fp2 = 11025; + +M = Fp1 / gcd(Fp1,Fp2) +L = Fp2 / gcd(Fp1,Fp2) + +eps_all = -linspace(-0.5+0.5/L, 0.5-0.5/L, L); + +h_all = zeros(1, N_FSD*L); +for ind = 1:L, + epsilon = eps_all(ind); + h = FSDfilter('optimal2', N_FSD, tau_N+epsilon, 0.45); +% h = FSDfilter('optimal2', N_FSD, tau_N+epsilon, 0.4); + h_all(ind:L:end) = h; +end + +K = 16*8192; +F = linspace(0, L*Fp1, K); + +H_all = abs(fft(h_all/L, K)); +figure(11) +subplot(2,1,1) +plot(h_all); +subplot(2,1,2) +plot(F, 20*log10(H_all)); +set(gca, 'Xlim', [0, L*Fp1/2], 'Ylim', [-100, 3]) + + +dane.h{1} = h_all; +dane.h{2} = [L, M]; +dane.Fp = Fp1; +save_filter_coef('ex4_task2_h_FSD_all', dane, 1); + diff --git a/Ex4/matlab/ex4_task2_h_FSD_all.coef b/Ex4/matlab/ex4_task2_h_FSD_all.coef new file mode 100644 index 0000000000000000000000000000000000000000..b12e93ef7292943bc38b57f86abbe339bd50a6ad GIT binary patch literal 280 zcmZQ{kY`|EWMpz=@ZgWJm~olYf&mCVh6wM_tFPX1ZnpET$og+PfkF+xTUf1@EJ(E~ z<6dh0<3gY{NZt2m>ATnNIJw*R@5Vj-HK}_*>Sil7+oT?RVRQ3puPx(YYg>>ypxoYL z2d?amZE@PCypeMsNZpoBKf6QkAK9In=w|=-Yk@sb2uy?cAaRg9NH0h|NFPW)$Q+Pf zkhvi9LH2;`1E~Yq4{`^{Js@|1)PdXyaxci;AoqjRf&2sV7s!7ge}dG3{0;Iy6OgmO I0Vv=A0R9Yf+W-In literal 0 HcmV?d00001 diff --git a/Ex4/matlab/getFSD_new.m b/Ex4/matlab/getFSD_new.m new file mode 100644 index 0000000..ab7d7fe --- /dev/null +++ b/Ex4/matlab/getFSD_new.m @@ -0,0 +1,468 @@ +% %poszukiwanie filtru optymalnego o dowolnej długoci +%w oparciu o układ równań rzeczywistych +% w oparciu o phase rotated real error +% +%implementacja w oparciu o poszukiwanie ekstremów +%pomiędzy dwoma kolejnymi punktami ekstremalnymi o tym samym znaku +% +% Wariant bezrastrowy w użyciem interpolacji parabolicznej +% +%getFSD_new(N,voff,d); +% N - długoć odpowiedzi impulsowej +% voff - częstotliwoć unormowana końca pasma dobrej aproksymacji +% d - opónienie netto + +% 2011.03.01 +function [h, TPEopt, ekst, A, B]=getFSD_new(N, voff, d, K, ekst, force_end); + +if nargin < 6, + force_end = 0; +end + +if nargin==0, + N=4; + voff=0.35; + d=0.25; + K=2048; %DFT length +elseif nargin==1, + voff=0.35; + d=0.25; + K=2048; %DFT length +elseif nargin==2 + d=0.25; + K=2048; %DFT length +elseif nargin==3 + K=2048; %DFT length +end; + +% df_factor = 10; df_factor_scaling = 1.05; +df_factor = 20; df_factor_scaling = 1.0; +df_factor = 4; + +% % K = K * 8 * 16; +% K_ = 8192*2*64; + +% N_LPF(ind)=ceil((-20*log10(sqrt(dp*ds))-13)/(14.6*(vs-vp))+1); +% N_FSD_est=ceil(-1/8*(PE/(4*(1/2-voff))+3)); +PE_est=-(N*8+3)*(4*(1/2-voff)); +if (PE_est < -140) + warning('Peek error estimation based on impulse response length shows that N is so large that it might result in fatal design errors'); +elseif (PE_est < -200) + warning('Peek error estimation based on impulse response length shows that N is so large that it probably will result in fatal design errors'); +elseif (PE_est < -275) + warning('Peek error estimation based on impulse response length shows that N is so large that it must result in fatal design errors'); + pause +end + + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% bez kwantyzacji osi częstotliwoci +M_in=round(voff*K)+1; % voff=(M_in-1)/K; + +L=(N-1)/2; % bulk delay +H_L = Hideal(L, voff, K); H_L=conj(H_L); +Hid = Hideal(L+d, voff, K); + +TPEopt=-300; +if nargin<5 +% if rem(N,2)==0 +% v=linspace(0,voff,N/2+1); +% else +% v=linspace(voff/N,voff,(N+1)/2); +% end; +% alfa=0.95; +% alfa=0.975; + alfa=0.999; + if (voff<=0.47) + alfa=0.99; + end +% alfa=0.996; +% alfa=0.999; + if rem(N,2)==0 +% '0' + x=[0:(N/2-1)]; + v=[0 cumsum(alfa.^x)]; + v=v/v(end)*voff; + else + x=[0:((N-1)/2)]; + v=cumsum(alfa.^x); + v(1)=v(1)/2; + v=v/v(end)*voff; + end; + ekst=(v*K); +% ekst=round(v*K); +end + +nn=1:N; A=zeros(N+1,N+1); B=zeros(N+1,1); +if (rem(N,2)==0) %parzyste + N_2=N/2; + A(1:N_2,N+1)=zeros(N_2,1); + A(((N_2+1):N),N+1)=((-1).^(1:N_2).'); + A(N+1,(1:(N+1)))=ones(1,N+1); + B(N+1)=1; +else + N_2=(N+1)/2; + A(1:N_2,N+1)=-((-1).^(1:N_2).'); + A(((N_2+1):(N+1)),N+1)=0; +end + +% ile = 0; +koniec = 1; +while 1, +% ile = ile + 1 + %construct equations + if (rem(N,2)==0) %parzyste + v=ekst(2:length(ekst))/K; %N-parzyste + for k=1:N_2, + A(k,nn)=sin(2*pi*(nn-1-L)*v(k)); + B(k)=sin(2*pi*v(k)*d); + A((N_2+k),nn)=cos(2*pi*(nn-1-L)*v(k)); + B((N_2+k))=cos(2*pi*v(k)*d); + end + else + v=ekst(1:length(ekst))/K; %N-nieparzyste + for k=1:N_2, + A(k,nn)=sin(2*pi*(nn-1-L)*v(k)); + B(k)=sin(2*pi*v(k)*d); + A((N_2+k),nn)=cos(2*pi*(nn-1-L)*v(k)); + B((N_2+k))=cos(2*pi*v(k)*d); + end + end + + if any(~isfinite(B)), + disp('B isn''t finite'); + error + end + if any(~isfinite(A)), + disp('A isn''t finite'); + error + end + x=A\B; % x=inv(A)*B; + h=x(1:N).'; + if any(~isfinite(h)), + disp('h isn''t finite'); + plot(20*log10(abs(Error))); + error + end + + if any(~isfinite(h)), + disp('Impulse response isn''t finite'); + error + end + + % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Error calculation + H = fft(h,K); + H = H(1:M_in); + H_L = H_L(1:M_in); + Hid = Hid(1:M_in); + + if (M_in-1)/K < voff, + n = 0:length(h)-1; + H_off = sum(h.*exp(-i*2*pi*voff*n)); + Hid_off = exp(-i*2*pi*voff*(L+d)); + H_L_off = exp(+i*2*pi*voff*L); + H = [H, H_off]; + Hid = [Hid, Hid_off]; + H_L = [H_L, H_L_off]; + end + + Error=H-Hid; + Error=Error.*H_L; + + n = 0:length(h)-1; + H_off = sum(h.*exp(i*2*pi*voff*(n-L).*n)); + Hid_off = exp(-i*2*pi*voff*d); + + % wyznaczenie współczynnika rotacji błędu + % => korygujemy błšd tak, żeby na częstotliwoci + Error_v_off = H_off - Hid_off; +% if abs(Error(M_in)) > 0, + if abs(Error_v_off) > 0, + Err_rot = conj(Error_v_off)/abs(Error_v_off); +% Err_rot = conj(Error(M_in))/abs(Error(M_in)); + Error=Error.*Err_rot; + else + Err_rot = 1; + end + if any(~isfinite(Error)), + disp('Normalized error isn''t finite'); + error + end + + if force_end == 1; + TPEopt = 20*log10(abs(x(N+1))); + TPEopt(2) = 20*log10(max(abs(Error))); + return; + end +% plot(20*log10(abs(Error))); + + % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % poszukiwanie położenia nowych ekstremów +% ekst=Ekstr(real(Error),ekst, N); +% ekst=Ekstr_new(h, ekst, Err_rot, d, N); + ekst_old = ekst; + ekst=Ekstr_new(h, ekst/K, d, N, K, df_factor)*K; + df_factor = round(df_factor * df_factor_scaling); + if df_factor > 200, + df_factor = 200; + end + + if any(~isfinite(ekst)), + disp('ekst isn''t finite'); + error + end + + % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % wyznaczenie peek error + %TPE=max(20*log10(abs(Error(ekst+1)))); + %TPE_H=max(20*log10(abs(Error))); + TPE=20*log10(abs(x(N+1))); + if TPEopt<TPE + TPEopt=TPE; + else +% ekst + ekst_old - ekst; + koniec = koniec - 1; + if koniec == 0, + break; + end + end +end + +return + + +%======================================================== +function Hid = Hideal(delay, F, K) +% delay - opónienie ułamkowe projektowanego filtru +% F - unormowana częstotliwoć górna pasma akuratnej aproksymacji +% K - liczba pršżków transformaty +% Hid - charakterystyka idealna (K-punktowa) + +v=(0:(K-1))/K; v(K/2:K)=v(K/2:K)-1; +Hid = ones(1,K).*exp(-i*2*pi*v*delay); + +%======================================================== +function x=Ekstr(Err, old, N) +% jeżeli filtr parzystej długoci to zakładamy, że punkty ekstremalne w 0 i M_in (end) +% nie ulegajš zmianie +% jeżeli filtr o nieparzystej długoci to w zerze napewno nie ma punktu ekstremalnego +% oraz punkt ekstremalny w M_in (end) nie ulega zmianie + +delta=max(abs(Err(old+1))); + +%wyjciowy zestaw punktów ekstremalnych +temp=old+1; %parzyste +if rem(N,2)==1 + temp=[1 temp]; %nieparzyste +end + +min_max=0; +for ind=length(temp):-1:3 + pom=Err(temp(ind-2):temp(ind)); + if min_max==0 + [wart, ind_new]=find(pom==min(pom)); + else + [wart, ind_new]=find(pom==max(pom)); + end + if abs(wart)>delta + temp(ind-1)=temp(ind-2)+ind_new-1; + end + min_max=1-min_max; +end + +x=temp-1; +if rem(N,2)==1 + x=x(2:length(x)); +end + +function f_new = Ekstr_new(h, f_old, d, N, K, df_factor); +% jeżeli filtr parzystej długoci to zakładamy, że punkty ekstremalne w 0 i M_in (end) +% nie ulegajš zmianie +% jeżeli filtr o nieparzystej długoci to w zerze napewno nie ma punktu ekstremalnego +% oraz punkt ekstremalny w M_in (end) nie ulega zmianie +L = (N-1)/2; +n = 0:N-1; n=n(:); + +f_old_ = f_old; +foff = f_old(end); +H_off = sum(h(:).*exp(-i*2*pi*foff*(n-L))); +Hid_off = exp(-i*2*pi*foff*d); +Error_f_off = H_off - Hid_off; +if abs(Error_f_off) > 0, + Err_rot = conj(Error_f_off)/abs(Error_f_off); +else + Err_rot = 1; +end + +for ind = 1:length(f_old), + H_off(ind) = sum(h(:).*exp(j*2*pi*f_old(ind)*(n-L).*n)); +end +Hid_old = exp(-i*2*pi*f_old*d); + +Err_old = real((H_off - Hid_old)*Err_rot); + +% delta=max(abs(Err(old+1))); +delta=max(abs(Err_old)); + + +do_draw = 0; +if do_draw == 1, + % % f = linspace(0,0.5, 2048); + f = linspace(0,0.5, K); % 2011.02.28 + + E_ = 0; + H_ = 0; + for n_ = n.', + E_ = E_ + Err_rot*(-j)*2*pi* h(n_+1).*(n_-(L+d)).*exp(-j*2*pi*f*(n_-(L+d))); + H_ = H_ + Err_rot*h(n_+1).*exp(-j*2*pi*f*(n_-L)); + end + + H_id = Err_rot*exp(-j*2*pi*f*d); + + figure(5) + subplot(3,1,1) + plot(f, real(E_)); + hold on + plot(f, imag(E_), 'r'); + hold off + set(gca, 'Xtick', f_old_, 'Xgrid', 'on'); + subplot(3,1,2) + plot(f, abs(H_-H_id), 'k'); + hold on + plot(f, real(H_-H_id), 'b'); + plot(f, imag(H_-H_id), 'r'); + hold off + + subplot(3,1,3) + plot(f, 20*log10(abs(H_-H_id)), 'k'); +end + +if rem(N, 2) == 1, + f_old = [0, f_old]; % 0 must always be included +end +% find extremas +% leave point at v_off (maximum) +f_new = f_old(end); + +polarization = -1; +while length(f_old) > 2, + % find extremum between f_start and f_end + f_end = f_old(end); + f_start = f_old(end-2); + + fo = f_old(end-1); % old value + + df = min([(f_end-fo), (fo-f_start)]) / df_factor; + + fo_new = find_extremum(h, d, Err_rot, [fo-df, fo, fo+df], polarization, do_draw); + + f_new = [fo_new, f_new]; + f_old(end) = []; + + polarization = -polarization; +end +if rem(N, 2) == 0, + f_new = [f_old(1), f_new]; % include 0 +end + +% size(f_old_) +% size(f_new) + +if do_draw == 1, + subplot(3,1,2) + set(gca, 'Xtick', f_new, 'Xgrid', 'on'); + subplot(3,1,3) + set(gca, 'Xtick', f_new, 'Xgrid', 'on'); + + % f_new + % + pause +end + +function fo_new = find_extremum(h, d, Err_rot, fs, polarization, do_draw) + +N = length(h); +n = 0:N-1; n = n(:); +L = (N-1)/2; + +f = fs; +% f = [fs(1), (fs(1)+fs(2))/2, fs(2), (fs(2)+fs(3))/2, fs(3)]; +% f = linspace(fs(1), fs(3), 11); + +% E_ = 0; +H_ = 0; +for n_ = n.', +% E_ = E_ + Err_rot*(-j)*2*pi* h(n_+1).*(n_-(L+d)).*exp(-j*2*pi*f*(n_-(L+d))); + H_ = H_ + Err_rot*h(n_+1).*exp(-j*2*pi*f*(n_-L)); +end +H_id = Err_rot*exp(-j*2*pi*f*d); + +E_ = real(H_-H_id) * polarization; + +%f(x) = a*x^2+b*x+c +%delta = b^2 - 4*a*c +%f_ekstremum = -b/(2*a) + +% % y = polyval(a, x) +% y1 = a*x1^2 + b*x1 + c +% y2 = a*x2^2 + b*x2 + c +% y3 = a*x3^2 + b*x3 + c + +a = polyfit(f, E_, 2); + +fo_new = -a(2)/(2*a(1)); + +% +% if (fo_new < fs(1)) +% fo_new = fs(1); +% end +% if (fo_new > fs(3)) +% fo_new = fs(3); +% end + +if (fo_new < fs(1)) || (fo_new > fs(3)) + ind = find(max(E_) == E_); + fo_new = f(ind(1)); +else + H_new = 0; + for n_ = n.', + H_new = H_new + Err_rot*h(n_+1).*exp(-j*2*pi*fo_new*(n_-L)); + end + H_id_new = Err_rot*exp(-j*2*pi*fo_new*d); + E_new = real(H_new-H_id_new) * polarization; + + E_ = [E_, E_new]; + f = [f, fo_new]; + + ind = find(max(E_) == E_); + if (fo_new ~= f(ind(1))), + fo_new = f(ind(1)); + end + +end + +% % if fo_new < fs(1) +% % fo_new = fs(1); +% % end +% % if fo_new > fs(3) +% % fo_new = fs(3); +% % end +% % % fo_new +% % % fo_new; + +% do_draw = 1; +if do_draw == 1, + f_ = linspace(fs(1), fs(3), 51); + y = polarization * polyval(a, f_); + subplot(3,1,2) + hold on + plot(f_, y, 'm'); + hold off + max_y = max(abs(y)); + if max_y == 0, max_y = 1, end; + set(gca, 'Ylim', [-1.15, 1.15]*max_y); + % % pause + % +end diff --git a/Ex4/matlab/readaudiofile.m b/Ex4/matlab/readaudiofile.m new file mode 100644 index 0000000..825a9a8 --- /dev/null +++ b/Ex4/matlab/readaudiofile.m @@ -0,0 +1,215 @@ +function [x, Fs] = readaudiofile(filename, param) +% [x, Fs] = readaudiofile(filename, param) +% +% returns vector x of the size SIZE=[samples channels]. +% eg. x = x(:,1) + j*x(:,2); +% +% special uses: +% param == 'size': returns SIZE in x +% param == 'cplx': for stereo files returns x as a complex vector instead of matrix +% +% supported file types: +% *.flt +% *.wav +% *.tape +% last modification: 2021.03.29 +% Author: Marek Blok + +return_cplx = 0; +if nargin == 1, + param = inf; +else + if strcmp(param, 'cplx') == 1, + return_cplx = 1; + param = inf; + end +end + +ind = find(filename == '.'); +if length(ind) == 0, + file_type = 'w'; % *.wav +else + ind = ind(end); + + temp = filename(ind+1:end); + + file_type = 'u'; % unknown format + if strcmp(temp, 'flt') == 1, + file_type = 'f'; % two channel floting point + elseif strcmp(temp, 'wav') == 1, + file_type = 'w'; % *.wav + elseif strcmp(temp, 'tape') == 1, + file_type = 't'; % *.tape + end +end + +switch file_type, + case 'w', + if strcmp(param, 'size') == 1, + if exist('audioread','file') == 0 + x = wavread(filename, 'size'); + % siz = [samples channels]. + else + info = audioinfo(filename); + x = [info.TotalSamples, info.NumChannels]; + Fs = info.SampleRate; + end + else + if isfinite(param) + if exist('audioread','file') == 0 + [x, Fs] = wavread(filename, param); + else + if length(param) == 1 + param = [1, param]; + end + [x, Fs] = audioread(filename, param); + end + else + if exist('audioread','file') == 0 + [x, Fs] = wavread(filename); + else + [x, Fs] = audioread(filename); + end + end + end + + case 't' + plik = fopen(filename, 'rb'); + if plik == -1, + error('File does not exist !!!'); + end + + header.size = fread(plik, 1, 'uint32', 0) + 4; + + header.fname = char(fread(plik, 256, 'char', 0).'); + header.cfg_fname = char(fread(plik, 256, 'char', 0).'); + header.sw_rev = fread(plik, 1, 'uint32', 0); + header.hw_rev = fread(plik, 1, 'uint32', 0); + header.file_ = fread(plik, 1, 'uint32', 0); + header.tape_type = fread(plik, 1, 'uint32', 0); + header.start_time = fread(plik, 1, 'int32', 0); % time_t + header.end_time = fread(plik, 1, 'int32', 0); % time_t + + header.total_samples = fread(plik, 1, 'uint32', 0); + file_length = header.total_samples * 4 + header.size + header.current_sample = fread(plik, 1, 'uint32', 0); + header.loop_start = fread(plik, 1, 'int64', 0); + header.loop_end = fread(plik, 1, 'int64', 0); + header.loop = fread(plik, 1, 'int32', 0); + header.group_size_32 = fread(plik, 1, 'uint32', 0); + header.block_size = fread(plik, 1, 'uint32', 0); + header.block_count = fread(plik, 1, 'uint32', 0); + header.fifo_size = fread(plik, 1, 'uint32', 0); + + + header.comment = char(fread(plik, 256, 'char', 0).'); + header.tmp = char(fread(plik, 20, 'char', 0).'); % time_t + header.status = fread(plik, 1, 'uint32', 0); + header.timestamps = fread(plik, 1, 'int32', 0); + header.freq = fread(plik, 1, 'float', 0); + header.cplx_datarate = fread(plik, 1, 'float', 0); + +% ftell(plik) + header.reserved = fread(plik, 128, 'uint32', 0); +% header.reserved.' + + header + ftell(plik) + + header.sample_type = 2; + header.ch_no = 2; + header.Fs = NaN; + + sample_type = 'int16'; + sample_size = 2; + + header_size = header.size; + if strcmp(param, 'size') == 1, + fseek(plik, 0, 'eof'); + size = (ftell(plik) - header_size) / sample_size / header.ch_no; % sizeof(float) *2 + x = size; + else + fseek(plik, header_size, 'bof'); + + len = param(1); + if length(param) > 1, + fseek(plik, sample_size*header.ch_no*(param(1)-1), 'cof'); + len = param(2) - param(1) + 1; + end + +% x = fread(plik, [header.ch_no, len], sample_type); + x = fread(plik, [header.ch_no, len], sample_type, 0); + x = x.'; + end + fclose(plik); + + case 'f' + plik = fopen(filename, 'rb'); + if plik == -1, + error('File does not exist !!!'); + end + + % 3 B - wersja pliku (w tym typ próbek) + % 1 B - liczba kanałów + % 4 B - szybkoć próbkowania + header_size = 8; + header.ver = fread(plik, 1, 'uint8'); + header.sample_type = fread(plik, 1, 'uint16'); + header.ch_no = fread(plik, 1, 'uint8'); + header.Fs = fread(plik, 1, 'uint32'); + + Fs = header.Fs; + + switch (header.ver), + case 0, + switch (header.sample_type), + case 0, + sample_type = 'float'; + sample_size = 4; + case 1, + sample_type = 'uchar'; + sample_size = 1; + case 2, + sample_type = 'short'; + sample_size = 2; + case 3, + sample_type = 'int'; + sample_size = 4; + otherwise + error('Unsupported *.flt sample type !!!'); + end + otherwise + error('Unsupported *.flt file version !!!'); + end + + + if strcmp(param, 'size') == 1, + fseek(plik, 0, 'eof'); + size = (ftell(plik) - header_size) / sample_size / header.ch_no; % sizeof(float) *2 + x = size; + else + len = param(1); + status = 0; + if length(param) > 1, + status = fseek(plik, sample_size*header.ch_no*(param(1)-1), 'cof'); + len = param(2) - param(1) + 1; + end + + if (status == -1) + x = []; + else + x = fread(plik, [header.ch_no, len], sample_type); + x = x.'; + end + end + + fclose(plik); + otherwise + error('Unsupported file format !!!'); +end + +if return_cplx == 1, + if length(x(1,:)) == 2, + x = x(:,1) + j*x(:,2); + end +end \ No newline at end of file diff --git a/Ex4/matlab/save_filter_coef.m b/Ex4/matlab/save_filter_coef.m new file mode 100644 index 0000000..8cf1f07 --- /dev/null +++ b/Ex4/matlab/save_filter_coef.m @@ -0,0 +1,226 @@ +function save_filter_coef(filename, coefficients, file_version) +% save_filter_coef(filename, coefficients [, file_version]) +% +% FIR filter coefficients +% coefficients.h +% - can be cell vector to store multiple FIR impulse responces +% - if any of the impulse responses is complex then all responses will +% be stored as complex +% IIR filter coefficients +% coefficients.a +% coefficients.b +% +% For file_version >= 1 (default == 0), +% coefficients.Fp - sampling frequency +% +% This file is a part of Digital Signal Processing Engine +% +% File format (*.coef) - this is open format, for general use +% * (not only for storing coefficients) +% +% File format (*.h) - this is C++ header file for DSPElib with hardcoded *.coef equivalent +% +% \author Marek Blok +% \date 2020.02.22 + +if nargin == 2, + file_version = 0; +end + +ind = find(filename == '.'); +if length(ind) == 0, + filename = [filename, '.coef']; +end + +% detect mode based on file extention +[PATHSTR,NAME,EXT] = fileparts(filename); +switch EXT + case '.h' + mode = 'h-file'; + plik = fopen(filename, 'wt'); + + case '.coef' + mode = 'coefs-file'; + plik = fopen(filename, 'wb'); + + otherwise + mode = 'unknown-file'; + error(mode); +end + +switch mode + case 'h-file' + fprintf(plik, '// save_filter_coef output (hard coded coefficients)\n'); + fprintf(plik, '#pragma once\n'); + fprintf(plik, '#include <DSP_lib.h>\n'); + fprintf(plik, '\n'); + + if isfield(coefficients, 'h'), + h = coefficients.h; + + for ind_h = 0:length(h)-1 + fprintf(plik, 'DSP_float_vector Farrow_coefs_row_%i = {', ind_h); + h_tmp = h{ind_h+1}; + for ind_p = 0:length(h_tmp)-1, + if ind_p > 0 + fprintf(plik, ', '); + end + fprintf(plik, '%.15ff', h_tmp(ind_p+1)); + end + %0.1f, 0.2f, 0.1f + fprintf(plik, '};\n'); + end + fprintf(plik, '\n'); + + %vector <DSP_float_vector> Farrow_coefs = { coefs_0, coefs_1, coefs_2 }; + fprintf(plik, 'vector <DSP_float_vector> Farrow_coefs = {'); + for ind_h = 0:length(h)-1 + if ind_h > 0 + fprintf(plik, ', '); + end + if (ind_h < length(h_tmp)) & (rem(ind_h, 5) == 0) + fprintf(plik, '\n '); + end + fprintf(plik, 'Farrow_coefs_row_%i', ind_h); + end + fprintf(plik, '\n };\n'); + + fprintf(plik, '\n'); + fprintf(plik, 'const unsigned int p_Farrow = %i; // should be equal to Farrow_coefs[0].size()-1\n', length(h{1})-1); + fprintf(plik, 'const unsigned int N_FSD = %i; // should be equal to Farrow_coefs.size()\n', length(h)); + end + + if isfield(coefficients, 'b'), + fclose all; + error('unsupported: coefficients.b'); + end + if isfield(coefficients, 'a'), + fclose all; + error('unsupported: coefficients.a'); + end + + case 'coefs-file' + % * - (uchar) 1B - file version number + fwrite(plik, file_version, 'uchar'); + + switch file_version, + case 0, + case 1, + % * - (uint) 4B - Sampling frequency + if isfield(coefficients, 'Fp'), + fwrite(plik, coefficients.Fp, 'uint32'); + else + fclose(plik); + error('Input data does not contain Fp'); + end + otherwise, + fclose(plik); + error('This version of coefficients file is unsupported'); + end + + if isfield(coefficients, 'h'), + isFIR = 1; + if iscell(coefficients.h) + resp_no = length(coefficients.h); + % if resp_no = 1; + % coefficients.h = coefficients.h{1}; + % end + else + resp_no = 1; + end + if resp_no == 1, + isComplex = any(imag(coefficients.h(:))); + else + isComplex = false; + for ind_resp = 1:resp_no, + isComplex = isComplex | any(imag(coefficients.h{ind_resp}(:))); + end + end + else + isFIR = 0; + isComplex = any(imag(coefficients.a(:))) | any(imag(coefficients.b(:))); + end + + % * - data - coefficients data (depends on fle version) + % * . + % * Data segment format: + % * -# (version: 0x00) + % * - (uchar) 1B - number of sample dimensions + % * 1 - real, 2 - complex, ... + if isComplex, + fwrite(plik, 2, 'uchar'); % complex + else + fwrite(plik, 1, 'uchar'); % real + end + % * - (uchar) 1B - sample component type + % * - DSP_FT_float (=1) : C++ float (32bit floating point) + % * - DSP_FT_short (=2) : C++ short (16bit signed integer) + % * - DSP_FT_uchar (=3) : C++ unsigned char (8bit unsigned integer with bias (0x80)) + % * - DSP_FT_double (=7) : C++ double (64bit floating point) + % * - DSP_FT_long_double (=8) : C++ long double (80bit floating point) + fwrite(plik, 1, 'uchar'); + + % * - (uchar) 1B - number of vectors + % * - 1 - FIR filter coefficients (one vector) + % * - 2 - IIR filter coefficients (two vectors) + % * - (x number of vectors) + % * - (ushort) 2B - number of samples in vector + % * - (x number of samples) + % * - (x number of sample dimensions) + % * - (sample componet type) xB - sample component + % * e.g. real, imag part + if isFIR, + fwrite(plik, resp_no, 'uchar'); + + if iscell(coefficients.h) + for ind_resp = 1:resp_no, + N_FIR = length(coefficients.h{ind_resp}); + fwrite(plik, N_FIR, 'uint16'); + if isComplex, + dane(1:2:2*N_FIR) = real(coefficients.h{ind_resp}); + dane(2:2:2*N_FIR) = imag(coefficients.h{ind_resp}); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.h{ind_resp}), 'float'); + end + end + else + N_FIR = length(coefficients.h); + fwrite(plik, N_FIR, 'uint16'); + if isComplex, + dane(1:2:2*N_FIR) = real(coefficients.h); + dane(2:2:2*N_FIR) = imag(coefficients.h); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.h), 'float'); + end + end + + else + fwrite(plik, 2, 'uchar'); + + N_a = length(coefficients.a); + fwrite(plik, N_a, 'uint16'); + if isComplex, + dane(1:2:2*N_a) = real(coefficients.a); + dane(2:2:2*N_a) = imag(coefficients.a); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.a), 'float'); + end + + + N_b = length(coefficients.b); + fwrite(plik, N_b, 'uint16'); + if isComplex, + dane(1:2:2*N_b) = real(coefficients.b); + dane(2:2:2*N_b) = imag(coefficients.b); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.b), 'float'); + end + end + +end +fclose(plik); + diff --git a/Ex4/matlab/test1_11025.wav b/Ex4/matlab/test1_11025.wav new file mode 100644 index 0000000000000000000000000000000000000000..a47f814892bd68c7eb58e32d6c1502b956d20c9f GIT binary patch literal 22094 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 YD$i9(O!0U=1Xq*Co^L63<w0=&2R&51VE_OC literal 0 HcmV?d00001 diff --git a/Ex4/matlab/test2_11025.wav b/Ex4/matlab/test2_11025.wav new file mode 100644 index 0000000000000000000000000000000000000000..04b882f23c78f86cdc6f6939b1d3ab256f70bbc5 GIT binary patch literal 22094 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%0DI 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 UJjn<CJpBg>JUa(m<5-^m1H$3D?*IS* literal 0 HcmV?d00001 diff --git a/Ex4/matlab/test_signal.wav b/Ex4/matlab/test_signal.wav new file mode 100644 index 0000000000000000000000000000000000000000..51a5040ccd128813e34dbea06c96952f494151c2 GIT binary patch literal 16044 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 literal 0 HcmV?d00001 diff --git a/Ex4/rundot.bat b/Ex4/rundot.bat new file mode 100644 index 0000000..30e8d91 --- /dev/null +++ b/Ex4/rundot.bat @@ -0,0 +1,4 @@ +path = "D:\Program Files (x86)\Graphviz\bin";%path% + +del Ex4_task2.gif +dot -Tgif Ex4_task2.dot -oEx4_task2.gif -- GitLab