annotate aim-mat/tools/@signal/genharmonics.m @ 4:537f939baef0 tip

various bug fixes and changed copyright message
author Stefan Bleeck <bleeck@gmail.com>
date Tue, 16 Aug 2011 14:37:17 +0100
parents 20ada0af3d7d
children
rev   line source
bleeck@3 1 % method of class @signal
bleeck@3 2 % function sig=genharmonicstim(sig,varargin)
bleeck@3 3 % INPUT VALUES:
bleeck@3 4 % sig: @signal with length and samplerate
bleeck@3 5 % varargin must have several parameters:
bleeck@3 6 % fundamental (default 128) = periodicity
bleeck@3 7 % min_fre (128) = lowest possible frequency
bleeck@3 8 % max_fre (10000) = highest possible frequency
bleeck@3 9 %
bleeck@3 10 % envelope of amplitudes
bleeck@3 11 % either
bleeck@3 12 % filterprop ([256,256,1024,512]) = fc, df1, bandwidth, df2 (in Hz)
bleeck@3 13 % default values: fc=3500;
bleeck@3 14 % df1=256;
bleeck@3 15 % bandwidth=1024;
bleeck@3 16 % df2=512;
bleeck@3 17 % the amplitdes can also be given by cf and two slopes for
bleeck@3 18 % higher and lower frequencies:
bleeck@3 19 % eg 'cf',1000,'lowslope',25,'highslope',38
bleeck@3 20 % the highest and lowest possible allowed harmonic are given
bleeck@3 21 % in either case by giving 'lowestharmonic' and
bleeck@3 22 % 'highestharmonic' (default value: 1 and inf)
bleeck@3 23 %
bleeck@3 24 % type = which type (default none)
bleeck@3 25 % filtered,
bleeck@3 26 % decreaseoddamplitude,
bleeck@3 27 % decreaseoddphase
bleeck@3 28 % shiftallcomponents
bleeck@3 29 % mistunedharmonic
bleeck@3 30 % decrease_amplitude_linear
bleeck@3 31 % changeby = value, that the odd harmonics shall vary (degree or dB or whatever)
bleeck@3 32 % phases must be in degrees!
bleeck@3 33 % RETURN VALUE:
bleeck@3 34 % sig: @signal
bleeck@3 35 %
bleeck@3 36 % examples:
bleeck@3 37 % create a stimulus with certain filtercharacteristic with random
bleeck@3 38 % phase, and every second harmonic reduced by an amount
bleeck@3 39 % tone(i)=genharmonics(sig,'fundamental',chroma,...
bleeck@3 40 % 'filterprop',[toneheight,handles.df1,handles.bw,handles.df2],...
bleeck@3 41 % 'phase','random',...
bleeck@3 42 % 'type','decreaseoddamplitude',...
bleeck@3 43 % 'changeby',octheight...
bleeck@3 44 % );
bleeck@3 45 %
bleeck@3 46 %
bleeck@3 47 %
bleeck@3 48 % create a signal with a mistuned harmonic
bleeck@3 49 % s=signal(0.1,16000);
bleeck@3 50 % clear p
bleeck@3 51 % p{1}='fundamental';
bleeck@3 52 % p{2}=100;
bleeck@3 53 % p{3}='type';
bleeck@3 54 % p{4}='mistunedharmonic';
bleeck@3 55 % p{5}='changeby';
bleeck@3 56 % p{6}=10;
bleeck@3 57 % p{7}='min_fre';
bleeck@3 58 % p{8}=500;
bleeck@3 59 % p{9}='max_fre';
bleeck@3 60 % p{10}=2000;
bleeck@3 61 % p{11}='harmonicnumber';
bleeck@3 62 % p{12}='12';
bleeck@3 63 % s=genharmonics(s,p{1},p{2},p{3},p{4},p{5},p{6},p{7},p{8},p{9},p{10},p{11},p{12})
bleeck@3 64
bleeck@3 65 % create a harmonic signal with lots of harmonics
bleeck@3 66 % s=signal(0.1,16000);
bleeck@3 67 % clear p
bleeck@3 68 % p{1}='fundamental';
bleeck@3 69 % p{2}=250;
bleeck@3 70 % p{3}='min_fre';
bleeck@3 71 % p{4}=499;
bleeck@3 72 % p{5}='max_fre';
bleeck@3 73 % p{6}=5001;
bleeck@3 74 % s=genharmonics(s,p{1},p{2},p{3},p{4},p{5},p{6})
bleeck@3 75 %
bleeck@3 76
bleeck@3 77
bleeck@3 78
bleeck@3 79 % This external file is included as part of the 'aim-mat' distribution package
bleeck@3 80 % (c) 2011, University of Southampton
bleeck@3 81 % Maintained by Stefan Bleeck (bleeck@gmail.com)
bleeck@3 82 % download of current version is on the soundsoftware site:
bleeck@3 83 % http://code.soundsoftware.ac.uk/projects/aimmat
bleeck@3 84 % documentation and everything is on http://www.acousticscale.org
bleeck@3 85
bleeck@3 86 function sig=genharmonics(sig,varargin)
bleeck@3 87
bleeck@3 88 if mod(nargin,2)==0
bleeck@3 89 disp('odd number of parameters - please input a full set of parameters and arguments');
bleeck@3 90 return;
bleeck@3 91 end
bleeck@3 92 str_fundamental=getargument(varargin ,'fundamental');
bleeck@3 93 str_type=getargument(varargin,'type');
bleeck@3 94 str_harmnr=getargument(varargin,'harmonicnumber');
bleeck@3 95 str_changeby=getargument(varargin,'changeby');
bleeck@3 96 str_filterprop=getargument(varargin,'filterprop');
bleeck@3 97 str_fc=getargument(varargin,'fc');
bleeck@3 98 str_lowslope=getargument(varargin,'lowslope');
bleeck@3 99 str_highslope=getargument(varargin,'highslope');
bleeck@3 100 str_lowestharmonic=getargument(varargin,'lowestharmonic');
bleeck@3 101 str_highestharmonic=getargument(varargin,'highestharmonic');
bleeck@3 102 str_bw=getargument(varargin,'bw');
bleeck@3 103 str_phase=getargument(varargin,'phase');
bleeck@3 104 str_min_fre=getargument(varargin,'min_fre');
bleeck@3 105 str_max_fre=getargument(varargin,'max_fre');
bleeck@3 106
bleeck@3 107 str_which_harmonics=getargument(varargin,'which harmonics');
bleeck@3 108
bleeck@3 109 % defaultvalues:
bleeck@3 110 if strcmp(str_filterprop,'') && isempty(str_max_fre{1})
bleeck@3 111 if strcmp(str_changeby,'')
bleeck@3 112 str_filterprop{1}=[256,256,1024,512];
bleeck@3 113 fc=256;
bleeck@3 114 df1=256;
bleeck@3 115 bandwidth=1024;
bleeck@3 116 df2=512;
bleeck@3 117 else
bleeck@3 118 min_fre=str_min_fre{1};
bleeck@3 119 max_fre=str_max_fre{1};
bleeck@3 120 df1=1;
bleeck@3 121 df2=1;
bleeck@3 122 fc=min_fre;
bleeck@3 123 bandwidth=max_fre-min_fre;
bleeck@3 124 end
bleeck@3 125 elseif isempty(str_max_fre{1})
bleeck@3 126 %eval(sprintf('filterprop=%s;',str_filterprop{1}));
bleeck@3 127 fc=str_filterprop{1}(1);
bleeck@3 128 df1=str_filterprop{1}(2);
bleeck@3 129 bandwidth=str_filterprop{1}(3);
bleeck@3 130 df2=str_filterprop{1}(4);
bleeck@3 131 end
bleeck@3 132 if strcmp(str_changeby,'')
bleeck@3 133 else
bleeck@3 134 if isnumeric(str_changeby{1})
bleeck@3 135 changeby=str_changeby{1};
bleeck@3 136 else
bleeck@3 137 eval(sprintf('changeby=%f;',str_changeby{1}));
bleeck@3 138 end
bleeck@3 139 end
bleeck@3 140
bleeck@3 141 % different method of defining envelope: center frequency is the
bleeck@3 142 % highest point, highslope and lowslope define the amplitude on both
bleeck@3 143 % sides for each harmonic
bleeck@3 144 if ~strcmp(str_lowslope,'') && ~strcmp(str_highslope,'')
bleeck@3 145 lowslope=str_lowslope{1};
bleeck@3 146 highslope=str_highslope{1};
bleeck@3 147 calculate_amplitude_with_slopes=1;
bleeck@3 148
bleeck@3 149 % test with
bleeck@3 150 % plot(powerspectrum(genharmonics(signal(0.1,16000),'fc',2000,'lowslope',30,'highslope',40,'fundamental',250)))
bleeck@3 151 else
bleeck@3 152 calculate_amplitude_with_slopes=0;
bleeck@3 153 end
bleeck@3 154
bleeck@3 155 if strcmp(str_type,'')
bleeck@3 156 str_type{1}='';
bleeck@3 157 type='';
bleeck@3 158 else
bleeck@3 159 type=str_type{1};
bleeck@3 160 end
bleeck@3 161
bleeck@3 162 if strcmp(str_phase,'')
bleeck@3 163 setphase='cosine';
bleeck@3 164 else
bleeck@3 165 setphase=str_phase{1};
bleeck@3 166 end
bleeck@3 167
bleeck@3 168 if strcmp(str_fundamental,'')
bleeck@3 169 str_fundamental{1}='128';
bleeck@3 170 fundamental=128;
bleeck@3 171 else
bleeck@3 172 if isnumeric(str_fundamental{1})
bleeck@3 173 fundamental=str_fundamental{1};
bleeck@3 174 else
bleeck@3 175 eval(sprintf('fundamental=%s;',str_fundamental{1}));
bleeck@3 176 end
bleeck@3 177 end
bleeck@3 178
bleeck@3 179 if strcmp(str_lowestharmonic,'')
bleeck@3 180 lowestharmonic=1;
bleeck@3 181 else
bleeck@3 182 if isnumeric(str_lowestharmonic{1})
bleeck@3 183 lowestharmonic=str_lowestharmonic{1};
bleeck@3 184 else
bleeck@3 185 eval(sprintf('lowestharmonic=%s;',lowestharmonic{1}));
bleeck@3 186 end
bleeck@3 187 end
bleeck@3 188 if strcmp(str_highestharmonic,'')
bleeck@3 189 highestharmonic=inf;
bleeck@3 190 else
bleeck@3 191 if isnumeric(str_highestharmonic{1})
bleeck@3 192 highestharmonic=str_highestharmonic{1};
bleeck@3 193 else
bleeck@3 194 eval(sprintf('highestharmonic=%s;',highestharmonic{1}));
bleeck@3 195 end
bleeck@3 196 end
bleeck@3 197
bleeck@3 198 if strcmp(str_fc{1},'')
bleeck@3 199 else
bleeck@3 200 if isnumeric(str_fc{1})
bleeck@3 201 fc=str_fc{1};
bleeck@3 202 else
bleeck@3 203 eval(sprintf('fc=%s;',str_fc{1}));
bleeck@3 204 end
bleeck@3 205 end
bleeck@3 206
bleeck@3 207 if strcmp(str_bw{1},'')
bleeck@3 208 else
bleeck@3 209 if isnumeric(str_bw{1})
bleeck@3 210 bandwidth=str_bw{1};
bleeck@3 211 else
bleeck@3 212 eval(sprintf('bandwidth=%s;',str_bw{1}));
bleeck@3 213 end
bleeck@3 214 end
bleeck@3 215
bleeck@3 216 if strcmp(str_which_harmonics,'')
bleeck@3 217 str_which_harmonics{1}='all';
bleeck@3 218 end
bleeck@3 219
bleeck@3 220 samplerate=sig.samplerate;
bleeck@3 221 length=getlength(sig);
bleeck@3 222
bleeck@3 223
bleeck@3 224 % begin!
bleeck@3 225
bleeck@3 226 % if isempty(str_max_fre)
bleeck@3 227 if isempty(str_max_fre{1})
bleeck@3 228 max_fre=fc+bandwidth+df2;
bleeck@3 229 min_fre=fc-df1;
bleeck@3 230 else
bleeck@3 231 min_fre=str_min_fre{1};
bleeck@3 232 max_fre=str_max_fre{1};
bleeck@3 233 end
bleeck@3 234
bleeck@3 235 if (min_fre<0) %squeese df1 to go from 0 to fc
bleeck@3 236 df1=df1-abs(min_fre);
bleeck@3 237 % disp('df1 was reduced')
bleeck@3 238 end
bleeck@3 239
bleeck@3 240 if fundamental > max_fre
bleeck@3 241 disp('error: genharmonics: fundamental must be smaller then highest frequency');
bleeck@3 242 return;
bleeck@3 243 end
bleeck@3 244
bleeck@3 245 s=signal(length,samplerate);
bleeck@3 246 if max_fre>1000
bleeck@3 247 s=setname(s,sprintf('Harmonic Signal - f0=%4.1f Hz, type: %s (from %2.2f kHz to %2.2f kHz)',fundamental,type,min_fre/1000,max_fre/1000));
bleeck@3 248 else
bleeck@3 249 s=setname(s,sprintf('Harmonic Signal - f0=%4.1f Hz, type: %s (from %3.0 Hz to %3.0f Hz)',fundamental,type,min_fre,max_fre));
bleeck@3 250 end
bleeck@3 251
bleeck@3 252 if calculate_amplitude_with_slopes
bleeck@3 253 s=setname(s,sprintf('Harmonic Signal - modfre=%4.1f Hz, type: %s (cf: %2.2f kHz, low slope: %3.0f dB/oct, high slope %3.0f dB/oct)',fundamental,type,fc/1000,lowslope,highslope));
bleeck@3 254 end
bleeck@3 255
bleeck@3 256 % in case of sloped amplitudes, we dont want a limit on harmonics
bleeck@3 257 if calculate_amplitude_with_slopes
bleeck@3 258 max_fre=getsr(sig)/2;
bleeck@3 259 min_fre=0;
bleeck@3 260 end
bleeck@3 261
bleeck@3 262 % if limit of harmonics is explicitly given
bleeck@3 263 if ~strcmp(str_highestharmonic,'')
bleeck@3 264 max_fre=highestharmonic*fundamental;
bleeck@3 265 end
bleeck@3 266 if ~strcmp(str_lowestharmonic,'')
bleeck@3 267 min_fre=lowestharmonic*fundamental;
bleeck@3 268 end
bleeck@3 269
bleeck@3 270 fre=fundamental;
bleeck@3 271 count_partials=1;
bleeck@3 272 while fre <= max_fre
bleeck@3 273 if fre >= min_fre
bleeck@3 274 temp=signal(length,samplerate);
bleeck@3 275 amplitude=1;
bleeck@3 276 phase=0;
bleeck@3 277 offset=0;
bleeck@3 278 if strcmp(type,'mistunedharmonic') % in %
bleeck@3 279 eval(sprintf('nr=%s;',str_harmnr{1}));
bleeck@3 280 if count_partials==nr
bleeck@3 281 offset=fundamental*changeby/100;
bleeck@3 282 amplitude=1;
bleeck@3 283 phase=0;
bleeck@3 284 end
bleeck@3 285 end
bleeck@3 286 if strcmp(type,'shiftallcomponents') % in Hz
bleeck@3 287 offset=changeby;
bleeck@3 288 amplitude=1;
bleeck@3 289 phase=0;
bleeck@3 290 end
bleeck@3 291 if strcmp(type,'decreaseoddphase')
bleeck@3 292 % phase must be given in degree!
bleeck@3 293 if mod(count_partials,2)==1
bleeck@3 294 amplitude=1;
bleeck@3 295 phase=changeby;
bleeck@3 296 end
bleeck@3 297 end
bleeck@3 298
bleeck@3 299 if strcmp(type,'decrease_amplitude_linear')
bleeck@3 300 % the amount must be given in changeby!
bleeck@3 301 amplitude=1*power(10,(-changeby*count_partials)/20);
bleeck@3 302 ampscale=1;
bleeck@3 303 elseif ~isempty(str_type{1})
bleeck@3 304 ampscale=filterbandamp(fre+offset,amplitude,fc,df1,bandwidth,df2);
bleeck@3 305 else
bleeck@3 306 ampscale=1;
bleeck@3 307 end
bleeck@3 308 amplitude=amplitude*ampscale;
bleeck@3 309
bleeck@3 310
bleeck@3 311 % stattdessen mit Slopes:
bleeck@3 312 if calculate_amplitude_with_slopes
bleeck@3 313 % calculate the distance from cf (in octaves)
bleeck@3 314 % and from this the attenuation
bleeck@3 315 % distance=log2(fre/fc);
bleeck@3 316 distance=fre/fc;
bleeck@3 317 % if distance >= 0
bleeck@3 318 if distance >= 1
bleeck@3 319 atten=distance*highslope;
bleeck@3 320 else
bleeck@3 321 atten=100;
bleeck@3 322 end
bleeck@3 323 amplitude=1*power(10,-atten/20);
bleeck@3 324 p=0;
bleeck@3 325 end
bleeck@3 326
bleeck@3 327 if strcmp(type,'decreaseoddamplitude')
bleeck@3 328 if mod(count_partials,2)==1
bleeck@3 329 amplitude=amplitude*power(10,changeby/20);
bleeck@3 330 end
bleeck@3 331 end
bleeck@3 332 if strcmp(type,'decreaseevenamplitude')
bleeck@3 333 if mod(count_partials,2)==0
bleeck@3 334 amplitude=amplitude*power(10,changeby/20);
bleeck@3 335 end
bleeck@3 336 end
bleeck@3 337
bleeck@3 338
bleeck@3 339 switch str_which_harmonics{1}
bleeck@3 340 case 'all'
bleeck@3 341 case 'only odd'
bleeck@3 342 if mod(count_partials,2)==0
bleeck@3 343 amplitude=0;
bleeck@3 344 end
bleeck@3 345 case 'only even'
bleeck@3 346 if mod(count_partials,2)==1
bleeck@3 347 amplitude=0;
bleeck@3 348 end
bleeck@3 349 end
bleeck@3 350
bleeck@3 351 % degree2rad
bleeck@3 352 switch setphase
bleeck@3 353 case 'random'
bleeck@3 354 piphase=rand(1)*2*pi+pi;
bleeck@3 355 case 'cosine'
bleeck@3 356 piphase=phase*(pi/180)+pi/2;
bleeck@3 357 case 'sine'
bleeck@3 358 piphase=phase*(pi/180);
bleeck@3 359
bleeck@3 360 end
bleeck@3 361 % disp(sprintf('fre: %3.2f amp:%2.1f',fre,amplitude*100));
bleeck@3 362 % amplitude
bleeck@3 363 % fre
bleeck@3 364 temp=generatesinus(temp,fre+offset,amplitude,piphase);
bleeck@3 365
bleeck@3 366 % add them up!
bleeck@3 367 s=s+temp;
bleeck@3 368 end
bleeck@3 369 fre=fre+fundamental;
bleeck@3 370 count_partials=count_partials+1;
bleeck@3 371 end
bleeck@3 372
bleeck@3 373 sig=s;