Skip to content

Commit 5a605c0

Browse files
committed
Add OrderByDepth to NeuropixelsV1f
1 parent 3fc4cca commit 5a605c0

File tree

5 files changed

+78
-46
lines changed

5 files changed

+78
-46
lines changed

OpenEphys.Onix1/ConfigureNeuropixelsV1f.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
172172
probeControl.WriteShiftRegisters();
173173
}
174174

175-
return DeviceManager.RegisterDevice(deviceName, device, DeviceType);
175+
var deviceInfo = new NeuropixelsV1fDeviceInfo(context, DeviceType, deviceAddress, ProbeConfiguration);
176+
177+
return DeviceManager.RegisterDevice(deviceName, deviceInfo);
176178
});
177179
}
178180
}

OpenEphys.Onix1/NeuropixelsV1eData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public int BufferSize
5050
/// <remarks>
5151
/// If <see cref="OrderByDepth"/> is false, then channels are ordered from 0 to 383.
5252
/// If <see cref="OrderByDepth"/> is true, then channels are ordered based on the depth
53-
/// of the electrodes
53+
/// of the electrodes.
5454
/// </remarks>
5555
[Description("Determines if the channels are returned ordered by depth.")]
5656
[Category(DeviceFactory.ConfigurationCategory)]

OpenEphys.Onix1/NeuropixelsV1fData.cs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ public int BufferSize
4242
set => bufferSize = (int)(Math.Ceiling((double)value / NeuropixelsV1.FramesPerRoundRobin) * NeuropixelsV1.FramesPerRoundRobin);
4343
}
4444

45+
/// <summary>
46+
/// Gets or sets a boolean value that controls if the channels are ordered by depth.
47+
/// </summary>
48+
/// <remarks>
49+
/// If <see cref="OrderByDepth"/> is false, then channels are ordered from 0 to 383.
50+
/// If <see cref="OrderByDepth"/> is true, then channels are ordered based on the depth
51+
/// of the electrodes.
52+
/// </remarks>
53+
[Description("Determines if the channels are returned ordered by depth.")]
54+
[Category(DeviceFactory.ConfigurationCategory)]
55+
public bool OrderByDepth { get; set; } = false;
56+
4557
/// <summary>
4658
/// Generates a sequence of <see cref="NeuropixelsV1DataFrame"/> objects.
4759
/// </summary>
@@ -50,24 +62,27 @@ public unsafe override IObservable<NeuropixelsV1DataFrame> Generate()
5062
{
5163
var spikeBufferSize = BufferSize;
5264
var lfpBufferSize = spikeBufferSize / NeuropixelsV1.FramesPerRoundRobin;
53-
5465
var bufferSize = BufferSize;
66+
var orderByDepth = OrderByDepth;
67+
5568
return DeviceManager.GetDevice(DeviceName).SelectMany(
5669
deviceInfo => Observable.Create<NeuropixelsV1DataFrame>(observer =>
5770
{
5871
var sampleIndex = 0;
59-
var device = deviceInfo.GetDeviceContext(typeof(NeuropixelsV1f));
72+
var info = (NeuropixelsV1fDeviceInfo)deviceInfo;
73+
var device = info.GetDeviceContext(typeof(NeuropixelsV1f));
6074
var spikeBuffer = new ushort[NeuropixelsV1.ChannelCount, spikeBufferSize];
6175
var lfpBuffer = new ushort[NeuropixelsV1.ChannelCount, lfpBufferSize];
6276
var frameCountBuffer = new int[spikeBufferSize * NeuropixelsV1.FramesPerSuperFrame];
6377
var hubClockBuffer = new ulong[spikeBufferSize];
6478
var clockBuffer = new ulong[spikeBufferSize];
79+
int[,] channelOrder = orderByDepth ? Neuropixels.OrderChannelsByDepth(info.ProbeConfiguration.ChannelMap, RawToChannel) : RawToChannel;
6580

6681
var frameObserver = Observer.Create<oni.Frame>(
6782
frame =>
6883
{
6984
var payload = (NeuropixelsV1fPayload*)frame.Data.ToPointer();
70-
NeuropixelsV1fDataFrame.CopyAmplifierBuffer(payload->AmplifierData, frameCountBuffer, spikeBuffer, lfpBuffer, sampleIndex);
85+
NeuropixelsV1fDataFrame.CopyAmplifierBuffer(payload->AmplifierData, frameCountBuffer, spikeBuffer, lfpBuffer, sampleIndex, channelOrder);
7186
hubClockBuffer[sampleIndex] = payload->HubClock;
7287
clockBuffer[sampleIndex] = frame.Clock;
7388

@@ -89,5 +104,43 @@ public unsafe override IObservable<NeuropixelsV1DataFrame> Generate()
89104
.SubscribeSafe(frameObserver);
90105
}));
91106
}
107+
108+
// ADC to channel
109+
// First dimension: ADC index
110+
// Second dimension: frame index within super frame
111+
// Output: channel number
112+
static readonly int[,] RawToChannel = {
113+
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22 },
114+
{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 },
115+
{24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46 },
116+
{25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47 },
117+
{48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70 },
118+
{49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71 },
119+
{72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94 },
120+
{73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95 },
121+
{96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118 },
122+
{97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119 },
123+
{120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142 },
124+
{121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143 },
125+
{144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166 },
126+
{145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167 },
127+
{168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190 },
128+
{169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191 },
129+
{192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214 },
130+
{193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215 },
131+
{216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238 },
132+
{217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239 },
133+
{240, 242, 244, 246, 248, 250, 252, 254, 256, 258, 260, 262 },
134+
{241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263 },
135+
{264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286 },
136+
{265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287 },
137+
{288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310 },
138+
{289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311 },
139+
{312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, 334 },
140+
{313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333, 335 },
141+
{336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358 },
142+
{337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359 },
143+
{360, 362, 364, 366, 368, 370, 372, 374, 376, 378, 380, 382 },
144+
{361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, 383 } };
92145
}
93146
}

