function two_neuron_sim % TWO_NEURON_SIM — 1 s simulation of two neurons with an excitatory synapse % % • Neuron A emits action potential(s) starting at t = 0.2 s. % • Number of spikes and spike frequency are user-defined. % • Neuron B receives an excitatory synaptic conductance from Neuron A. % • Controls: Neuron B target voltage (V_hold), synapse strength, synapse reversal potential, playback speed. % • Resizable UI with scrollbars. Axes are yoked (linked) in X and Y. %% ---------- UI LAYOUT ---------- fig = uifigure('Name','Two Neuron Simulation (1 s)','Position',[100 100 980 760], ... 'AutoResizeChildren','on'); root = uigridlayout(fig,[1 2], 'ColumnWidth',{'1x', 360}, 'RowHeight',{'1x'}, 'Scrollable','on'); root.Padding = 10; root.RowSpacing = 10; root.ColumnSpacing = 10; % Left side: plots left = uigridlayout(root, [2 1], 'RowHeight',{'1x','1x'}, 'ColumnWidth',{'1x'}, 'Scrollable','on'); left.Layout.Row = 1; left.Layout.Column = 1; left.Padding = 0; left.RowSpacing = 10; ax1 = uiaxes(left); ax1.Layout.Row = 1; hold(ax1,'on'); ax2 = uiaxes(left); ax2.Layout.Row = 2; hold(ax2,'on'); linkaxes([ax1 ax2],'xy'); % yoke both axes % Right side: controls right = uigridlayout(root,[17 1], ... 'RowHeight',{'fit','fit','fit','fit','fit','fit','fit','fit','fit','fit','fit','fit','fit','fit','fit','fit','1x'}, ... 'ColumnWidth',{'1x'}, 'Scrollable','on'); right.Layout.Row = 1; right.Layout.Column = 2; right.Padding = 8; right.RowSpacing = 8; % Title + hint lblTitle = uilabel(right,'Text','Controls','FontWeight','bold','FontSize',14); lblTitle.Layout.Row = 1; hint = uilabel(right,'Text','Adjust controls then press Run.','FontColor',[0.2 0.2 0.2]); hint.Layout.Row = 2; % Neuron A: Number of Spikes & Frequency lblNAS = uilabel(right,'Text','Neuron A: Number of Spikes','HorizontalAlignment','left'); lblNAS.Layout.Row = 3; numSpikesField = uieditfield(right,'numeric','Limits',[1 50],'Value',1,'ValueDisplayFormat','%.0f'); numSpikesField.Layout.Row = 4; numSpikesField.ValueChangedFcn = @(~,~) setHint(); lblFreq = uilabel(right,'Text','Neuron A: Spike Frequency (Hz)','HorizontalAlignment','left'); lblFreq.Layout.Row = 5; freqField = uieditfield(right,'numeric','Limits',[1 200],'Value',20,'ValueDisplayFormat','%.1f'); freqField.Layout.Row = 6; freqField.ValueChangedFcn = @(~,~) setHint(); % Neuron B Target Voltage lblVhold = uilabel(right,'Text','Neuron B Target Voltage (mV)','HorizontalAlignment','left'); lblVhold.Layout.Row = 7; slVhold = uislider(right, 'Limits',[-80 20], 'MajorTicks',-80:20:20, 'Value', -65); slVhold.Layout.Row = 8; editV = uieditfield(right,'numeric','Limits',[-120 120],'Value',-65,'ValueDisplayFormat','%.1f'); editV.Layout.Row = 9; % Synapse Strength lblGS = uilabel(right,'Text','Synapse Strength','HorizontalAlignment','left'); lblGS.Layout.Row = 10; slGSyn = uislider(right, 'Limits',[0 50], 'MajorTicks',0:10:50, 'Value',5); slGSyn.Layout.Row = 11; % Synapse Reversal Potential lblEs = uilabel(right,'Text','Synapse Reversal Potential (mV)','HorizontalAlignment','left'); lblEs.Layout.Row = 12; slEsyn = uislider(right,'Limits',[-80 80],'MajorTicks',-80:20:80,'Value',0); slEsyn.Layout.Row = 13; editEsyn = uieditfield(right,'numeric','Limits',[-120 120],'Value',0,'ValueDisplayFormat','%.1f'); editEsyn.Layout.Row = 14; % Playback speed control lblSpeed = uilabel(right,'Text','Playback Speed (0.1x – 10x)','HorizontalAlignment','left'); lblSpeed.Layout.Row = 15; slSpeed = uislider(right,'Limits',[0.1 10],'Value',1,'MajorTicks',[0.1 1 5 10]); slSpeed.Layout.Row = 16; % Run button btn = uibutton(right,'Text','Run','ButtonPushedFcn',@(b,evt) runSim()); btn.FontWeight = 'bold'; btn.FontSize = 14; btn.Layout.Row = 17; % Callbacks slVhold.ValueChangingFcn = @(s,evt) setHint(); slGSyn.ValueChangingFcn = @(s,evt) setHint(); slEsyn.ValueChangingFcn = @(s,evt) setHint(); slSpeed.ValueChangingFcn = @(s,evt) setHint(); editV.ValueChangedFcn = @(h,evt) setSliderFromEdit(slVhold, editV); editEsyn.ValueChangedFcn = @(h,evt) setSliderFromEdit(slEsyn, editEsyn); slVhold.ValueChangedFcn = @(s,evt) setEditFromSlider(editV, s); slGSyn.ValueChangedFcn = @(s,evt) setHint(); slEsyn.ValueChangedFcn = @(s,evt) setEditFromSlider(editEsyn, s); %% Axes cosmetics setupAxes(ax1, 'Neuron A'); setupAxes(ax2, 'Neuron B'); %% Run once runSim(); %% ---------- Utilities ---------- function setHint hint.Text = 'Values changed — press Run to recompute.'; hint.FontColor = [0.55 0.35 0.05]; end function setSliderFromEdit(sl, ed) sl.Value = ed.Value; setHint(); end function setEditFromSlider(ed, sl) ed.Value = sl.Value; end function setupAxes(ax, ttl) grid(ax,'on'); ax.Box = 'on'; ax.NextPlot = 'replacechildren'; ax.Title.String = ttl; ax.Title.FontWeight = 'bold'; ax.XLabel.String = 'Time (ms)'; ax.YLabel.String = 'V_m (mV)'; end function runSim % Read UI nSpk = max(1, round(numSpikesField.Value)); freqHz = max(1, freqField.Value); Vhold_mV = slVhold.Value; gsynMax_nS = slGSyn.Value; Esyn_mV = slEsyn.Value; speed = slSpeed.Value; % Params T = 1.0; % seconds dt = 1e-5; % s (0.01 ms) t = 0:dt:T; nT = numel(t); C = 200e-12; % F gL = 10e-9; % S EL = -0.065; % V gClamp_nS = 20; % fixed clamp strength (Neuron B) % Neuron A spikes: N spikes at freqHz starting at 0.2 s tsp0 = 0.2; % s first spike isi = 1/max(freqHz, 1e-6); % s between spikes spike_times = tsp0 + (0:nSpk-1)*isi; spike_times = spike_times(spike_times <= T - 1e-3); % keep in bounds V1 = EL*ones(1,nT); ap_dur = 0.003; % 3 ms Vpeak = 0.040; % +40 mV tau1 = 0.0004; tau2 = 0.0012; % sharp waveform for s = spike_times idx = t >= s & t <= s + ap_dur; tt = t(idx) - s; spike_w = (exp(-tt/tau2) - exp(-tt/tau1)); spike_w = spike_w / max(spike_w + eps); Vcand = EL + (Vpeak - EL) * spike_w; V1(idx) = max(V1(idx), Vcand); end % Synapse onto Neuron B: alpha conductance per spike, summed tau_syn = 0.005; % s gsyn = zeros(1,nT); for s = spike_times tt2 = max(t - s, 0); alpha = (tt2/tau_syn).*exp(1 - tt2/tau_syn); alpha(tt2==0) = 0; gsyn = gsyn + (gsynMax_nS*1e-9) * alpha; end Esyn = Esyn_mV/1000; % V % Neuron B gClamp = gClamp_nS * 1e-9; % S Vhold = Vhold_mV/1000; % V V2 = EL * ones(1,nT); for k = 1:nT-1 Isyn = gsyn(k) * (Esyn - V2(k)); Iclamp = gClamp * (Vhold - V2(k)); dV = ( -gL*(V2(k)-EL) + Isyn + Iclamp ) / C; V2(k+1) = V2(k) + dt * dV; end % ----- Plot & Animate ----- ms = 1e3; cla(ax1); cla(ax2); h1 = plot(ax1, nan, nan, 'LineWidth',1.5); h2 = plot(ax2, nan, nan, 'LineWidth',1.5); yMin = floor(1e3*min([V1 V2])) - 5; % mV yMax = ceil(1e3*max([V1 V2])) + 5; % mV if yMin > -90, yMin = -90; end if yMax < 50, yMax = 50; end ax1.XLim = [0 T*ms]; ax2.XLim = [0 T*ms]; ax1.YLim = [yMin yMax]; ax2.YLim = [yMin yMax]; % Only E_syn reference on Neuron B yline(ax2, Esyn_mV, '--', 'E_{syn}','LabelHorizontalAlignment','left'); % Frame pacing and stride based on speed target_fps = 60; frame_dt = 1/target_fps; % s/frame (real time) base_step = max(1, round(frame_dt/dt)); % samples per frame @1x step = max(1, round(base_step * speed)); for k = 1:step:nT set(h1,'XData', t(1:k)*ms, 'YData', V1(1:k)*1e3); set(h2,'XData', t(1:k)*ms, 'YData', V2(1:k)*1e3); drawnow limitrate; pause(frame_dt); end % Final high-fidelity frame set(h1,'XData', t*ms, 'YData', V1*1e3); set(h2,'XData', t*ms, 'YData', V2*1e3); drawnow; hint.Text = 'Playback complete. Adjust sliders and press Run again.'; hint.FontColor = [0.2 0.45 0.2]; end end