MATLAB: Adjusting the dynamic range of a plot of logarithmic values

2.8k views Asked by At

I have been unable to find anything close to this with Google, so I'm afraid that my question itself may be flawed... None the less, here goes:

I wish to display a matrix of values (Z) at various fixed dynamic ranges. In this case, fixed at 0dB, 10dB, ..., 40dB.

My current approach is to find Zmag = abs(Z).^2, Zn = normalized(Zmag), Zdb = 10*log10(1+Zn)

In order to view a different dynamic range (say, 10dB) I would include 'Zn(Zn<0.1)=0.1' before finding Zdb. For 20dB I do the same, except the value of interest changes to 0.01.

Then I do a color mesh plot of Zn and view the XY (top, from 3D perspective) plot to see something similar to what imagesc(Zn) would give. The intent is that as I increase the dynamic range, I should see a more detailed plot (with more colors between the maximum and minimum, in this case).

My current method is performing as (I think) it should for 10dB: 10dB dynamic range mesh Compared to 40dB: 40dB dynamic range mesh plot

However, I can't see a difference between my 0,20,30, and 40dB plots. I would expect there to be a gradual increase in values from 0dB to 40dB.

-Dylan

EDIT: Here is some sample code. It is a snippit of the real code, but should still run:

%% Constants
fnum = 1;
Fc = 1/16;
taup = 128;
taumin = 1;
taumax = 512;
taux = taumin:taumax;

%% Signal
l = 1:16; %Signal length
s = sin(2*pi*Fc*l); %Original Signal
sig = zeros([1 taup+512]);
sig(taup:taup+size(l,2)-1) = s;

[mfr,fdy] = MatchedFilterResponse(sig,taup,l);
Z = mfr;

slices = true;
%full dynamic range
name = 'Short Tone Ping results with 0dB range';
Zmag = abs(Z).^2;
Zn = normalizeMat(Zmag);
Zdb = 10*log10(1+Zn);
fnum = plotSurfaces(taux,fdy,Zdb,fnum,name,slices);

slices = false;
%40dB dynamic range
name = 'Short Tone Ping results with 40dB range';
Z40mag = Zmag;
Z40n = normalizeMat(Z40mag);
Z40n(Z40n<0.0001) = 0.0001;
Z40db = 10*log10(1+Z40n);
fnum = plotSurfaces(taux,fdy,Z40db,fnum,name,slices);

function [mfr,fdy] = MatchedFilterResponse(sig,taup,l)
    Fdmin = -1/16;
    Fdmax = 1/16;
    Fdinc = (0.125)/(255);
    fdy = linspace(Fdmin,Fdmax,256);
    i = 0;
    for tau = 1:512
        i = i+1;
        j = 0;
        for Fd = Fdmin:Fdinc:Fdmax
            j = j+1;
            a = sig(l+taup-1);
            b = sig(l+tau).*exp(1i*2*pi*Fd*l);
            mfr(j,i) = sum(a.*b);
        end
    end
return
end

function [fnum] = plotSurfaces(taux,fdy,z,fnum,name,slices)
    fid = figure(fnum);
    axes1 = axes('Parent',fid);
    grid(axes1,'on');
    hold(axes1,'all');
    msh = mesh(taux,fdy,z,'Parent',axes1);
    xlabel ('Delay - seconds');
    ylabel ('Frequency offset from center frequency - Cycles/sample');
    zlabel ('Ambiguity function (Normalized Magnitude-Squared)','Visible','off');
    fname = strcat(name,' (Ambiguity Function z(\tau;F_d))');
    title(fname);
    ax = axis;
    axis([50 200 ax(3) ax(4)])
    cb = colorbar('peer',axes1);
    set(get(cb,'ylabel'),'String','Magnitude-Squared (dB)');
    hold off;
    fnum = fnum + 1;
    return
end
1

There are 1 answers

3
Itamar Katz On

There are a few methods of compressing/expanding the dynamic range, and thresholding from below is just one. You could threshold from above, or you could do a 'softer' compression of the dynamic range, by using a smoother function.

The gradual increase you expect to see depends on the distribution of values of Zn, and without an example of data and the code you use, it's hard to find the cause or problem in code (if it is a bug at all).

Anyway if your aim is to display the data (as opposed to any further analysis you might want to do), I suggest you compress the dynamic range of the colormap, and not of the data itself. The fastest way to do it is to right-click the colorbar and choosing 'Interactive Colormap Shift', which enables you to use the mouse directly on the colrbar in order to change the dynamic range.

If you want to do it programatically, create a few custom colormaps according to the distribution of your values. For example (I am using only red values, for the sake of simplicity)

data = 10 .^ randn(100,100);                      % large dynamic range data
ncols = 128;                                      % number of colors in the colormap
R1 = [linspace(0,1, 10)'; ones(ncols - 10, 1); ]; % colormap for the small values
R2 = [zeros(ncols - 10, 1); linspace(0,1,10)'];   % colormap for the large values
G = zeros(ncols, 1);
B = zeros(ncols, 1);
cmap1 = [R1, G, B];
cmap2 = [R2, G, B];

figure
subplot(1,2,1)
rgbplot(cmap1) % plot the colormap values
subplot(1,2,2)
imagesc (data) % plot the data
colormap(cmap1)
colorbar

figure
subplot(1,2,1)
rgbplot(cmap2)
subplot(1,2,2)
imagesc (data)
colormap(cmap2)
colorbar