OpenEphys.Onix1/NeuropixelsV1fDataFrame.cs

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ namespace OpenEphys.Onix1
33
{
44
class NeuropixelsV1fDataFrame
55
{
6-
internal static unsafe void CopyAmplifierBuffer(ushort* amplifierData, int[] frameCountBuffer, ushort[,] spikeBuffer, ushort[,] lfpBuffer, int index)
6+
internal static unsafe void CopyAmplifierBuffer(ushort* amplifierData, int[] frameCountBuffer, ushort[,] spikeBuffer, ushort[,] lfpBuffer, int index, int[,] channelOrder)
77
{
88
var frameCountStartIndex = index * NeuropixelsV1.FramesPerSuperFrame;
99
frameCountBuffer[frameCountStartIndex] = (amplifierData[FrameCounterMsbIndex] << 10) | (amplifierData[FrameCounterLsbIndex] << 0);
@@ -16,7 +16,7 @@ internal static unsafe void CopyAmplifierBuffer(ushort* amplifierData, int[] fra
1616
for (int k = 0; k < NeuropixelsV1.AdcCount; k++)
1717
{
1818
// TODO: Why would I not do this bit shift ont the FPGA??
19-
lfpBuffer[RawToChannel[k, lfpFrameIndex], lfpBufferIndex] = (ushort)(amplifierData[AdcToFrameIndex[k]] >> 5); // Q11.5 -> Q11.0
19+
lfpBuffer[channelOrder[k, lfpFrameIndex], lfpBufferIndex] = (ushort)(amplifierData[AdcToFrameIndex[k]] >> 5); // Q11.5 -> Q11.0
2020
}
2121

2222
// Loop over 12 AP frames within each "super-frame"
@@ -27,7 +27,7 @@ internal static unsafe void CopyAmplifierBuffer(ushort* amplifierData, int[] fra
2727

2828
for (int k = 0; k < NeuropixelsV1.AdcCount; k++)
2929
{
30-
spikeBuffer[RawToChannel[k, i], index] = (ushort)(amplifierData[AdcToFrameIndex[k] + adcDataOffset] >> 5); // Q11.5 -> Q11.0
30+
spikeBuffer[channelOrder[k, i], index] = (ushort)(amplifierData[AdcToFrameIndex[k] + adcDataOffset] >> 5); // Q11.5 -> Q11.0
3131
}
3232

3333
frameCountBuffer[frameCountStartIndex + i + 1] =
@@ -48,44 +48,6 @@ internal static unsafe void CopyAmplifierBuffer(ushort* amplifierData, int[] fra
4848
5, 12, 19, 26, 33,
4949
6, 13, 20, 27, 34,
5050
7, 14};
51-
52-
// ADC to channel
53-
// First dimension: ADC index
54-
// Second dimension: frame index within super frame
55-
// Output: channel number
56-
static readonly int[,] RawToChannel = {
57-
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22 },
58-
{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 },
59-
{24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46 },
60-
{25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47 },
61-
{48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70 },
62-
{49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71 },
63-
{72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94 },
64-
{73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95 },
65-
{96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118 },
66-
{97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119 },
67-
{120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142 },
68-
{121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143 },
69-
{144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166 },
70-
{145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167 },
71-
{168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190 },
72-
{169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191 },
73-
{192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214 },
74-
{193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215 },
75-
{216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238 },
76-
{217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239 },
77-
{240, 242, 244, 246, 248, 250, 252, 254, 256, 258, 260, 262 },
78-
{241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263 },
79-
{264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286 },
80-
{265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287 },
81-
{288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310 },
82-
{289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311 },
83-
{312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, 334 },
84-
{313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333, 335 },
85-
{336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358 },
86-
{337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359 },
87-
{360, 362, 364, 366, 368, 370, 372, 374, 376, 378, 380, 382 },
88-
{361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, 383 } };
8951
}
9052

9153
[StructLayout(LayoutKind.Sequential, Pack = 1)]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace OpenEphys.Onix1
4+
{
5+
class NeuropixelsV1fDeviceInfo : DeviceInfo
6+
{
7+
public NeuropixelsV1fDeviceInfo(ContextTask context, Type deviceType, uint deviceAddress, NeuropixelsV1ProbeConfiguration probeConfiguration)
8+
: base(context, deviceType, deviceAddress)
9+
{
10+
ProbeConfiguration = probeConfiguration;
11+
}
12+
13+
public NeuropixelsV1ProbeConfiguration ProbeConfiguration { get; }
14+
}
15+
}

0 commit comments

Comments
 (0)